diff --git a/targets/PROJECTS/SPECTRA/COPYING b/targets/PROJECTS/SPECTRA/COPYING deleted file mode 100644 index 94a9ed024d..0000000000 --- a/targets/PROJECTS/SPECTRA/COPYING +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/targets/PROJECTS/SPECTRA/CRMClient b/targets/PROJECTS/SPECTRA/CRMClient deleted file mode 100755 index 29465e592a..0000000000 Binary files a/targets/PROJECTS/SPECTRA/CRMClient and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/CRMClientmain b/targets/PROJECTS/SPECTRA/CRMClientmain deleted file mode 100755 index be19a63560..0000000000 Binary files a/targets/PROJECTS/SPECTRA/CRMClientmain and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/README.txt b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/README.txt deleted file mode 100644 index 69dc0fc9c4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/README.txt +++ /dev/null @@ -1,270 +0,0 @@ - -######################################## -# -# SPECTRA DEMO INSTALLATION AND RUN -# -# -# -# Rui Costa -# -# v1.13 (15 Oct 2014) -# -######################################## - -######################################## -1. REQUIREMENTS - - - To properly run the demo these are the main pieces of software - that are required: - - OPENAIR4G (checkout the main trunk from the EURECOM SVN). - - ODTONE (Open 802.21 protocol from ITAveiro git server). - - Boost C++ Libraries are requested by ODTONE (v1.48 or higher) - - REST Toolkit (Codename "Casablanca") - - Adequate shell/bash start-up scripts for both eNB and UE. - - BEFORE attempting any installation YOU MUST check your system for - any required software that these components require, as for - instance, a compatible GCC/G++ compiler, build tools, etc. - - NOTES BEFORE INSTALLATION: - - N1. Installation SHOULD NOT be done as ROOT. IF and WHEN super - user permissions are required you will be prompted for them. - - N2. You MUST have a valid EURECOM SVN-enabled account for the - Openair4G code. - - N3. For ODTONE software, you MUST have installed the ITAveiro - SSL/TLS certificates available at their webserver. - - N4. You MUST have Internet access in order to properly build and - deploy the software, as some of the software is fetched online. - - -######################################## -2. BUILD & INSTALL - - 2.1. PREPARATION - Start by creating a folder on a non-root directory, preferably - your home folder. Copy the script into - the newly created folder, henceforth referred to as - . - - - 2.2. INSTALLATION - There are two ways of processing the installation: - - If you already have performed a checkout of the OpenAir svn. - (Aimed at single installations for OAI developers.) - - If you only have the demonstration source code & scripts. - (To allow easier deployment over several machines, just copy - the demo's source folder, including the prepare and install - scripts to which ever machine you need and let the scripts do - the work for you) - - - 2.2.1 From the OPENAIR SVN - Go to the folder: - /trunk/targets/PROJECTS/SPECTRA/DEMO_SPECTRA - and run the installation script with the node type to install: - # ./spectra_demo_install.sh -oai_svn - - 2.2.2 From the demo's source code and scripts. - Go to the and run: - # ./spectra_demo_install.sh -full - - - - If the previous step has been well performed, you should now have - a local working copy of the OpenAir SVN on your local machine, along - with additional code required for the demo. - - - 2.3. CRM - This component of the demo MUST be compiled and installed separately. - Check /CRM/ for more details. - There is a google app that must be running in the google cloud, - and it's url configured in the source code. The local client is based - on the C++ REST framework codenamed "Casablanca". - Furthermore you need to compile the local client components - (CRMClient and CRMMain). - In the CRM client you will find a folder which includes some - basic scripts that populate the google app database, and show how to - interact with it. - - 2.4. TVWS Sensing Measurements - There is a server and client for simulating the TVWS measurements and - run the cognitive algorithm to activate the required actions on the - LTE link. (this is the goal of the demo) - Copy the client & server located at /clientSensing/ - into the ENB2 startup folder (/targets/PROJECTS/SPECTRA) - - - 2.5. TROUBLESHOOTING - If for some reason the installation does not run as expected, check - for permission-related issues or missing software packages. - Otherwise, try to install the components one by one, as defined in - the installation scripts. - (see and for - compilation and configuration details). - - The preparation script will automatically call the installation - script, but in case it does not, run it manually, it is located at: - /openair4G/targets/PROJECTS/SPECTRA/ - - NOTE: During installation we apply a patch to ODTONE, due to the - lack of a definition for LTE links and their attributes. - However, as new versions are released the patch may need to - be adapted. Therefore, be aware of compilation issues - originating from the compilation of the ODTONE core functions. - - -######################################## -3. CONFIGURATION - - You MUST make sure that the configuration of your physical and - logical interfaces matches with your Open Air and ODTONE - configuration files. Take all parameters into account while - checking the configuration files and launch scripts, located in: - - /openair4G/targets/PROJECTS/SPECTRA/ - - /ODTONE/dist/ - - 3.1 Base Configuration - This is the network configuration on the config files: - - UE1 - eth0 (192.168.13.2) - oai0 (10.0.0.2) (LTE emulated link) - - ENB1 - eth0 (192.168.12.122) internet access gw (192.168.12.100) - eth1 (192.168.13.1) - oai0 (10.0.0.1) (LTE emulated link) - eth2 (192.168.14.3) (Internal Relay Connection) - - UE2 - eth0 (192.168.14.4) (Internal Relay Connection) - eth1 (192.168.15.5) - oai0 (10.0.2.3) (LTE emulated link) - - ENB2 - eth0 (192.168.15.6) - oai0 (10.0.2.4) (LTE emulated link) - - - -######################################## -4. RUNNING THE DEMO - - 1. We advise you to turn off the network manager service in order - for the startup script configuration to be effective and final. - This can be achieved by executing: - - # sudo service network-manager stop - - 2. (On all machines) Go to OpenAir Launch folder: - /openair4G/targets/PROJECTS/SPECTRA/ - - 3. Launch the eNB1 on eNB1 machine: - # sudo ./start_enb.bash - Wait for eNB1 to reach stand by mode. - - 4. Launch the UE1 on UE1 machine: - # sudo ./start_ue.bash - - 5. Launch the eNB2 on eNB2 machine: - # sudo ./start_enb.bash - Wait for eNB2 to reach stand by mode. - - 6. Launch the UE2 on UE2 machine: - # sudo ./start_ue.bash - - 7. Any other modules will be launched automatically - if present. (CRM client, TVWS sensing, MIHF, MIH Users, etc.) - - Enjoy the demo! - - - - - - - -################################################################################ -CHANGELOG - -v0.99 (03/09/2014) - - First script and file. - -v1.00 (04/09/2014) - - Added compartmentalization for each sw component - - Added full installation procedure from scratch - - Fetching sw from repositories, compilation & installation - - Revisioned output - -v1.01 (05/09/2014) - - Added OpenAir conf files - - Added MIHF Users - - Reduced printed output - -v1.02 (08/09/2014) - - Bug correcting on installation and configuration paths & scripts - - Patched Open Air script - -v1.03 (09/09/2014) - - Patched MIHF to support LTE link based on previous code - - Added - with patch files: - - Revisioned - -v1.04 (11/09/2014) - - Corrected MIHF patch bugs - - Added patch file - - Corrected path and filename bugs on - -v1.05 (15/09/2014) - - Corrected MIHF patch bugs - - Added a number of patch files - - Adjusted patch execution on - -v1.06 (17/09/2014) - - Working demo 1 eNB 1 UE - - Modified configuration files for UE and eNB - - Substituted overwrite of files into a Git patch for SPECTRA - -v1.07 (19/09/2014) - - Expanded demo to 4 machines: - - 2 real: ue1, eNB1 - - 2 virtual: eNB2, ue2 (both hosted by eNB1) - -v1.08 (23/09/2014) - - Included CRM client and TVWS sensing modules. - -v1.09 (24/09/2014) - - Final Demo setup ready. - -v1.10 (29/09/2014) - - Updated RRC code for OpenAir. - - Code commit to OpenAir SVN trunk. - -v1.11 (01/10/2014) - - Restructure of source code tree and installation files to - include the full demo (2 eNB and 2 ue) - - Splitted prepare and install scripts. - - Added colour coded steps and error stoppage on install script. - -v1.12 (13/10/2014) - - Added bug fixes on launch and install scripts - - Added final version to openair svn - - Reworked README file. - -v1.13 (15/10/2014) - - Polishing of the demo - - Added bug fixes on launch scripts for enb1 - - Added feature to put measurements on CRM from enb1 - - Changed readable output of received measurement reports on enb2 - - Added more informative output on the sensingClient (TVWS) - - Demonstration now stops at end of MIH_Link_Actions.confirm - message on MIH_User of enb2 - - Added info on sensing client and CRM - - Reworked README file. - -################################################################################ EOF diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_install.sh b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_install.sh deleted file mode 100755 index bfd812b086..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_install.sh +++ /dev/null @@ -1,290 +0,0 @@ -#!/bin/bash - -######################################## -# -# SPECTRA DEMO INSTALLATION AND RUN -# -# -# -SCRIPT_VERSION="v1.12" -DATE="13 Oct 2014" -AUTHOR="Rui Costa" -EMAIL="ferreira@eurecom.fr" -######################################## - -OWN_TAG=$0 - -INSTALL_PATH=$PWD -OPENAIR_PATH=$INSTALL_PATH/openair4G -ODTONE_PATH=$INSTALL_PATH/ODTONE -BOOST_PATH=$INSTALL_PATH/boost_1_49_0 -SPECTRA_SRC_PATH=$INSTALL_PATH/spectra_demo_src - -NODE_TYPE=NONE -INSTALL_TYPE=NONE - -########################################################################################### UTILS -function util_echo { -# return value passed in $1 (usually $?) -# return value = 0 - OK - Light green -if [ $1 -eq 0 ] ; then - echo -e "\e[92m\e[1m[$OWN_TAG]\e[0m $2" -# return value != 0 - ERROR -else -# return value -gt 255 - WARNING - Light Yellow - if [ $1 -gt 255 ] ; then - echo -e "\e[93m\e[1m[$OWN_TAG]\e[0m $2" - else -# return value 1 to 255 - ERROR - Light RED - echo -e "\e[91m\e[1m[$OWN_TAG]\e[0m $2" - exit - fi -fi -} - -########################################################################################### BOOST C++ -function fetch_boost { -cd $INSTALL_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "BOOST C++ Library ..." -# Although new versions of boost exist, when compiling ODTONE he asks for v1.49.0 -# (we humour it so to not have linkage problems later) -wget --trust-server-names "http://downloads.sourceforge.net/project/boost/boost/1.49.0/boost_1_49_0.tar.gz?r=&ts=1412338583&use_mirror=optimate" -util_echo $? "Fetched BOOST C++ Library ..." -sleep 2 -tar -xzf boost_1_49_0.tar.gz -util_echo $? "Extracted BOOST C++ Library ..." -} - -function build_boost { -cd $BOOST_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "BOOST C++ Library ..." -sleep 2 -# Configuring Boost -./bootstrap.sh -util_echo $? "Bootstrapped BOOST C++ Library ..." -sleep 2 -# Compiling Boost (pthread link flag is vital) -./b2 --with-date_time --with-thread linkflags=-lpthread -util_echo $? "Built BOOST C++ Library ..." -} - -########################################################################################### ODTONE -function fetch_odtone { -cd $INSTALL_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "ODTONE ..." -sleep 2 -# Getting newest version of Odtone -git clone https://github.com/ATNoG/ODTONE.git -util_echo $? "Checked Out ODTONE from ITAveiro GIT..." -cd $ODTONE_PATH -git submodule update --init -util_echo $? "Updated ODTONE submodules..." -} - -function build_odtone { -cd $ODTONE_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "ODTONE ..." - -# /***** REPLACED WITH Git spectra PATCH -# -# Establishing the pointer to a local compilation of boost instead of the usual in /usr/local/src/ -#touch boost-build.jam -#echo "boost-build $BOOST_PATH/tools/build/v2 ;" > boost-build.jam -# Copying our new MIH Users -#cp -r $SPECTRA_SRC_PATH/mih_users/* $ODTONE_PATH/app/ -# we MUST patch these files! ODTONE by default has no knowledge of LTE links -# this overwrite of files ensures that full LTE link parameters exist. -# A better way of paching the files should be implemented later!! -#cp -r $SPECTRA_SRC_PATH/mihf/link.hpp $ODTONE_PATH/inc/odtone/mih/types/ -#cp -r $SPECTRA_SRC_PATH/mihf/archive.hpp $ODTONE_PATH/inc/odtone/mih/detail/ -#cp -r $SPECTRA_SRC_PATH/mihf/address.hpp $ODTONE_PATH/inc/odtone/mih/types/ -#cp -r $SPECTRA_SRC_PATH/mihf/bin_query.hpp $ODTONE_PATH/inc/odtone/mih/types/ -#cp -r $SPECTRA_SRC_PATH/mihf/CMakeLists.txt $ODTONE_PATH/lib/odtone/ -#cp -r $SPECTRA_SRC_PATH/mihf/conf.cpp $ODTONE_PATH/lib/odtone/ -#cp -r $SPECTRA_SRC_PATH/mihf/conf.hpp $ODTONE_PATH/inc/odtone/ -#cp -r $SPECTRA_SRC_PATH/mihf/Jamfile $ODTONE_PATH/lib/odtone/ -#cp -r $SPECTRA_SRC_PATH/mihf/command_service.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/dst_transaction.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/event_service.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/link_book.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/main.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/service_access_controller.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/service_management.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/src_transaction.cpp $ODTONE_PATH/src/mihf/ -#cp -r $SPECTRA_SRC_PATH/mihf/transaction_pool.cpp $ODTONE_PATH/src/mihf/ -# -# *****/ -# Applying SPECTRA patch to ODTONE source code -git apply --check --stat $SPECTRA_SRC_PATH/common/mihf_src/0001-SPECTRA-patch-for-ODTONE-v0.1.patch -util_echo $? "Checking if SPECTRA patch can be aplied..." -git apply $SPECTRA_SRC_PATH/common/mihf_src/0001-SPECTRA-patch-for-ODTONE-v0.1.patch -util_echo $? "Applying SPECTRA patch to ODTONE..." -# Changing hostname on the boost build -sed -i "s%nikaia%$USER%g" $ODTONE_PATH/boost-build.jam -util_echo $? "Modifying boost-build.jam..." -# Compiling Odtone core -$BOOST_PATH/b2 linkflags=-lpthread -util_echo $? "Compiled ODTONE..." -# Copying lte_test_user for this node -rm -rf $ODTONE_PATH/app/lte_test_user -cp -r $SPECTRA_SRC_PATH/$NODE_TYPE/mih_user/* $ODTONE_PATH/app/ -util_echo $? "Installed ODTONE mih user for: $NODE_TYPE..." -# Compiling lte_test_user -$BOOST_PATH/b2 app/lte_test_user/ linkflags=-lpthread linkflags=-lrt -util_echo $? "Compiled ODTONE apps..." -# Copying odtone confs -cp $SPECTRA_SRC_PATH/$NODE_TYPE/mih_conf/*.conf $ODTONE_PATH/dist/ -util_echo $? "Installed ODTONE configuration files for: $NODE_TYPE..." -} - -########################################################################################### OPENAIR -function fetch_openair { -mkdir $OPENAIR_PATH -cd $INSTALL_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "OPENAIR EURECOM ..." -sleep 2 -svn co http://svn.eurecom.fr/openair/openair4G/trunk $OPENAIR_PATH -util_echo $? "Checked Out openair4G/trunk from EURECOM SVN..." -} - -function build_openair { -cd $OPENAIR_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "OPENAIR ..." -sleep 2 -# Putting in place pre-made scripts for the build of openair -cp $SPECTRA_SRC_PATH/common/openair_scripts/* $OPENAIR_PATH/targets/PROJECTS/SPECTRA/ -util_echo $? "Installed OpenAir common build scripts ..." -# Putting in place pre-made scripts for the conf of openair -cp $SPECTRA_SRC_PATH/$NODE_TYPE/oai_conf/* $OPENAIR_PATH/targets/PROJECTS/SPECTRA/ -util_echo $? "Installed OpenAir startup scripts and conf for $NODE_TYPE..." -cd $OPENAIR_PATH/targets/PROJECTS/SPECTRA/ -# Updating the path location of ODTONE and BOOST on the script, according to the local machine. -sed -i "s%path_to_boost_folder%$BOOST_PATH%g" env_802dot21.bash -util_echo $? " Fixed BOOST path in env_802dot21.bash... $BOOST_PATH" -sed -i "s%path_to_odtone_folder%$ODTONE_PATH%g" env_802dot21.bash -util_echo $? " Fixed ODTONE path in env_802dot21.bash... $ODTONE_PATH" -if [ $NODE_TYPE == "enb2" ] ; then - sed -i "s%enb_lte_user%enb2_lte_user%g" env_802dot21.bash - util_echo $? " Fixed exec name (enb2_lte_user) for $NODE_TYPE..." -# sed -i "s%ENB_MIH_USER_CONF_FILE=enb_lte_user.conf%ENB_MIH_USER_CONF_FILE=enb2_lte_user.conf%g" env_802dot21.bash - util_echo $? " Fixed conf name (enb2_lte_user.conf) for path $NODE_TYPE..." -fi -if [ $NODE_TYPE == "ue2" ] ; then - sed -i "s%ue_lte_user%ue2_user%g" env_802dot21.bash - util_echo $? " Fixed exec name (enb2_lte_user) for $NODE_TYPE..." - util_echo $? " Fixed conf name (enb2_lte_user.conf) for path $NODE_TYPE..." -fi -# executing the (re)build of all components -# superuser necessary for installing the ITTY tool of openair -./build_all.bash -util_echo $? "Finished OpenAir build..." -} - -########################################################################################### PRINT_HELP -function print_help { -util_echo 333 " -------------------------------------------------" -util_echo 333 " USAGE: " -util_echo 333 " $ $OWN_TAG " -util_echo 333 " " -util_echo 333 " " -util_echo 333 " -full If you start from scratch" -util_echo 333 " -oai_svn If you got this script after" -util_echo 333 " checking out the Openair SVN" -util_echo 333 " " -util_echo 333 " -ue1 For installing ue1 files" -util_echo 333 " -ue2 For installing ue2 files" -util_echo 333 " -enb1 For installing eNB1 files" -util_echo 333 " -enb2 For installing eNB2 files" -util_echo 333 " " -util_echo 333 " -------------------------------------------------" -util_echo 333 " " -exit -} - -########################################################################################### MAIN -clear -# Testing Args -if [ $# -ne 2 ]; then - util_echo 333 " Incorrect Number of Arguments!!" - print_help -fi -if [ $1 == "-full" ]; then - INSTALL_TYPE=FULL -fi -if [ $1 == "-oai_svn" ]; then - INSTALL_TYPE=OAISVN -fi -if [ $2 == "-ue1" ]; then - NODE_TYPE=ue1 -fi -if [ $2 == "-ue2" ]; then - NODE_TYPE=ue2 -fi -if [ $2 == "-enb1" ]; then - NODE_TYPE=enb1 -fi -if [ $2 == "-enb2" ]; then - NODE_TYPE=enb2 -fi -if [ $INSTALL_TYPE == "NONE" ]; then - util_echo 333 " Incorrect Arguments (type of installation) !!" - print_help -fi -if [ $NODE_TYPE == "NONE" ]; then - util_echo 333 " Incorrect Arguments (type of node) !!" - print_help -fi -# Starting... -util_echo $? " -------------------------------------------------" -util_echo $? " SPECTRA DEMO " -util_echo $? " Installation Script" -util_echo $? " " -util_echo $? " $SCRIPT_VERSION $DATE" -util_echo $? " " -util_echo $? " Author: $AUTHOR <$EMAIL> " -util_echo $? " -------------------------------------------------" -util_echo 333 " Performing installation type: $INSTALL_TYPE for $NODE_TYPE" -sleep 3 -util_echo $? " -------------------------------------------------" -util_echo $? " >> Fetching sources" -util_echo $? " -------------------------------------------------" -if [ $INSTALL_TYPE == "OAISVN" ]; then - INSTALL_PATH=$PWD/../../../../ - OPENAIR_PATH=$PWD/../../../ - ODTONE_PATH=$INSTALL_PATH/ODTONE - BOOST_PATH=$INSTALL_PATH/boost_1_49_0 - SPECTRA_SRC_PATH=$PWD/spectra_demo_src -else - fetch_openair -fi -fetch_odtone -fetch_boost -sleep 1 -util_echo $? " -------------------------------------------------" -util_echo $? " >> Building" -util_echo $? " -------------------------------------------------" -sleep 2 -build_boost -build_odtone -build_openair -util_echo 333 " Open Air Configuration files at:" -util_echo 333 " $OPENAIR_PATH/targets/PROJECTS/SPECTRA/" -util_echo 333 " " -util_echo 333 " ODTONE Configuration files at:" -util_echo 333 " $ODTONE_PATH/dist/" -util_echo $? " " -util_echo $? " " -util_echo $? " -------------------------------------------------" -util_echo $? " SPECTRA DEMO preparation script ... finished!" -util_echo $? " -------------------------------------------------" -cd $INSTALL_PATH -exit 0 -########################################################################################### EOF - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_prepare.sh b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_prepare.sh deleted file mode 100755 index 365b849cb4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_prepare.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -######################################## -# -# SPECTRA DEMO PREPARATION -# -# -# -SCRIPT_VERSION="v1.12" -DATE="13 Oct 2014" -AUTHOR="Rui Costa" -EMAIL="ferreira@eurecom.fr" -######################################## - -OWN_TAG=$0 - -INSTALL_PATH=$PWD -OPENAIR_PATH=$INSTALL_PATH/openair4G -ODTONE_PATH=$INSTALL_PATH/ODTONE -BOOST_PATH=$INSTALL_PATH/boost_1_49_0 -SPECTRA_SRC_PATH=$INSTALL_PATH/spectra_demo_src -SPECTRA_OAI_PATH=$OPENAIR_PATH/targets/PROJECTS/SPECTRA/ - -########################################################################################### UTILS -function util_echo { -# return value passed in $1 (usually $?) -# return value = 0 - OK - Light green -if [ $1 -eq 0 ] ; then - echo -e "\e[92m\e[1m[$OWN_TAG]\e[0m $2" -# return value != 0 - ERROR -else -# return value -gt 255 - WARNING - Light Yellow - if [ $1 -gt 255 ] ; then - echo -e "\e[93m\e[1m[$OWN_TAG]\e[0m $2" - else -# return value 1 to 255 - ERROR - Light RED - echo -e "\e[91m\e[1m[$OWN_TAG]\e[0m $2" - exit - fi -fi -} - -########################################################################################### OPENAIR -function fetch_openair { -mkdir $OPENAIR_PATH -cd $INSTALL_PATH -util_echo $? "-------------------------------------------------" -util_echo $? "OPENAIR EURECOM ..." -sleep 2 -svn co http://svn.eurecom.fr/openair/openair4G/trunk $OPENAIR_PATH -util_echo $? "Checked Out openair4G/trunk from EURECOM SVN..." -} - -########################################################################################### MAIN -clear -# Starting... -util_echo $? " -------------------------------------------------" -util_echo $? " SPECTRA DEMO " -util_echo $? " Prepararation Script" -util_echo $? " " -util_echo $? " $SCRIPT_VERSION $DATE" -util_echo $? " " -util_echo $? " Author: $AUTHOR <$EMAIL> " -util_echo $? " -------------------------------------------------" -util_echo $? " " -sleep 3 -util_echo $? " -------------------------------------------------" -util_echo $? " >> Fetching sources" -util_echo $? " -------------------------------------------------" - -fetch_openair - -cd $SPECTRA_OAI_PATH/ -util_echo $? " >> Finished Prepare Script!!" -util_echo $? " >> Entering Install Script!!" -./spectra_demo_install.sh -oai_svn $1 - -########################################################################################### EOF - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient deleted file mode 100644 index 29465e592a..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.cpp deleted file mode 100644 index f079c0594e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.cpp +++ /dev/null @@ -1,249 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "cpprest/basic_types.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/uri.h" -#include - -#include "CRMClient.hpp" - -using namespace std; -using namespace web; -using namespace web::http; -using namespace web::http::client; -using namespace utility; - -// namespace odtone { - -CRMClient::CRMClient(char* url) -{ - m_url = (char*) (malloc (200* sizeof (char))); - m_url = url; -} - -CRMClient::CRMClient() -{ -} - -CRMClient::~CRMClient() -{ -} - -void CRMClient::SetUrl(char* url) -{ - m_url = url; -} - -// Retrieves a JSON value from an HTTP request. -pplx::task CRMClient::RequestJSONValueAsync() -{ - http_client client (U(m_url)); - return client.request(methods::GET).then([](http_response response) -> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - ofstream myfile; - myfile.open ("outputGET.txt"); - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString <second; - - for(auto iterInner = arrayValue.cbegin(); iterInner != arrayValue.cend(); ++iterInner) - { - const json::value &propertyValue = iterInner->second; - for(auto iterlast = propertyValue.cbegin(); iterlast != propertyValue.cend(); ++iterlast) - { - const json::value &Name = iterlast->first; - const json::value &Value = iterlast->second; - cout<< U("Parameter: ") << Name.to_string()< CRMClient::StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4) -{ - - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("pid"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6) -{ - - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("key"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("type"), json::value(param3))); - putvalue.push_back(make_pair(json::value("unit"), json::value(param4))); - putvalue.push_back(make_pair(json::value("value"), json::value(param5))); - putvalue.push_back(make_pair(json::value("time"), json::value(param6))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5) -{ - - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("did"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - putvalue.push_back(make_pair(json::value("time"), json::value(param5))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::Delete() -{ - char* url = m_url; - return pplx::create_task([url] -// return pplx::create_task([m_url] - { - http_client client (U(url)); - - return client.request(methods::DEL); - - }).then([](http_response response) - { - if(response.status_code() == status_codes::OK) - { - auto body = response.extract_string(); - - std::wcout << L"Deleted: " << body.get().c_str() << std::endl; - } - }); -} - - -// } \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.hpp deleted file mode 100644 index 29949336f4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClient.hpp +++ /dev/null @@ -1,56 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : FATMA HRIZI -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_CRM_CLIENT_HPP -#define ODTONE_CRM_CLIENT_HPP - - -#include -#include -#include -#include -#include -#include "cpprest/basic_types.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/uri.h" -#include - -// namespace odtone { -class CRMClient { - -public: - - CRMClient(); - ~CRMClient(); - CRMClient(char* url); - - void SetUrl(char* url); - pplx::task RequestJSONValueAsync(); - pplx::task StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4); - pplx::task StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6); - pplx::task StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5); - pplx::task Delete(); - - -private: - char * m_url; - -}; -// } - - -#endif diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClientmain b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClientmain deleted file mode 100644 index be19a63560..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/CRMClientmain and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/Makefile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/Makefile deleted file mode 100644 index baefb60f60..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# CRMClient.o: CRMClient.cpp CRMClient.hpp -# g++-4.8 CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -# -# -# install: main.cpp -# g++-4.8 -Wall main.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -L. -std=c++11 -lcrmclient -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -o CRMClientmain - -main: main.cpp - g++-4.8 -Wall main.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -L. -std=c++11 -lcrmclient -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -o CRMClientmain - -lib: CRMClient.cpp CRMClient.hpp - -# 64 bits compilation -# g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -m64 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -# g++-4.8 -shared -m64 -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o -# ln -sf libcrmclient.so.1.0 libcrmclient.so -# ln -sf libcrmclient.so.1.0 libcrmclient.so.1 - -# 32 bits compilation - g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem - g++-4.8 -shared -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o - ln -sf libcrmclient.so.1.0 libcrmclient.so - ln -sf libcrmclient.so.1.0 libcrmclient.so.1 - -clean: - rm *.o *.so* diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/main.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/main.cpp deleted file mode 100644 index 1bad18a3db..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/CRMClient/main.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "CRMClient.hpp" - -int main(int argc,char *argv[]) -{ - char * policiesurl = (char*) malloc( 100 * sizeof(char) ); - strcpy(policiesurl,"http://1.gae-spectra.appspot.com/policies"); - -// strcpy(policiesurl,"http://localhost:8888/policies"); - char * measurementsurl = (char*) malloc( 100* sizeof(char) ); - strcpy(measurementsurl,"http://1.gae-spectra.appspot.com/measurements"); -// strcpy(measurementsurl,"http://localhost:8888/measurements"); - char * decisionsurl = (char*) malloc( 100 * sizeof(char)); - strcpy(decisionsurl,"http://1.gae-spectra.appspot.com/decisions"); - int c; - - CRMClient client (policiesurl); - client.RequestJSONValueAsync().wait(); - - - return 0; -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/docs/server-gae-codeoverview.doc b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/docs/server-gae-codeoverview.doc deleted file mode 100644 index 2238611203..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/docs/server-gae-codeoverview.doc and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.classpath b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.classpath deleted file mode 100644 index a47d678fae..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.classpath +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.project b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.project deleted file mode 100644 index f19131ebc3..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.project +++ /dev/null @@ -1,43 +0,0 @@ - - - rest-gae-server - - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.google.gdt.eclipse.core.webAppProjectValidator - - - - - com.google.appengine.eclipse.core.gaeProjectChangeNotifier - - - - - com.google.appengine.eclipse.core.projectValidator - - - - - com.google.appengine.eclipse.core.enhancerbuilder - - - - - org.eclipse.jdt.core.javanature - com.google.appengine.eclipse.core.gaeNature - org.eclipse.wst.common.project.facet.core.nature - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.appengine.eclipse.core.prefs b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.appengine.eclipse.core.prefs deleted file mode 100644 index 47aa0ca55e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.appengine.eclipse.core.prefs +++ /dev/null @@ -1,9 +0,0 @@ -#Thu Sep 19 14:41:16 CEST 2013 -eclipse.preferences.version=1 -filesCopiedToWebInfLib=appengine-api-1.0-sdk-1.7.4.jar|appengine-api-labs.jar|appengine-endpoints.jar|appengine-jsr107cache-1.7.4.jar|asm-4.0.jar|datanucleus-api-jdo-3.1.1.jar|datanucleus-api-jpa-3.1.1.jar|datanucleus-appengine-2.1.1.jar|datanucleus-core-3.1.1.jar|geronimo-jpa_2.0_spec-1.0.jar|jdo-api-3.0.1.jar|jsr107cache-1.1.jar|jta-1.1.jar -gaeDatanucleusVersion=v2 -gaeDeployDialogSettings=true -gaeIsEclipseDefaultInstPath=true -googleCloudSqlEnabled=false -localDevMySqlEnabled=true -ormEnhancementInclusions=src/ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.gdt.eclipse.core.prefs b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.gdt.eclipse.core.prefs deleted file mode 100644 index c6960b06d2..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/.settings/com.google.gdt.eclipse.core.prefs +++ /dev/null @@ -1,5 +0,0 @@ -#Wed Dec 12 09:47:01 CET 2012 -eclipse.preferences.version=1 -jarsExcludedFromWebInfLib= -warSrcDir=war -warSrcDirIsOutput=true diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/gcm-server.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/gcm-server.jar deleted file mode 100644 index 41264c8095..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/gcm-server.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/json_simple-1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/json_simple-1.1.jar deleted file mode 100644 index f395f41471..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/json_simple-1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.json.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.json.jar deleted file mode 100644 index 543438992f..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.json.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.json.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.json.jar deleted file mode 100644 index 49b2873525..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.json.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.servlet.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.servlet.jar deleted file mode 100644 index 5df964798b..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.servlet.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.wadl.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.wadl.jar deleted file mode 100644 index 5a96ccac00..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.wadl.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.xml.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.xml.jar deleted file mode 100644 index 213199baaa..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.ext.xml.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.jar deleted file mode 100644 index 32a3c8483f..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.restlet.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.beans-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.beans-3.1.1.RELEASE.jar deleted file mode 100644 index a69bcb1f3d..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.beans-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.context-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.context-3.1.1.RELEASE.jar deleted file mode 100644 index a35e486989..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.context-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web-3.1.1.RELEASE.jar deleted file mode 100644 index 42ed92c7c2..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar deleted file mode 100644 index 8e27a5bc7e..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/jdoconfig.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/jdoconfig.xml deleted file mode 100644 index 6961b7ed9b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/jdoconfig.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/persistence.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/persistence.xml deleted file mode 100644 index d15d3fbbfa..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/META-INF/persistence.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - org.datanucleus.api.jpa.PersistenceProviderImpl - - - - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/DeviceManager.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/DeviceManager.java deleted file mode 100644 index 8f0f5e4922..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/DeviceManager.java +++ /dev/null @@ -1,181 +0,0 @@ -package fr.eurecom.pushing; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Date; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.mortbay.log.Log; -import org.restlet.resource.Get; -import fr.eurecom.senml.entity.RegisteredDeviceType; -import fr.eurecom.senml.persistence.JDOStorage; - -/** - * Exposes the following URLs: - * - /pushing/register, POST, to register a device - * - /pushing/unregister, POST, to unregister a device - * - /pushing/list, GET, to retrieve the list of registered devices - * - /pushing/test, GET, test a notification to the registered devices - * - */ -public class DeviceManager extends HttpServlet { - /** - * - */ - private static final long serialVersionUID = 1L; - private static final Logger log = Logger.getLogger("DeviceManager"); - - public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - System.out.println("OK doPost"); - System.out.println(request.getParameter("reqType") + " " + request.getParameter("deviceType")); - try { - if (request.getParameter("reqType").equals("reg")) { - // Registration of a device. Android or iOS? - if (request.getParameter("deviceType").equals("android")) { - registerAndroidDevice(request, response); - } else if (request.getParameter("deviceType").equals("ios")) { - registerAppleDevice(request, response); - } - } else if (request.getParameter("reqType").equals("unreg")) { - System.out.println("OK UNREGISTERING!"); - if (request.getParameter("deviceType").equals("android")) { - System.out.println("UNREGISTERING ANDROID!"); - unregisterAndroidDevice(request, response); - } else if (request.getParameter("deviceType").equals("ios")) { - unregisterAppleDevice(request, response); - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - response.setStatus(500); - } - } - - - private void unregisterAppleDevice(HttpServletRequest request, - HttpServletResponse response) { - // TODO Auto-generated method stub - response.setStatus(403); - } - - - private void unregisterAndroidDevice(HttpServletRequest request, - HttpServletResponse response) { - String key = request.getParameter("registrationID"); - // TODO Auto-generated method stub - List devices = JDOStorage.getInstance().getAll(RegisteredDeviceType.class); - Iterator iter = devices.iterator(); - while (iter.hasNext()) { - RegisteredDeviceType device = iter.next(); - System.out.print("Analyzing " + device.getDeviceRegistrationKey()); - if (device.getDeviceRegistrationKey().equals(key)) { - JDOStorage.getInstance().delete(device); - System.out.println("OK"); - return; - } else { - System.out.println("NO!"); - } - } - } - - private void registerAppleDevice(HttpServletRequest request, HttpServletResponse response) { - // TODO Auto-generated method stub - response.setStatus(403); - } - - private void registerAndroidDevice(HttpServletRequest request, HttpServletResponse response) throws JSONException, IOException { - Date n = new Date(); - - boolean isadmin = (request.getParameter("isadmin") != null); - - - - RegisteredDeviceType device = new RegisteredDeviceType( - UUID.randomUUID().toString(), - request.getParameter("deviceType") + ": " + request.getParameter("deviceDet"), - request.getParameter("devicekey"), n.getTime()); - if (isadmin) { - System.out.println("ADMIN"); - device.setIsadmin(isadmin); - } - JDOStorage.getInstance().write(device); - response.setContentType("text/html"); - PrintWriter writer = response.getWriter(); - response.setStatus(200); - writer.write("Registered"); - } - - /** - * Handle HTTP GET method / Json - * - * @return a JSON Zone Representation - */ - @Get - public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - PrintWriter writer = response.getWriter(); - if (request.getPathInfo().equals("/test")) { - GCMPushingServer GCM = GCMPushingServer.getInstance(); - try { - GCM.sendNotification("notification test "); - writer.write("Sent a notification test to the following devices:"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else if (request.getPathInfo().equals("/alarm")) { - GCMPushingServer GCM = GCMPushingServer.getInstance(); - try { - GCM.sendNotification("ALARM for sensor: " + request.getParameter("sensor")); - writer.write("OK"); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - writer.write("NO"); - } - return; - } - List devices = JDOStorage.getInstance().getAll(RegisteredDeviceType.class); - if (devices.isEmpty()) { - // No devices registered - response.setStatus(200); - writer.write("The list of devices is empty."); - return; - } - response.setContentType("text/html"); - JSONArray jsonDevices = new JSONArray(); - Iterator iter = devices.iterator(); - writer.write(""); - // Get the list of devices and build the json - try { - while (iter.hasNext()) { - RegisteredDeviceType current = iter.next(); - JSONObject obj = new JSONObject(current); - jsonDevices.put(obj); - String deviceLogo = obj.getString("deviceType").split(":")[0].toLowerCase(); - - writer.write(""); - } - writer.write("
Device LogoDevice Typeregistered onRegistration Key
" - + obj.getString("deviceType") + "" - + obj.getString("time") + "" - + obj.getString("deviceRegistrationKey") + "
"); - } catch (Exception e) { - response.setStatus(500); - log.log(Level.WARNING, "", e); - - } - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/GCMPushingServer.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/GCMPushingServer.java deleted file mode 100644 index fae42ba44b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/GCMPushingServer.java +++ /dev/null @@ -1,206 +0,0 @@ -package fr.eurecom.pushing; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import com.google.android.gcm.server.Message; -import com.google.android.gcm.server.MulticastResult; -import com.google.android.gcm.server.Sender; - -import fr.eurecom.senml.entity.RegisteredDeviceType; -import fr.eurecom.senml.entity.SensorAdmin; -import fr.eurecom.senml.persistence.JDOStorage; - -public class GCMPushingServer implements IPushingServer { - - private List REG_IDS, ADMIN_REG_IDS; - // HARD-CODED, move on a different configuration file! - private String API_KEY = "AIzaSyDO3RS9FZPTp0d2BNn-0zKUuiiOI45-ED8"; - private boolean initialized = false; - - private static final GCMPushingServer instance = new GCMPushingServer(); - - protected GCMPushingServer() { - - } - - public static GCMPushingServer getInstance() { - if (!instance.isInitialized()) { - instance.initialize(); - } - return instance; - } - - public boolean isInitialized() { - return initialized; - } - - public void initialize() { - REG_IDS = ADMIN_REG_IDS = new ArrayList(); - initialized = true; - } - - public void refreshDevicesList() { - REG_IDS = new ArrayList(); - List list = JDOStorage.getInstance().getAll( - RegisteredDeviceType.class); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - RegisteredDeviceType current = iter.next(); - if (isAndroidDevice(current)) { - if (current.isIsadmin()) { - if (ADMIN_REG_IDS.indexOf(current) == -1) { - System.out.println("Refreshing the list of admins...adding " - + current.getDeviceRegistrationKey()); - ADMIN_REG_IDS.add(current.getDeviceRegistrationKey()); - } - } else { - if (REG_IDS.indexOf(current) == -1) { - System.out.println("Refreshing the list...adding " - + current.getDeviceRegistrationKey()); - REG_IDS.add(current.getDeviceRegistrationKey()); - } - } - } - } - } - - /** - * Return true if the device is of type Android - * - * @param device - * @return - */ - private boolean isAndroidDevice(RegisteredDeviceType device) { - System.out.print("isAndroidDevice? "); - if (device.getDeviceType().toLowerCase().indexOf("android") > -1) { - System.out.println("Yes"); - } else { - System.out.println("No"); - } - return (device.getDeviceType().toLowerCase().indexOf("android") > -1); - } - - @Override - public void sendNotification(String data) throws JSONException { - // Refresh the devices list and put it on the JSON object - refreshDevicesList(); - System.out.println("Calling gcmnotify with data = " + data); - GCMnotify(data); - // TODO: Check that is part of monitored sensors - GCMnotify(data, true); - } - - private void GCMnotify(String data) { - - System.out.println("Sending data: " + data); - - // Instance of com.android.gcm.server.Sender, that does the - // transmission of a Message to the Google Cloud Messaging service. - Sender sender = new Sender(API_KEY); - - // This Message object will h old the data that is being transmitted - // to the Android client devices. For this demo, it is a simple text - // string, but could certainly be a JSON object. - Message message = new Message.Builder() - - // If multiple messages are sent using the same .collapseKey() - // the android target device, if it was offline during earlier - // message - // transmissions, will only receive the latest message for that - // key when - // it goes back on-line. - // .collapseKey(collapseKey) - .timeToLive(30).delayWhileIdle(true) - .addData("type", "zoneupdated") - .addData("notificationmessage", "WL-BOX, zone updated: " + data.replace("ZoneUpdated", "")) - .addData("alertstatus", "info") - .addData("message", data).build(); - - if (REG_IDS.size() == 0) { - // Noone to notify - return; - } - try { - // use this for multicast messages. The second parameter - // of sender.send() will need to be an array of register ids. - - MulticastResult result = sender.send(message, REG_IDS, 1); - - if (result.getResults() != null) { - int canonicalRegId = result.getCanonicalIds(); - if (canonicalRegId != 0) { - - } - } else { - int error = result.getFailure(); - System.out.println("Broadcast failure: " + error); - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - - // TODO: Only one constructor, most of the code is the same... - private void GCMnotify(String data, boolean isadmin) { - System.out.println("ADMIN! Sending data: " + data); - - // Instance of com.android.gcm.server.Sender, that does the - // transmission of a Message to the Google Cloud Messaging service. - Sender sender = new Sender(API_KEY); - - // This Message object will h old the data that is being transmitted - // to the Android client devices. For this demo, it is a simple text - // string, but could certainly be a JSON object. - Message message = new Message.Builder() - - // If multiple messages are sent using the same .collapseKey() - // the android target device, if it was offline during earlier - // message - // transmissions, will only receive the latest message for that - // key when - // it goes back on-line. - // .collapseKey(collapseKey) - .timeToLive(30).delayWhileIdle(true) - .addData("type", "alert") - .addData("notificationmessage", "WL-BOX admin, SENSOR ALERT!") - .addData("alertstatus", "alert") - .addData("message", data).build(); - - if (ADMIN_REG_IDS.size() == 0) { - // Noone to notify - System.out.println("Admin IDS empty"); - return; - } - try { - // use this for multicast messages. The second parameter - // of sender.send() will need to be an array of register ids. - - MulticastResult result = sender.send(message, ADMIN_REG_IDS, 1); - - if (result.getResults() != null) { - System.out.println("!) null"); - int canonicalRegId = result.getCanonicalIds(); - if (canonicalRegId != 0) { - - } - } else { - int error = result.getFailure(); - System.out.println("Broadcast failure: " + error); - } - - } catch (Exception e) { - e.printStackTrace(); - } - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/IPushingServer.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/IPushingServer.java deleted file mode 100644 index 29d2ef0702..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/pushing/IPushingServer.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.eurecom.pushing; - -import org.json.JSONException; - -public interface IPushingServer { - public void sendNotification(String data) throws JSONException; -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/Contact.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/Contact.java deleted file mode 100644 index 95b66ab678..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/Contact.java +++ /dev/null @@ -1,146 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -/** - * This class implements the Contact entity. - * - */ -public class Contact { - - // private static final long serialVersionUID = 7390103290165670089L; - /** - * Contact's identifier. - */ - private final int id; - /** - * Contact's first name - */ - private String firstName = "N/A"; - /** - * Contact's last name - */ - private String lastName = "N/A"; - /** - * Contact's email address - */ - private String mail = "N/A"; - /** - * Contact's phone number - */ - private String phone = "N/A"; - - /** - * Constructs a contact with the specified id. - * - * @param id - */ - public Contact(int id) { - this.id = id; - } - - /** - * Constructs a contact with the specified values. - * - * @param id - * Contact's identifier. - * @param firstname - * Contact's first name. - * @param lastname - * Contact's last name. - * @param mail - * Contact's email address. - * @param phone - * Contact's Phone number. - */ - public Contact(int id, String firstname, String lastname, String mail, - String phone) { - this.id = id; - this.firstName = firstname; - this.lastName = lastname; - this.mail = mail; - this.phone = phone; - } - - /** - * - * @return the contact id. - */ - public int getId() { - return id; - } - - /** - * Set an email address - * - * @param mail - * email address. - */ - public void setMail(String mail) { - this.mail = mail; - } - - /** - * Retrieve the email address. - * - * @return the mail address if set, "N/A" otherwise. - */ - public String getMail() { - return mail; - } - - /** - * Retrieve the first name. - * - * @return the first name if set, "N/A" otherwise. - */ - public String getFirstName() { - return firstName; - } - - /** - * Set a first name. - * - * @param firstname - * to set. - */ - public void setFirstName(String firstname) { - this.firstName = firstname; - } - - /** - * Retrieve the last name. - * - * @return the last name set, "N/A" otherwise. - */ - public String getLastName() { - return lastName; - } - - /** - * Set a last name. - * - * @param lastname - * to set, "N/A" otherwise. - */ - public void setLastName(String lastname) { - this.lastName = lastname; - } - - /** - * Retrieve the phone number. - * - * @return the phone set, "N/A" otherwise. - */ - public String getPhone() { - return phone; - } - - /** - * Set the phone number. - * - * @param phone - * number to set. - */ - public void setPhone(String phone) { - this.phone = phone; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactBaseResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactBaseResource.java deleted file mode 100644 index 4f3b3c6c46..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactBaseResource.java +++ /dev/null @@ -1,173 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.restlet.data.Status; -import org.restlet.ext.wadl.WadlServerResource; - -import com.google.appengine.api.channel.ChannelMessage; -import com.google.appengine.api.channel.ChannelService; -import com.google.appengine.api.channel.ChannelServiceFactory; - -import fr.eurecom.restlet.resources.persistence.Storage; - -public abstract class ContactBaseResource extends WadlServerResource { - private final static String CONTACTS_UPDATED = "contactsupdated"; - private static final Logger log = Logger.getLogger("ContactBaseResource"); - - public enum MEMBERS { - CONTACT, ID, FIRSTNAME, LASTNAME, PHONE, MAIL - } - - protected static final String CONTACTS = "contacts"; - protected static final String CONTACT = "contact"; - protected static final String ID = "id"; - protected static final String FIRST_NAME = "firstname"; - protected static final String LAST_NAME = "lastname"; - protected static final String PHONE = "phone"; - protected static final String MAIL = "mail"; - - protected static final String URL = "url"; - protected static final String REQUEST_QUERY_SORT = "sort"; - -// HACK, this class is also used to support subscribers for senml objects. Move the subscribers channel API Stuffs to a common place. - protected static final Map subscribers = new HashMap(); - - final static class Token { - public String token; - public long timestamp; - - public Token(String token) { - this.token = token; - this.timestamp = System.currentTimeMillis(); - } - } - /** - * Retrieve the contacts from the persistence layer. - * - * @return the contact's list. - */ - protected List getContacts() { - // Dispatcher d = (Dispatcher)getApplication(); - return Storage.getInstance().getContacts(MEMBERS.ID, 0, 999); - } - - /** - * Retrieve the contacts sorted by Last name from the persistence layer. - * - * @return a sorted contacts list. - */ - @SuppressWarnings("unchecked") - protected List getSortedContacts(String sort) { - try { - MEMBERS mSorted = sort == null || sort.trim().isEmpty() ? MEMBERS.LASTNAME - : MEMBERS.valueOf(sort.trim().toUpperCase()); - - return Storage.getInstance().getContacts(mSorted, 0, 999); - } catch (Exception e) { - e.printStackTrace(); - return Collections.EMPTY_LIST; - } - } - - /** - * Retrieve the contact which matches this id from the persistence layer. - * - * @param id - * @return contact or null. - */ - protected Contact getContact(int id) { - return Storage.getInstance().getContact(id); - } - - /** - * Delete a contact from the persistence layer. - * - * @param id - * @return Status.SUCCESS_NO_CONTENT if deleted, - * Status.CLIENT_ERROR_NOT_FOUND otherwise. - */ - protected Status removeContact(int id) { - if (Storage.getInstance().removeContact(id)) { - sendUpdateSubscribers(CONTACTS_UPDATED); - return Status.SUCCESS_NO_CONTENT; - } - else { - return Status.CLIENT_ERROR_NOT_FOUND; - } - } - - /** - * Save a new contact to the persistence layer. (restricted to 50 contacts - * currently). - * - * @param contact - * @return Status.SUCCESS_CREATED if saved, - * Status.SERVER_ERROR_INSUFFICIENT_STORAGE otherwise. - */ - protected Status addContact(Contact contact) { - if (Storage.getInstance().saveContact(contact)) { - sendUpdateSubscribers(CONTACTS_UPDATED); - return Status.SUCCESS_CREATED; - } - return Status.SERVER_ERROR_INSUFFICIENT_STORAGE; - } - - /** - * Update a contact to the persistence layer. - * - * @param contact - * @return Status.SUCCESS_OK if updated, Status.CLIENT_ERROR_NOT_FOUND - * otherwise. - */ - protected Status updateContact(Contact contact) { - if (Storage.getInstance().saveContact(contact)) { - sendUpdateSubscribers(CONTACTS_UPDATED); - return Status.SUCCESS_NO_CONTENT; - } else { - return Status.CLIENT_ERROR_NOT_FOUND; - } - } - - - public static void addSubscriber(String clientID, String token) { - subscribers.put(clientID, new Token(token)); - } - - public static void deleteSubscriber(String clientID) { - subscribers.remove(clientID); - } - - public static String getToken(String clientID) { - Token t = subscribers.get(clientID); - if (t != null && (System.currentTimeMillis() - t.timestamp) < 7200000) { - return t.token; - } - else { - return null; - } - } - - public static void sendUpdateSubscribers(String message) { - ChannelService service = ChannelServiceFactory.getChannelService(); - try { - service.sendMessage(new ChannelMessage("I235", message)); - log.info("Notified I235" + message); - } - catch (Exception e) { - log.log(Level.WARNING, "Error Notifying client I235", e); - System.out.println("Error notifying client I235"); - } - -/* for (String clientID : subscribers.keySet()) { - System.out.println("Will notify " + clientID + " " + message); - service.sendMessage(new ChannelMessage(clientID, message)); - } - */ - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactResource.java deleted file mode 100644 index ae313671bb..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactResource.java +++ /dev/null @@ -1,242 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.Map; - -import org.json.JSONObject; -import org.restlet.data.Form; -import org.restlet.data.MediaType; -import org.restlet.data.Status; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.ParameterInfo; -import org.restlet.ext.wadl.ParameterStyle; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.RequestInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.xml.DomRepresentation; -import org.restlet.representation.Representation; -import org.restlet.resource.Delete; -import org.restlet.resource.Get; -import org.restlet.resource.Put; -import org.restlet.resource.ResourceException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -/** - * - * This class represents the Contact resource - */ - -public class ContactResource extends ContactBaseResource { - - /** - * underlying contact. - */ - private Contact contact = null; - - /** - * Resource contact identifier. - */ - private int identifier = -1; - - @Override - public Representation describe() { - System.out.println("describe"); - setName("Contact Resource"); - setDescription("Manage the current Contact"); - return super.describe(); - } - - @Override - public void describeDelete(MethodInfo mInfo) { - mInfo.setIdentifier("ContactDelete"); - mInfo.setDocumentation("To Delete the current contact."); - - ResponseInfo response = new ResponseInfo( - "Contact deleted. No contents returned."); - response.getStatuses().add(Status.SUCCESS_NO_CONTENT); - mInfo.getResponses().add(response); - - response = new ResponseInfo("Contact not found"); - response.getStatuses().add(Status.CLIENT_ERROR_NOT_FOUND); - mInfo.getResponses().add(response); - } - - @Override - public void describeGet(MethodInfo mInfo) { - mInfo.setIdentifier("ContactDetail"); - mInfo.setDocumentation("To retrieve details of the current contact."); - - ResponseInfo response = new ResponseInfo("Current contact details"); - response.getStatuses().add(Status.SUCCESS_OK); - - RepresentationInfo repInfo = new RepresentationInfo( - MediaType.APPLICATION_XML); - repInfo.setXmlElement(CONTACT); - repInfo.setDocumentation("XML representation of the current contact."); - response.getRepresentations().add(repInfo); - - repInfo = new RepresentationInfo(MediaType.APPLICATION_JSON); - repInfo.setDocumentation("JSON representation of the current contact"); - repInfo.setXmlElement(CONTACT); - response.getRepresentations().add(repInfo); - mInfo.getResponses().add(response); - - response = new ResponseInfo("Contact not found"); - repInfo = new RepresentationInfo(MediaType.TEXT_HTML); - repInfo.setIdentifier("contactError"); - response.getStatuses().add(Status.CLIENT_ERROR_NOT_FOUND); - response.getRepresentations().add(repInfo); - mInfo.getResponses().add(response); - } - - @Override - public void describePut(MethodInfo mInfo) { - mInfo.setIdentifier("ContactUpdate"); - mInfo.setDocumentation("To update details of the current contact"); - - RequestInfo requestInfo = new RequestInfo(); - // requestInfo.getParameters().add( - // new ParameterInfo(ID, true, "Number", ParameterStyle.QUERY, - // "Contact identifier")); - requestInfo.getParameters().add( - new ParameterInfo(FIRST_NAME, false, "String", - ParameterStyle.QUERY, "Contact First Name")); - requestInfo.getParameters().add( - new ParameterInfo(LAST_NAME, false, "String", - ParameterStyle.QUERY, "Contact Last Name")); - requestInfo.getParameters().add( - new ParameterInfo(PHONE, false, "String", ParameterStyle.QUERY, - "Contact Phone number")); - requestInfo.getParameters().add( - new ParameterInfo(MAIL, false, "String", ParameterStyle.QUERY, - "Contact email address")); - - mInfo.setRequest(requestInfo); - - ResponseInfo responseInfo = new ResponseInfo("Contact not Found"); - responseInfo.getStatuses().add(Status.CLIENT_ERROR_NOT_FOUND); - mInfo.getResponses().add(responseInfo); - - responseInfo = new ResponseInfo( - "Contact updated, no contents returned."); - responseInfo.getStatuses().add(Status.SUCCESS_NO_CONTENT); - mInfo.getResponses().add(responseInfo); - } - - @Override - protected void doInit() throws ResourceException { - String sIdentifier = (String) getRequest().getAttributes().get("id"); - if (sIdentifier != null) { - identifier = Integer.parseInt(sIdentifier); - contact = getContact(identifier); - } - setExisting(contact != null); - } - - /** - * Handle HTTP GET method / xml - * - * @return a xml resource representation - */ - @Get("xml") - public Representation toXML() { - try { - DomRepresentation representation = new DomRepresentation( - MediaType.TEXT_XML); - - Document d = representation.getDocument(); - Element eltItem = d.createElement(CONTACT); - d.appendChild(eltItem); - - Element el = d.createElement(ID); - el.appendChild(d.createTextNode("" + contact.getId())); - eltItem.appendChild(el); - - el = d.createElement(FIRST_NAME); - el.appendChild(d.createTextNode(contact.getFirstName())); - eltItem.appendChild(el); - - el = d.createElement(LAST_NAME); - el.appendChild(d.createTextNode(contact.getLastName())); - eltItem.appendChild(el); - - el = d.createElement(PHONE); - el.appendChild(d.createTextNode(contact.getPhone())); - eltItem.appendChild(el); - - el = d.createElement(MAIL); - el.appendChild(d.createTextNode(contact.getMail())); - eltItem.appendChild(el); - - d.normalizeDocument(); - - return representation; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - /** - * Handle HTTP GET method / json - * - * @return a json resource representation. - */ - @Get("json") - public Representation toJSON() { - JSONObject jObject = new JSONObject(); - try { - jObject.put(ID, "" + contact.getId()); - jObject.put(FIRST_NAME, contact.getFirstName()); - jObject.put(LAST_NAME, contact.getLastName()); - jObject.put(PHONE, contact.getPhone()); - jObject.put(MAIL, contact.getMail()); - - return new JsonRepresentation(jObject); - } catch (Exception e) { - return null; - } - } - - /** - * Handle HTTP PUT method. Update an existing contact. - * - * @param entity - */ - @Put - public void updateContact(Representation entity) { - Map map = new Form(entity).getValuesMap(); - - for (String k : map.keySet()) { - MEMBERS m = MEMBERS.valueOf(k.toUpperCase()); - - switch (m) { - case FIRSTNAME: - contact.setFirstName(map.get(k)); - break; - case LASTNAME: - contact.setLastName(map.get(k)); - break; - case PHONE: - contact.setPhone(map.get(k)); - break; - case MAIL: - contact.setMail(map.get(k)); - break; - } - } - - Status updateStatus = super.updateContact(contact); - setStatus(updateStatus); - } - - /** - * Handle HTTP DELETE method. Delete an existing contact. - */ - @Delete - public void deleteContact() { - Status deleteStatus = super.removeContact(identifier); - setStatus(deleteStatus); - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsResource.java deleted file mode 100644 index ce9426c977..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsResource.java +++ /dev/null @@ -1,335 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.Iterator; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.restlet.Context; -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.data.Form; -import org.restlet.data.MediaType; -import org.restlet.data.Method; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.OptionInfo; -import org.restlet.ext.wadl.ParameterInfo; -import org.restlet.ext.wadl.ParameterStyle; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.RequestInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.xml.DomRepresentation; -import org.restlet.representation.Representation; -import org.restlet.representation.StringRepresentation; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -public class ContactsResource extends ContactBaseResource { - - /** - * {@inheritDoc} - */ - @Override - public Representation describe() { - setName("Contacts Resource"); - setDescription("Retrieve contacts list"); - return super.describe(); - } - - /** - * {@inheritDoc} - */ - @Override - public void describeGet(MethodInfo mInfo) { - mInfo.setIdentifier("ContactsList"); - mInfo.setDocumentation("To Retrieve a sorted list of contacts"); - - RequestInfo requestInfo = new RequestInfo(); - ParameterInfo pInfo = createCommonParameter(REQUEST_QUERY_SORT, - "Sort query", LAST_NAME); - pInfo.getOptions().add( - createOptionInfo(FIRST_NAME, "Sort by first name")); - pInfo.getOptions() - .add(createOptionInfo(LAST_NAME, "Sort by last name")); - pInfo.getOptions().add(createOptionInfo(MAIL, "Sort by Email")); - pInfo.getOptions().add(createOptionInfo(PHONE, "Sort by Phone")); - - requestInfo.getParameters().add(pInfo); - mInfo.setRequest(requestInfo); - - ResponseInfo response = new ResponseInfo("Current list of contacts"); - response.getStatuses().add(Status.SUCCESS_OK); - - RepresentationInfo repInfo = new RepresentationInfo( - MediaType.APPLICATION_XML); - repInfo.setXmlElement(CONTACTS); - repInfo.setDocumentation("XML List of contacts"); - response.getRepresentations().add(repInfo); - - repInfo = new RepresentationInfo(MediaType.APPLICATION_JSON); - repInfo.setXmlElement(CONTACTS); - repInfo.setDocumentation("JSON List of contacts"); - response.getRepresentations().add(repInfo); - - mInfo.getResponses().add(response); - } - - /** - * {@inheritDoc} - */ - @Override - public void describePost(MethodInfo mInfo) { - mInfo.setIdentifier("ContactsAdd"); - mInfo.setIdentifier("To add a new contact to the list"); - - RequestInfo requestInfo = new RequestInfo(); - requestInfo.getParameters().add( - new ParameterInfo(ID, true, "Number", ParameterStyle.QUERY, - "Contact identifier")); - requestInfo.getParameters().add( - createCommonParameter(FIRST_NAME, "Contact First Name")); - requestInfo.getParameters().add( - createCommonParameter(LAST_NAME, "Contact Last Name")); - requestInfo.getParameters().add( - createCommonParameter(PHONE, "Contact Phone Number")); - requestInfo.getParameters().add( - createCommonParameter(MAIL, "Contact Email address")); - - mInfo.setRequest(requestInfo); - - ResponseInfo response = new ResponseInfo("Contact saved"); - response.getStatuses().add(Status.SUCCESS_CREATED); - response.getParameters().add( - new ParameterInfo("Content-Location", ParameterStyle.HEADER, - "URI contact saved")); - mInfo.getResponses().add(response); - - response = new ResponseInfo("Contact not saved. (restricted to 50)"); - response.getStatuses().add(Status.SERVER_ERROR_INSUFFICIENT_STORAGE); - mInfo.getResponses().add(response); - } - - // HACK: Version Restlet-gae 2.1-rc5. - // There is an error routing the GET request when - // the Request Header Content-Type = application/x-www-form-urlencoded and - // Header Accept = "application/json" and - // URI have a query : http://localhost:8888/contacts?sort=firstname. - // In this case the router ignores the Accept header and route the request - // to @Get("xml") systematically because the query is badly interpreted. - // To workaround this problem, at the init we reformat the Entity with an - // empty Representation. - - @Override - public void init(Context context, Request request, Response response) { - // System.out.println("init" + request + " " + response); - // System.out.println("Content-Type: " + - // request.getEntity().getMediaType()); - if (request.getMethod().compareTo(Method.GET) == 0) { - Representation entity = request.getEntity(); - System.out.println("Entity " + entity + " Content-Type: " - + request.getEntity().getMediaType()); - request.setEntity(new StringRepresentation("")); - } - super.init(context, request, response); - } - - /** - * Handle HTTP GET Metod / xml - * - * @return an XML list of contacts. - */ - @Get("xml") - public Representation toXML() { - // System.out.println("Request Original Ref " + getOriginalRef()); - // System.out.println("Request Entity " + getRequest().getEntityAsText() - // + - // " entity mediaType " + getRequest().getEntity().getMediaType()); - - Reference ref = getRequest().getResourceRef(); - final String baseURL = ref.getHierarchicalPart(); - Form formQuery = ref.getQueryAsForm(); - - try { - DomRepresentation representation = new DomRepresentation( - MediaType.TEXT_XML); - - Document d = representation.getDocument(); - Element elContacts = d.createElement(CONTACTS); - d.appendChild(elContacts); - - Iterator it = getSortedContacts( - formQuery.getFirstValue(REQUEST_QUERY_SORT, LAST_NAME)) - .iterator(); - while (it.hasNext()) { - Contact contact = it.next(); - - Element el = d.createElement(CONTACT); - - Element id = d.createElement(ID); - id.appendChild(d.createTextNode(String.format("%s", - contact.getId()))); - el.appendChild(id); - - Element firstname = d.createElement(FIRST_NAME); - firstname.appendChild(d.createTextNode(contact.getFirstName())); - el.appendChild(firstname); - - Element lastname = d.createElement(LAST_NAME); - lastname.appendChild(d.createTextNode(contact.getLastName())); - el.appendChild(lastname); - - Element url = d.createElement(URL); - url.appendChild(d.createTextNode(String.format("%s/%s", - baseURL, contact.getId()))); - el.appendChild(url); - - elContacts.appendChild(el); - } - - d.normalizeDocument(); - return representation; - } catch (Exception e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * Handle HTTP GET method / Json - * - * @return a JSON list of contacts. - */ - @Get("json") - public Representation toJSON() { - // System.out.println("Request Original Ref " + getOriginalRef()); - // System.out.println("Request Entity " + getRequest().getEntityAsText() - // + - // " entity mediaType " + getRequest().getEntity().getMediaType()); - - try { - JSONArray jcontacts = new JSONArray(); - Reference ref = getRequest().getResourceRef(); - final String baseURL = ref.getHierarchicalPart(); - Form formQuery = ref.getQueryAsForm(); - - Iterator it = getSortedContacts( - formQuery.getFirstValue(REQUEST_QUERY_SORT, LAST_NAME)) - .iterator(); - - while (it.hasNext()) { - Contact contact = it.next(); - - JSONObject jcontact = new JSONObject(); - jcontact.put(ID, String.format("%s", contact.getId())); - jcontact.put(URL, String.format("%s/%s", baseURL, contact.getId())); - jcontact.put(FIRST_NAME, contact.getFirstName()); - jcontact.put(LAST_NAME, contact.getLastName()); - jcontacts.put(jcontact); - } - - JSONObject contacts = new JSONObject(); - contacts.put(CONTACTS, jcontacts); - return new JsonRepresentation(contacts); - } catch (Exception e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * Handle HTTP POST Method. - * - * @param entity - * contact to create. - * @return The new contact URI representation (Header Content-Location). - */ - @Post - public Representation createContact(Representation entity) { - Form form = new Form(entity); - - try { - int id = Integer.parseInt(form.getFirstValue(ID, "-1")); - if (id == -1) { - System.out.println("id = -1"); - setStatus(Status.CLIENT_ERROR_EXPECTATION_FAILED, - "Must provide 'id' field."); - return null; - } - - Contact contact = getContact(id) == null ? new Contact(id) - : getContact(id); - contact.setFirstName(form.getFirstValue(FIRST_NAME, "N/A")); - contact.setLastName(form.getFirstValue(LAST_NAME, "N/A")); - contact.setPhone(form.getFirstValue(PHONE, "N/A")); - contact.setMail(form.getFirstValue(MAIL, "N/A")); - - Status createStatus = super.addContact(contact); - setStatus(createStatus); - - Representation rep = new StringRepresentation("Contact created", - MediaType.TEXT_PLAIN); - rep.setLocationRef(String.format("%s/%s", getRequest() - .getResourceRef().getIdentifier(), id)); - return rep; - } catch (Exception e) { - e.printStackTrace(); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /** - * Helper Method creating common form of ParameterInfo - * - * @param name - * ParameterInfo name - * @param description - * ParameterInfo description - * @return ParameterInfo formatted : required=false, parameterStyle=Query, - * defaultValue="N/A", type="String". - */ - private static ParameterInfo createCommonParameter(String name, - String description) { - return createCommonParameter(name, description, "N/A"); - } - - /** - * Helper Method creating common form of ParameterInfo - * - * @param name - * - ParameterInfo name - * @param description - * - ParameterInfo description - * @param defaultValue - * - ParameterInfo defaultValue. - * @return ParameterInfo formatted : required=false, parameterStyle=Query, - * type="String". - */ - private static ParameterInfo createCommonParameter(String name, - String description, String defaultValue) { - ParameterInfo pi = new ParameterInfo(name, false, "String", - ParameterStyle.QUERY, description); - pi.setDefaultValue(defaultValue); - return pi; - - } - - /** - * Helper method creating an OptionInfo - * - * @param value - * Option's value - * @param description - * - Option's description - * @return an OptionInfo with the specified values. - */ - private static OptionInfo createOptionInfo(String value, String description) { - OptionInfo oi = new OptionInfo(description); - oi.setValue(value); - return oi; - } -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsSubResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsSubResource.java deleted file mode 100644 index e59b890131..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ContactsSubResource.java +++ /dev/null @@ -1,69 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.json.JSONObject; -import org.restlet.data.Form; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.representation.Representation; -import org.restlet.resource.Get; - -import com.google.appengine.api.channel.ChannelServiceFactory; - -public class ContactsSubResource extends ContactBaseResource { - private static final Logger log = Logger.getLogger("ContactSubResource"); - - /** - * {@inheritDoc} - */ - @Override - public void describePost(MethodInfo mInfo) { - } - - - - /** - * Handle HTTP GET Subscribe method - * - * @param entity - must contains the client id channel. - * @return a JSON Representation of the token. - */ - @Get - public Representation subscribe(Representation entity) { - Reference ref = getRequest().getResourceRef(); - Form formQuery = ref.getQueryAsForm(); - JSONObject json = new JSONObject(); - - try { - String clientID = formQuery.getFirstValue("clientID", "").trim(); - if (clientID.isEmpty()) { - log.warning("client ID not found"); - setStatus(Status.CLIENT_ERROR_EXPECTATION_FAILED, - "Must provide a clientID field."); - return null; - } - String token = getToken(clientID); - if (token == null) { - token = ChannelServiceFactory.getChannelService().createChannel(clientID); - log.info("Create a new token [" + token + "]"); - addSubscriber(clientID, token); - } - else { - log.info("Token already existing for client " + clientID); - } - - json.append("token", token); - return new JsonRepresentation(json); - - - } catch (Exception e) { - e.printStackTrace(); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorInResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorInResource.java deleted file mode 100644 index 629132ee24..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorInResource.java +++ /dev/null @@ -1,149 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.restlet.data.MediaType; -import org.restlet.data.Status; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.wadl.WadlServerResource; -import org.restlet.representation.Representation; -import org.restlet.resource.Get; -import org.restlet.resource.Delete; -import org.restlet.resource.Put; -import org.restlet.resource.Post; - -import fr.eurecom.senml.entity.*; -import fr.eurecom.senml.persistence.JDOStorage; - - -public class SensorInResource extends WadlServerResource { - private static final Logger log = Logger.getLogger("SensorInResource"); - private static final MediaType SENML_JSON = MediaType.valueOf("application/senml+json"); - /** - * {@inheritDoc} - */ - @Override - public Representation describe() { - setName("Sensor-In Resource"); - setDescription("Acquisition sensors receiver"); - return super.describe(); - } - - @Post - @Put - public void updateSensor(Representation entity) { - JSONObject jObject = null; - String text = null; - try { - MediaType mt = entity.getMediaType(); - text = entity.getText(); - if (mt.isCompatible(MediaType.APPLICATION_JSON) || mt.isCompatible(SENML_JSON) ) { - jObject = new JSONObject(text); - } - else { - setStatus(Status.CLIENT_ERROR_NOT_ACCEPTABLE, "Content is not JSON compatible"); - log.info("This entry cause a 406 response / reason not json"); - return; - } - - String bn = jObject.has(ISensor.BASE_NAME) ? jObject.getString(ISensor.BASE_NAME) : null; - long bt = jObject.has(ISensor.BASE_TIME) ? jObject.getLong(ISensor.BASE_TIME) : Long.MIN_VALUE; - String bu = jObject.has(ISensor.BASE_UNIT) ? jObject.getString(ISensor.BASE_UNIT) : null; - - if (! jObject.has(ISensor.MEASUREMENT) || bn == null) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "Parameter Base Name[bn] or measure[e] missing."); - log.info("This entry cause a 400 response. reason bn - e missing ||" + text + "||"); - return; - } - JSONArray measures = jObject.getJSONArray(ISensor.MEASUREMENT); - -// TODO: Remove this hack: zone key is static. For first tests with IQSIM and demo. - IZone zone = JDOStorage.getInstance().getById("Aix", ZoneAdmin.class); - SensorAdmin sa = new SensorAdmin(bn, "Generic Sensor", zone); - boolean parsingOK = true; - String reasonPhrase = null; - - for (int i = 0; i < measures.length(); i++) { - - JSONObject m = measures.getJSONObject(i); - - Measure.ParamTypeValue tv = getUnitType(m); - if (tv == null) { - parsingOK = false; - reasonPhrase = "Measure miss type value [v|sv|bv]"; - break; - } - - Units unit = getUnit(m, bu); - if (unit == null) { - parsingOK = false; - reasonPhrase = "parameter unit [bu|u] invalid (missing or unknown)"; - break; - } - - String name = m.has(Measure.PARAM_NAME) ? m.getString(Measure.PARAM_NAME) : null; - if ( name == null || name.trim().isEmpty()) { - parsingOK = false; - reasonPhrase = "parameter name [n] missing or empty. Not supported"; - break; - } - - String type = m.has(Measure.PARAM_TYPE) ? m.getString(Measure.PARAM_TYPE) : null; - if ( type == null || type.trim().isEmpty()) { - parsingOK = false; - reasonPhrase = "parameter type [n] missing or empty. Not supported"; - break; - } - - - sa.addMeasure(name.trim(), unit, tv, - m.getString(tv.getSenML()), - m.has(Measure.PARAM_TIME) ? m.getLong(Measure.PARAM_TIME) : - bt == Long.MIN_VALUE ? 0 : bt, type.trim()); - } - - if (!parsingOK) { - setStatus(Status.CLIENT_ERROR_BAD_REQUEST, reasonPhrase); - log.info("This entry cause a 400 response / reason " + reasonPhrase + " ||" + text + "||"); - } - else { - setStatus(Status.SUCCESS_CREATED); - } - } - catch (Exception e) { - log.warning("Unexpected error receiving this entry : ||" + text + "||"); - log.log(Level.WARNING, "Unexpected Error", e); - - setStatus(Status.SERVER_ERROR_INTERNAL, "Unexpected Error"); - } - return; - } - - private static Measure.ParamTypeValue getUnitType(JSONObject m) { - if (m.has(Measure.PARAM_VALUE)) { - return Measure.ParamTypeValue.FLOAT; - } - else if (m.has(Measure.PARAM_BOOLEAN_VALUE)) { - return Measure.ParamTypeValue.BOOL; - } - else if (m.has(Measure.PARAM_STRING_VALUE)) { - return Measure.ParamTypeValue.STRING; - } - else if (m.has(Measure.PARAM_SUM_VALUE)) { - return Measure.ParamTypeValue.SUM; - } - return null; - } - - private static Units getUnit(JSONObject m, String bu) throws JSONException { - String u = m.has(Measure.PARAM_UNIT) ? m.getString(Measure.PARAM_UNIT) : bu != null ? bu : null; - return u == null ? null : Units.getUnit(u); - } -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorPost.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorPost.java deleted file mode 100644 index 583652f797..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/SensorPost.java +++ /dev/null @@ -1,278 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.math.BigInteger; -import java.security.MessageDigest; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.restlet.data.MediaType; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.data.Tag; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.wadl.WadlServerResource; -import org.restlet.ext.xml.DomRepresentation; -import org.restlet.representation.Representation; -import org.restlet.resource.Get; -import org.restlet.resource.Post; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import fr.eurecom.restlet.resources.common.ZonesResource.ZoneFormat; -import fr.eurecom.senml.entity.ISensor; -import fr.eurecom.senml.entity.IZone; -import fr.eurecom.senml.entity.PostValAdmin; -import fr.eurecom.senml.entity.ZoneAdmin; -import fr.eurecom.senml.persistence.JDOStorage; - -public class SensorPost extends WadlServerResource { - private static final Logger log = Logger.getLogger("SensorPost"); - - /** - * {@inheritDoc} - */ - @Override - public Representation describe() { - setName("Sensor Post"); - setDescription("Post Something, is a test!"); - return super.describe(); - } - - @Post("json") - public Representation doPost(String entity) { - String senmlValue = (String) getRequest().getAttributes().get("senml"); - //IZone zone = JDOStorage.getInstance().getById(id, ZoneAdmin.class); - JSONObject jzone = new JSONObject(); - try { - jzone.put("senml", senmlValue); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - Date n = new Date(); - PostValAdmin sa = new PostValAdmin(); - sa.addPost("testing post " + String.valueOf(n), - entity, - "NOW".equals(n) ? 0 : System.currentTimeMillis()); - - Representation out = new JsonRepresentation(jzone); - return out; - - } - - /** - * {@inheritDoc} - */ - @Override - public void describeGet(MethodInfo mInfo) { - mInfo.setIdentifier("Sensor Posting"); - mInfo.setDocumentation("To Retrieve a zone description"); - ResponseInfo response = new ResponseInfo("Current list of zones"); - response.getStatuses().add(Status.SUCCESS_OK); - - RepresentationInfo repInfo = new RepresentationInfo( - MediaType.APPLICATION_JSON); - repInfo.setDocumentation("JSON array of of the current list zone"); - response.getRepresentations().add(repInfo); - - mInfo.getResponses().add(response); - } - - /** - * Handle HTTP GET method / Json - * - * @return a JSON Zone Representation - */ - @Get("json") - public Representation toJSON() { - - final String baseURL = buildBaseURL(getRequest().getResourceRef()); - - String id = (String) getRequest().getAttributes().get("id"); - IZone zone = JDOStorage.getInstance().getById(id, ZoneAdmin.class); - JSONObject jzone = new JSONObject(); - - try { - - jzone.put(ZoneFormat.NAME.getRestAtr(), zone.getName()); - - JSONArray subZones = new JSONArray(); - - for (IZone sub : zone.getSubZones()) { - JSONObject z = new JSONObject(); - z.put(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, sub.getKey())); - z.put(ZoneFormat.NAME.getRestAtr(), sub.getName()); - z.put(ZoneFormat.HAS_SENSORS.getRestAtr(), sub.getSensors() - .size() > 0); - - z.put(ZoneFormat.HAS_SUBZONES.getRestAtr(), sub.getSubZones() - .size() > 0); - - subZones.put(z); - } - if (subZones.length() > 0) { - jzone.put(ZoneFormat.SUBZONE.getRestAtr(), subZones); - } - - JSONArray sensors = new JSONArray(); - for (ISensor sensor : zone.getSensors()) { - sensors.put(sensor.toJSONSenML()); - } - if (sensors.length() > 0) { - jzone.put(ZoneFormat.SENSORS_SENML.getRestAtr(), sensors); - } - -/* String md5 = md5(jzone.toString()); - Tag tag = md5 == null ? null : new Tag(md5, false); - if (!isModified(tag)) { - setStatus(Status.REDIRECTION_NOT_MODIFIED); - return null; - } -*/ - Representation json = new JsonRepresentation(jzone); -// json.setTag(tag); - return json; - } catch (Exception e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - log.log(Level.WARNING, "", e); - return null; - } - } - - /** - * HTTP GET method / xml accept - * - * @return a XML Zone Representation - */ - - @Get("xml") - public Representation toXML() { - long before = System.currentTimeMillis(); - String id = (String) getRequest().getAttributes().get("id"); - IZone zone = JDOStorage.getInstance().getById(id, ZoneAdmin.class); - final String baseURL = buildBaseURL(getRequest().getResourceRef()); - - try { - DomRepresentation xml = new DomRepresentation(MediaType.TEXT_XML); - Document d = xml.getDocument(); - - Element currentZone = d.createElement(ZoneFormat.ZONE.getRestAtr()); - currentZone.setAttribute(ZoneFormat.NAME.getRestAtr(), - zone.getName()); - d.appendChild(currentZone); - - for (IZone subzone : zone.getSubZones()) { - Element sub = d.createElement(ZoneFormat.SUBZONE.getRestAtr()); - sub.setAttribute(ZoneFormat.NAME.getRestAtr(), - subzone.getName()); - sub.setAttribute(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, subzone.getKey())); - sub.setAttribute(ZoneFormat.HAS_SENSORS.getRestAtr(), "" - + (subzone.getSensors().size() > 0)); - - sub.setAttribute(ZoneFormat.HAS_SUBZONES.getRestAtr(), "" - + (subzone.getSubZones().size() > 0)); - - currentZone.appendChild(sub); - - } - - for (ISensor sensor : zone.getSensors()) { - Node senml = sensor.toXMLSenML(d); - currentZone.appendChild(senml); - } - -/* String md5 = md5(xml.getText()); - Tag tag = md5 == null ? null : new Tag(md5, false); - if (!isModified(tag)) { - setStatus(Status.REDIRECTION_NOT_MODIFIED); - return null; - } -*/ -// xml.setTag(tag); - return xml; - } catch (Exception e) { - log.log(Level.WARNING, "", e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /* - * Alternative method to add an header to the response. Series
- * responseHeaders = (Series
) - * getResponse().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS); if - * (responseHeaders == null) { responseHeaders = new - * Series
(Header.class); getResponse().getAttributes().put( - * HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders); - * - * } responseHeaders.add(new Header("ETag", md5)); - */ - - /** - * Build a String baseURL = to current URI/Reference less the last path - * segment. - * - * @param reference - * the current reference object - * @return String base URI. - */ - private String buildBaseURL(Reference reference) { - Reference ref = new Reference(reference); - List segments = ref.getSegments(); - if (segments.size() > 0) { - segments.remove(segments.size() - 1); - ref.setSegments(segments); - } - return ref.getHierarchicalPart(); - } - - private String md5(String value) { - try { - MessageDigest m = MessageDigest.getInstance("MD5"); - m.reset(); - m.update(value.getBytes()); - byte[] digest = m.digest(); - BigInteger bigInt = new BigInteger(1, digest); - String hashtext = bigInt.toString(16); - // Now we need to zero pad it if you actually want the full 32 - // chars. - while (hashtext.length() < 32) { - hashtext = "0" + hashtext; - } - return hashtext; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private boolean isModified(Tag currentTag) { - boolean modified = true; - if (currentTag == null) { - return modified; - } - - if (getRequest().getConditions() != null - && getRequest().getConditions().getNoneMatch() != null) { - - for (Tag noMatch : getRequest().getConditions().getNoneMatch()) { - if (currentTag.equals(noMatch)) { - modified = false; - break; - } - } - } - return modified; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZoneResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZoneResource.java deleted file mode 100644 index c4ae2f4aaf..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZoneResource.java +++ /dev/null @@ -1,255 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.math.BigInteger; -import java.security.MessageDigest; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.restlet.data.MediaType; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.data.Tag; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.wadl.WadlServerResource; -import org.restlet.ext.xml.DomRepresentation; -import org.restlet.representation.Representation; -import org.restlet.resource.Get; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import fr.eurecom.restlet.resources.common.ZonesResource.ZoneFormat; -import fr.eurecom.senml.entity.ISensor; -import fr.eurecom.senml.entity.IZone; -import fr.eurecom.senml.entity.ZoneAdmin; -import fr.eurecom.senml.persistence.JDOStorage; - -public class ZoneResource extends WadlServerResource { -// Map etags = new HashMap(); - private static final Logger log = Logger.getLogger("ZoneResource"); - - /** - * {@inheritDoc} - */ - @Override - public Representation describe() { - setName("Zone Resource"); - setDescription("Retrieve a zone description"); - return super.describe(); - } - - /** - * {@inheritDoc} - */ - @Override - public void describeGet(MethodInfo mInfo) { - mInfo.setIdentifier("Zone description"); - mInfo.setDocumentation("To Retrieve a zone description"); - ResponseInfo response = new ResponseInfo("Current list of zones"); - response.getStatuses().add(Status.SUCCESS_OK); - - RepresentationInfo repInfo = new RepresentationInfo( - MediaType.APPLICATION_JSON); - repInfo.setDocumentation("JSON array of of the current list zone"); - response.getRepresentations().add(repInfo); - - mInfo.getResponses().add(response); - } - - /** - * Handle HTTP GET method / Json - * - * @return a JSON Zone Representation - */ - @Get("json") - public Representation toJSON() { - - final String baseURL = buildBaseURL(getRequest().getResourceRef()); - - String id = (String) getRequest().getAttributes().get("id"); - IZone zone = JDOStorage.getInstance().getById(id, ZoneAdmin.class); - JSONObject jzone = new JSONObject(); - - try { - - jzone.put(ZoneFormat.NAME.getRestAtr(), zone.getName()); - - JSONArray subZones = new JSONArray(); - - for (IZone sub : zone.getSubZones()) { - JSONObject z = new JSONObject(); - z.put(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, sub.getKey())); - z.put(ZoneFormat.NAME.getRestAtr(), sub.getName()); - z.put(ZoneFormat.ZONE_TYPE.getRestAtr(), sub.getType()); - z.put(ZoneFormat.HAS_SENSORS.getRestAtr(), sub.getSensors() - .size() > 0); - - z.put(ZoneFormat.HAS_SUBZONES.getRestAtr(), sub.getSubZones() - .size() > 0); - - subZones.put(z); - } - if (subZones.length() > 0) { - jzone.put(ZoneFormat.SUBZONE.getRestAtr(), subZones); - } - - JSONArray sensors = new JSONArray(); - for (ISensor sensor : zone.getSensors()) { - sensors.put(sensor.toJSONSenML()); - } - if (sensors.length() > 0) { - jzone.put(ZoneFormat.SENSORS_SENML.getRestAtr(), sensors); - } - -/* String md5 = md5(jzone.toString()); - Tag tag = md5 == null ? null : new Tag(md5, false); - if (!isModified(tag)) { - setStatus(Status.REDIRECTION_NOT_MODIFIED); - return null; - } -*/ - Representation json = new JsonRepresentation(jzone); -// json.setTag(tag); - return json; - } catch (Exception e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - log.log(Level.WARNING, "", e); - return null; - } - } - - /** - * HTTP GET method / xml accept - * - * @return a XML Zone Representation - */ - - @Get("xml") - public Representation toXML() { - long before = System.currentTimeMillis(); - String id = (String) getRequest().getAttributes().get("id"); - IZone zone = JDOStorage.getInstance().getById(id, ZoneAdmin.class); - final String baseURL = buildBaseURL(getRequest().getResourceRef()); - - try { - DomRepresentation xml = new DomRepresentation(MediaType.TEXT_XML); - Document d = xml.getDocument(); - - Element currentZone = d.createElement(ZoneFormat.ZONE.getRestAtr()); - currentZone.setAttribute(ZoneFormat.NAME.getRestAtr(), - zone.getName()); - currentZone.setAttribute(ZoneFormat.ZONE_TYPE.getRestAtr(), zone.getType()); - d.appendChild(currentZone); - - for (IZone subzone : zone.getSubZones()) { - Element sub = d.createElement(ZoneFormat.SUBZONE.getRestAtr()); - sub.setAttribute(ZoneFormat.NAME.getRestAtr(), - subzone.getName()); - sub.setAttribute(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, subzone.getKey())); - sub.setAttribute(ZoneFormat.HAS_SENSORS.getRestAtr(), "" - + (subzone.getSensors().size() > 0)); - - sub.setAttribute(ZoneFormat.HAS_SUBZONES.getRestAtr(), "" - + (subzone.getSubZones().size() > 0)); - - currentZone.appendChild(sub); - - } - - for (ISensor sensor : zone.getSensors()) { - Node senml = sensor.toXMLSenML(d); - currentZone.appendChild(senml); - } - -/* String md5 = md5(xml.getText()); - Tag tag = md5 == null ? null : new Tag(md5, false); - if (!isModified(tag)) { - setStatus(Status.REDIRECTION_NOT_MODIFIED); - return null; - } -*/ -// xml.setTag(tag); - return xml; - } catch (Exception e) { - log.log(Level.WARNING, "", e); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - /* - * Alternative method to add an header to the response. Series
- * responseHeaders = (Series
) - * getResponse().getAttributes().get(HeaderConstants.ATTRIBUTE_HEADERS); if - * (responseHeaders == null) { responseHeaders = new - * Series
(Header.class); getResponse().getAttributes().put( - * HeaderConstants.ATTRIBUTE_HEADERS, responseHeaders); - * - * } responseHeaders.add(new Header("ETag", md5)); - */ - - /** - * Build a String baseURL = to current URI/Reference less the last path - * segment. - * - * @param reference - * the current reference object - * @return String base URI. - */ - private String buildBaseURL(Reference reference) { - Reference ref = new Reference(reference); - List segments = ref.getSegments(); - if (segments.size() > 0) { - segments.remove(segments.size() - 1); - ref.setSegments(segments); - } - return ref.getHierarchicalPart(); - } - - private String md5(String value) { - try { - MessageDigest m = MessageDigest.getInstance("MD5"); - m.reset(); - m.update(value.getBytes()); - byte[] digest = m.digest(); - BigInteger bigInt = new BigInteger(1, digest); - String hashtext = bigInt.toString(16); - // Now we need to zero pad it if you actually want the full 32 - // chars. - while (hashtext.length() < 32) { - hashtext = "0" + hashtext; - } - return hashtext; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - private boolean isModified(Tag currentTag) { - boolean modified = true; - if (currentTag == null) { - return modified; - } - - if (getRequest().getConditions() != null - && getRequest().getConditions().getNoneMatch() != null) { - - for (Tag noMatch : getRequest().getConditions().getNoneMatch()) { - if (currentTag.equals(noMatch)) { - modified = false; - break; - } - } - } - return modified; - } -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZonesResource.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZonesResource.java deleted file mode 100644 index 252e362a12..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/common/ZonesResource.java +++ /dev/null @@ -1,200 +0,0 @@ -package fr.eurecom.restlet.resources.common; - -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.mortbay.log.Log; -import org.restlet.Context; -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.data.MediaType; -import org.restlet.data.Method; -import org.restlet.data.Reference; -import org.restlet.data.Status; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.ext.wadl.MethodInfo; -import org.restlet.ext.wadl.RepresentationInfo; -import org.restlet.ext.wadl.ResponseInfo; -import org.restlet.ext.wadl.WadlServerResource; -import org.restlet.ext.xml.DomRepresentation; -import org.restlet.representation.Representation; -import org.restlet.representation.StringRepresentation; -import org.restlet.resource.Get; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import fr.eurecom.senml.entity.IZone; -import fr.eurecom.senml.entity.ZoneAdmin; -import fr.eurecom.senml.persistence.JDOStorage; - -public class ZonesResource extends WadlServerResource { - - public static enum ZoneFormat { - ID("id", "zone identifier"), NAME("name", "zone name"), SUBZONE( - "subzone", "subzone description"), - // SENSORS("sensors","sensors lsit uri"), - PARENT_ZONE("parent", "name zone parent"), ZONE("zone", "Zone"), URI( - "uri", "URI"), HAS_SUBZONES("has_subzones", "Has subzones"), HAS_SENSORS( - "has_sensors", "Has_sensors"), SENSORS_SENML("senml", - "sensors over senml"),ZONE_TYPE("type", "type of the zone"); - - private final String restAttr; - private final String desc; - - ZoneFormat(String restAttr, String desc) { - this.restAttr = restAttr; - this.desc = desc; - } - - public String getRestAtr() { - return restAttr; - } - - public String getDescription() { - return desc; - } - }; - - /** - * {@inheritDoc} - */ - @Override - public Representation describe() { - setName("Zones Resource"); - setDescription("Retrieve zones list"); - return super.describe(); - } - - /** - * {@inheritDoc} - */ - @Override - public void describeGet(MethodInfo mInfo) { - mInfo.setIdentifier("Zones List"); - Log.info("oooooo"); - mInfo.setDocumentation("To Retrieve a list of zones"); - ResponseInfo response = new ResponseInfo("Current list of zones"); - response.getStatuses().add(Status.SUCCESS_OK); - - RepresentationInfo repInfo = new RepresentationInfo( - MediaType.APPLICATION_JSON); - repInfo.setDocumentation("JSON array of of the current list zone"); - response.getRepresentations().add(repInfo); - - mInfo.getResponses().add(response); - } - - // HACK: Version Restlet-gae 2.1-rc5. - // There is an error routing the GET request when - // the Request Header Content-Type = application/x-www-form-urlencoded and - // Header Accept = "application/json" and - // URI have a query : http://localhost:8888/contacts?sort=firstname. - // In this case the router ignores the Accept header and route the request - // to @Get("xml") systematically because the query is badly interpreted. - // To workaround this problem, at the init we reformat the Entity with an - // empty Representation. - - @Override - public void init(Context context, Request request, Response response) { - // System.out.println("init" + request + " " + response); - // System.out.println("Content-Type: " + - // request.getEntity().getMediaType()); - if (request.getMethod().compareTo(Method.GET) == 0) { - Representation entity = request.getEntity(); - System.out.println("Entity " + entity + " Content-Type: " - + request.getEntity().getMediaType()); - request.setEntity(new StringRepresentation("")); - } - super.init(context, request, response); - } - - /** - * Handle HTTP GET method / Json - * - * @return a JSON list of root zones by default. - */ - @Get("json") - public Representation toJSON() { - // System.out.println("Request Original Ref " + getOriginalRef()); - // System.out.println("Request Entity " + getRequest().getEntityAsText() - // + - // " entity mediaType " + getRequest().getEntity().getMediaType()); - - try { - List zones = JDOStorage.getInstance() - .getAll(ZoneAdmin.class); - JSONArray jzones = new JSONArray(); - Reference ref = getRequest().getResourceRef(); - final String baseURL = ref.getHierarchicalPart(); - - for (IZone zone : zones) { - if (zone.getParentZone() == null) { - - JSONObject jzone = new JSONObject(); - jzone.put(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, zone.getKey())); - - jzone.put(ZoneFormat.NAME.getRestAtr(), zone.getName()); - jzone.put(ZoneFormat.ZONE_TYPE.getRestAtr(), zone.getType()); - - jzone.put(ZoneFormat.HAS_SENSORS.getRestAtr(), zone - .getSensors().size() > 0); - - jzone.put(ZoneFormat.HAS_SUBZONES.getRestAtr(), zone - .getSubZones().size() > 0); - - jzones.put(jzone); - } - } - - JSONObject zoneHead = new JSONObject(); - zoneHead.put(ZoneFormat.SUBZONE.getRestAtr(), jzones); - return new JsonRepresentation(zoneHead); - } catch (Exception e) { - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } - - @Get("xml") - public Representation toXML() { - try { - List zones = JDOStorage.getInstance() - .getAll(ZoneAdmin.class); - Reference ref = getRequest().getResourceRef(); - final String baseURL = ref.getHierarchicalPart(); - - DomRepresentation xml = new DomRepresentation(MediaType.TEXT_XML); - Document d = xml.getDocument(); - Element root = d.createElement(ZoneFormat.ZONE.getRestAtr()); - d.appendChild(root); - - for (IZone zone : zones) { - if (zone.getParentZone() == null) { - Element subzone = d.createElement(ZoneFormat.SUBZONE - .getRestAtr()); - - subzone.setAttribute(ZoneFormat.NAME.getRestAtr(), - zone.getName()); - - subzone.setAttribute(ZoneFormat.URI.getRestAtr(), - String.format("%s/%s", baseURL, zone.getKey())); - - subzone.setAttribute(ZoneFormat.HAS_SENSORS.getRestAtr(), - "" + (zone.getSensors().size() > 0)); - - subzone.setAttribute(ZoneFormat.HAS_SUBZONES.getRestAtr(), - "" + (zone.getSubZones().size() > 0)); - root.appendChild(subzone); - } - } - - return xml; - } catch (Exception e) { - e.printStackTrace(); - setStatus(Status.SERVER_ERROR_INTERNAL); - return null; - } - } -} \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/Dispatcher.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/Dispatcher.java deleted file mode 100644 index 3e2dd2675e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/Dispatcher.java +++ /dev/null @@ -1,43 +0,0 @@ -package fr.eurecom.restlet.resources.gae; - -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.Restlet; -import org.restlet.ext.wadl.ApplicationInfo; -import org.restlet.ext.wadl.DocumentationInfo; -import org.restlet.ext.wadl.WadlApplication; -import org.restlet.resource.Directory; -import org.restlet.routing.Router; - -import fr.eurecom.restlet.resources.common.ContactResource; -import fr.eurecom.restlet.resources.common.ContactsResource; -import fr.eurecom.restlet.resources.common.ContactsSubResource; - -public class Dispatcher extends WadlApplication { - - @Override - public Restlet createInboundRoot() { - Router router = new Router(getContext()); - router.attachDefault(new Directory(getContext(), "war:///")); -// web xml mapping = /* -// router.attach("/contacts", ContactsResource.class); -// router.attach("/contacts/{id}", ContactResource.class); -// web xml mapping = /contacts/* - router.attach("", ContactsResource.class); - router.attach("/subscribe", ContactsSubResource.class); - router.attach("/{id}", ContactResource.class); - return router; - } - - @Override - public ApplicationInfo getApplicationInfo(Request request, Response response) { - ApplicationInfo info = super.getApplicationInfo(request, response); - - DocumentationInfo docInfo = new DocumentationInfo( - "emulator-box-services application documentation"); - docInfo.setTitle("Emulator Box Services application infos."); - info.setDocumentation(docInfo); - - return info; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/DispatcherSenml.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/DispatcherSenml.java deleted file mode 100644 index d103d44d5a..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/DispatcherSenml.java +++ /dev/null @@ -1,48 +0,0 @@ -package fr.eurecom.restlet.resources.gae; - -import java.util.logging.Logger; - -import org.restlet.Request; -import org.restlet.Response; -import org.restlet.Restlet; -import org.restlet.ext.wadl.ApplicationInfo; -import org.restlet.ext.wadl.DocumentationInfo; -import org.restlet.ext.wadl.WadlApplication; -import org.restlet.resource.Directory; -import org.restlet.routing.Router; - -import fr.eurecom.restlet.resources.common.SensorPost; -import fr.eurecom.restlet.resources.common.ZonesResource; -import fr.eurecom.restlet.resources.common.ZoneResource; -import fr.eurecom.restlet.resources.common.SensorInResource; - - -public class DispatcherSenml extends WadlApplication { - private static final Logger log = Logger.getLogger("DispatcherSenml"); - - @Override - public Restlet createInboundRoot() { - log.info("SenML dispatcher attaches resources"); - Router router = new Router(getContext()); - router.attachDefault(new Directory(getContext(), "war:///")); -// web xml mapping = /* - - router.attach("/zones", ZonesResource.class); - router.attach("/zones/{id}", ZoneResource.class); - router.attach("/sensorsin", SensorInResource.class); - router.attach("/posttest", SensorPost.class); - return router; - } - - @Override - public ApplicationInfo getApplicationInfo(Request request, Response response) { - ApplicationInfo info = super.getApplicationInfo(request, response); - - DocumentationInfo docInfo = new DocumentationInfo( - "emulator-box-services application documentation"); - docInfo.setTitle("Emulator Box Services application infos."); - info.setDocumentation(docInfo); - - return info; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/ResourcesServletGAE.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/ResourcesServletGAE.java deleted file mode 100644 index 5d46ceb2dc..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/gae/ResourcesServletGAE.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.eurecom.restlet.resources.gae; - -import java.io.IOException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** - * This class serves for test only. Can be deleted. - * @author ouest - * - */ - -@SuppressWarnings("serial") -public class ResourcesServletGAE extends HttpServlet { - - @Override - public void doGet(HttpServletRequest req, HttpServletResponse resp) - throws IOException { - resp.setContentType("text/plain"); - resp.getWriter().println("Hello, world"); - } - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/PMF.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/PMF.java deleted file mode 100644 index 77d3e5f741..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/PMF.java +++ /dev/null @@ -1,18 +0,0 @@ -package fr.eurecom.restlet.resources.persistence; - -import javax.jdo.JDOHelper; -import javax.jdo.PersistenceManagerFactory; - -public final class PMF { - private static final PersistenceManagerFactory pmfInstance = JDOHelper - .getPersistenceManagerFactory("transactions-optional"); - - private PMF() { - } - - public static PersistenceManagerFactory get() { - return pmfInstance; - } -} - -// PersistenceManager pm = PMF.get().getPersistenceManager(); diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/Storage.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/Storage.java deleted file mode 100644 index c0f0983d9c..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/restlet/resources/persistence/Storage.java +++ /dev/null @@ -1,252 +0,0 @@ -package fr.eurecom.restlet.resources.persistence; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -import fr.eurecom.restlet.resources.common.Contact; -import fr.eurecom.restlet.resources.common.ContactBaseResource.MEMBERS; - -/** - * This class is a naive implementation of contact's datastore, it should be - * replaced by a NOSQL JDO storage. - */ -// TODO: Replace this class by NOSQL JDO implementation. -public class Storage { - - /** - * Array of contacts. Restricted to 50 contacts. - */ - private final Contact[] backend = new Contact[50]; - - /** - * Storage instance. - */ - private static Storage instance = null; - - private static final String TEMPLATE_SORT = "%s-%s"; - - /** - * Constructs a storage. Initialize a bunch of contacts. - */ - private Storage() { - backend[0] = new Contact(0, "Bonnie", "Parker", "bonnie@gangsters.org", - "+1-555-329-4589"); - backend[1] = new Contact(1, "Clyde", "Barrow", "clyde@gangsters.org", - "+1-555-329-4589"); - backend[2] = new Contact(2, "John", "Dillinger", "john@gangsters.org", - "+1-555-355-3232"); - backend[3] = new Contact(3, "Herman", "Lamm", "herman@gangsters.org", - "+1-555-258-2365"); - backend[4] = new Contact(4, "Willie", "Sutton", "will@gangsters.org", - "+1-555-258-2365"); - - for (int i = 5; i < 50; i++) { - backend[i] = null; - } - } - - /** - * Retrieve the singleton storage. - * - * @return a Storage instance. - */ - public static Storage getInstance() { - if (instance == null) { - instance = new Storage(); - } - return instance; - } - - /** - * Retrieve a list of sorted contacts, starting with the given offset. - * - * @param sort - * - Sort parameter. - * @param minLimit - * - reserved for a future usage - * @param maxLimit - * - reserved for a future usage - * @return a sorted list of the contacts. - */ - @SuppressWarnings("unchecked") - public List getContacts(MEMBERS sort, int minLimit, int maxLimit) { - switch (sort) { - case ID: - return getSortedById(); - case FIRSTNAME: - return getSortedByFirstName(); - case LASTNAME: - return getSortedByLastName(); - case PHONE: - return getSortedByPhone(); - case MAIL: - return getSortedByEmail(); - } - - return Collections.EMPTY_LIST; - } - - /** - * Save a contact, the Contact's id must be comprise between 0 and 49. - * - * @param contact - * to save. - * @return true if correctly saved, false otherwise. - */ - public boolean saveContact(Contact contact) { - if (checkIndex(contact.getId())) { - backend[contact.getId()] = contact; - return true; - } - return false; - } - - /** - * Delete a contact. Same as {@link #removeContact(int)} - * {@code - * removeContact(conctact.getId(); - * } - * - * @param contact - * to delete. - * @return true if deleted, false otherwise. - */ - public boolean removeContact(Contact contact) { - return removeContact(contact.getId()); - } - - /** - * Delete a contact - * - * @param identifier - * - Contact's identifier - * @return true if deleted, false otherwise - * @see Storage.removeContact(Contact) - */ - public boolean removeContact(int identifier) { - if (checkIndex(identifier)) { - backend[identifier] = null; - return true; - } - return false; - } - - /** - * Retrieve a contact from an identifier. - * - * @param identifier - * - Contact's identifier - * @return Contact. - */ - public Contact getContact(int identifier) { - if (checkIndex(identifier)) { - return backend[identifier]; - } - return null; - } - - private boolean checkIndex(int index) { - return index > -1 && index < 50; - } - - /** - * Sort contacts by email field. - * - * @return a sorted list of contacts. - */ - private List getSortedByEmail() { - Map sorted = new TreeMap( - String.CASE_INSENSITIVE_ORDER); - for (int i = 0; i < 50; i++) { - if (backend[i] != null) { - sorted.put(unicKey(backend[i].getMail(), i), backend[i]); - } - } - return new ArrayList(sorted.values()); - } - - /** - * Sort contacts by phone number - * - * @return a sorted list of contacts. - */ - private List getSortedByPhone() { - Map sorted = new TreeMap( - String.CASE_INSENSITIVE_ORDER); - for (int i = 0; i < 50; i++) { - if (backend[i] != null) { - sorted.put(unicKey(toNumeric(backend[i].getPhone()), i), - backend[i]); - } - } - return new ArrayList(sorted.values()); - } - - /** - * Sort contacts by last name - * - * @return a sorted list of contacts. - */ - private List getSortedByLastName() { - Map sorted = new TreeMap( - String.CASE_INSENSITIVE_ORDER); - for (int i = 0; i < 50; i++) { - if (backend[i] != null) { - sorted.put(unicKey(backend[i].getLastName(), i), backend[i]); - } - } - return new ArrayList(sorted.values()); - } - - /** - * Sort contacts by first name - * - * @return a sorted list of contacts. - */ - private List getSortedByFirstName() { - Map sorted = new TreeMap( - String.CASE_INSENSITIVE_ORDER); - for (int i = 0; i < 50; i++) { - if (backend[i] != null) { - sorted.put(unicKey(backend[i].getFirstName(), i), backend[i]); - } - } - return new ArrayList(sorted.values()); - } - - /** - * Sort contacts by identifier. - * - * @return a sorted list of contacts. - */ - private List getSortedById() { - return Arrays.asList(backend); - } - - private static String toNumeric(String phone) { - char[] chars = phone.toCharArray(); - StringBuilder builder = new StringBuilder(); - for (char c : chars) { - if (Character.isDigit(c)) { - builder.append(c); - } - } - return builder.toString(); - } - - /** - * Format a unic key (necessary when at least 2 contacts have a same - * property value like firstname/lastname..) - * - * @param key - * @param id - * @return - */ - private static String unicKey(String key, int id) { - return String.format(TEMPLATE_SORT, key, id); - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ContactTest.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ContactTest.java deleted file mode 100644 index a3d5a2c7ca..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ContactTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package fr.eurecom.senml.entity; - -import javax.jdo.annotations.IdGeneratorStrategy; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import com.google.appengine.api.datastore.Key; - -@PersistenceCapable -public class ContactTest { - - @PrimaryKey - @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) - private Key key; - - @Persistent - private String firstName; - - @Persistent - private String lastName; - - @Persistent - private String email; - - public ContactTest(String firstName, String lastName, String email) { - this.firstName = firstName; - this.lastName = lastName; - this.email = email; - } - - public String getirstName() {return firstName;} - public String getLastName() {return lastName;} - public String getEmail() {return email;} - public Key getKey() {return key;} -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IPostVal.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IPostVal.java deleted file mode 100644 index 1e759d7af5..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IPostVal.java +++ /dev/null @@ -1,9 +0,0 @@ -package fr.eurecom.senml.entity; - - -public interface IPostVal { - public final static String BASE_NAME = "bn"; - public final static String STATUS = "status"; - - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensor.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensor.java deleted file mode 100644 index 6bb154b939..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensor.java +++ /dev/null @@ -1,37 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.List; - -import org.json.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -public interface ISensor { - public final static String BASE_NAME = "bn"; - public final static String BASE_TIME = "bt"; - public final static String BASE_UNIT = "bu"; - public final static String VERSION = "ver"; - public final static String MEASUREMENT = "e"; - - public String getUUID(); - - public IZone getZone(); - - public String getTitle(); - - public List getMeasures(); - -// public List getMeasuresKey(); - -// public List getMeasuresPrint(); - - public JSONObject toJSONSenML(); - - public Document toXMLSenML(); - - public Node toXMLSenML(Document rootDocument); - - public String getBaseUnit(); - - public String zoneType(); -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensorAdmin.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensorAdmin.java deleted file mode 100644 index 69b14b2f07..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ISensorAdmin.java +++ /dev/null @@ -1,34 +0,0 @@ -package fr.eurecom.senml.entity; - -import fr.eurecom.senml.entity.Measure.ParamTypeValue; - -public interface ISensorAdmin extends ISensor { - - public boolean linkZone(IZone zone); - - public boolean linkZone(String zoneKey); - - public void unlinkZone(); - - public Measure addMeasure(String measureName, - Units measureUnit, - ParamTypeValue measureTypeValue, - String measureValue, long timeMeasure, String type); - - public void deleteMeasure(String measureKey); - - public void deleteMeasure(Measure measure); - - public void setTitle(String title); - -// void tag(Tag tag); - -// void untag(Tag tag); - - public void destroy(); - - public Measure addMeasure(String measureName, Units measureUnit, - ParamTypeValue measureTypeValue, String measureValue, - long timeMeasure, String type, String sum); - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZone.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZone.java deleted file mode 100644 index 08e3465ab0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZone.java +++ /dev/null @@ -1,23 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.List; - -public interface IZone extends Comparable { - -// public boolean hasSensors(); - -// public boolean hasSubZones(); - - public List getSubZones(); - - public List getSensors(); - - public String getName(); - - public String getKey(); - - public IZone getParentZone(); - - String getType(); - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZoneAdmin.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZoneAdmin.java deleted file mode 100644 index 15e665ff0c..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/IZoneAdmin.java +++ /dev/null @@ -1,17 +0,0 @@ -package fr.eurecom.senml.entity; - - -public interface IZoneAdmin extends IZone { - - public boolean linkParentZone(String parentZoneKey); - - public boolean linkParentZone(IZone parentZone); - - public void unlinkParentZone(); - -// public boolean addSensor(String sensorKey); - -// public boolean removeSensor(String sensorKey); - - public void destroy(); -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Measure.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Measure.java deleted file mode 100644 index 5d707a1ff0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Measure.java +++ /dev/null @@ -1,301 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.sql.Date; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.UUID; -import java.util.logging.Logger; -import java.util.Map; - -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import org.json.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorage; - -/** - * Immutable object. Represents the SenML Measurement entry. - * - * @author dalmassi - * - */ - -@PersistenceCapable(detachable = "true") -public class Measure { - - public enum ParamTypeValue { - BOOL("bv"), FLOAT("v"), STRING("sv"), SUM("s"); - - private String encoded; - private final static Map mTypeValue = new HashMap(); - - ParamTypeValue(String encoded) { - this.encoded = encoded; - } - - public String getSenML() { - return encoded; - } - - public static ParamTypeValue getParamTypeValue(String senmlEncoded) { - if (mTypeValue == null) { - initMapValue(); - } - return mTypeValue.get(senmlEncoded); - } - - private static synchronized void initMapValue() { - if (mTypeValue.size() > 0) { - return; - } - for (ParamTypeValue v : values()) { - mTypeValue.put(v.encoded, v); - } - } - }; - - @NotPersistent - private static final DateFormat df = new SimpleDateFormat( - "yyyy.MM.dd G 'at' HH:mm:ss z"); - - @NotPersistent - private static final Logger log = Logger - .getLogger("sensors.entity.Measure"); - @NotPersistent - public static final String PARAM_UNIT = "u"; - @NotPersistent - public static final String PARAM_NAME = "n"; - @NotPersistent - public static final String PARAM_TIME = "t"; - @NotPersistent - public static final String PARAM_VALUE = "v"; - @NotPersistent - public static final String PARAM_STRING_VALUE = "sv"; - @NotPersistent - public static final String PARAM_BOOLEAN_VALUE = "bv"; - @NotPersistent - public static final String PARAM_SUM_VALUE = "s"; - @NotPersistent - public static final String PARAM_UPDATE_TIME = "ut"; - @NotPersistent - public static final String PARAM_TYPE = "type"; - - @PrimaryKey - @Persistent - Key key; - - @Persistent - private String name; - - @Persistent - private String unitCS; - - @Persistent - private String unitPrint; - - @Persistent - private String unitKindOfQty; - - @Persistent - private String value; - - @Persistent - private String paramTypeValueEncoded; - - private long time; - - @Persistent - private String sensorKey; - - private String baseunitCS; - - private String baseunitPrint; - - private String baseunitKindOfQty; - - private String type; - - private String sum; - - public Measure(String sensorKey, String name, Units unit, - ParamTypeValue typeValue, String value, long time, String type) { - this.sensorKey = sensorKey; - - this.name = name == null || name.isEmpty() ? generateName() : name; - this.unitCS = unit == null ? null : unit.getCS(); - this.unitPrint = unit == null ? null : unit.getPrint(); - this.unitKindOfQty = unit == null ? null : unit.getKindofQty(); - this.paramTypeValueEncoded = typeValue.getSenML(); - this.value = value; - this.time = time; - this.key = KeyFactory.createKey(Measure.class.getSimpleName(), - sensorKey + name); - this.type = type; - } - - public Measure(String sensorKey, String name, Units unit, - ParamTypeValue typeValue, String value, long time, String type, String sum) { - this.sensorKey = sensorKey; - - this.name = name == null || name.isEmpty() ? generateName() : name; - this.unitCS = unit == null ? null : unit.getCS(); - this.unitPrint = unit == null ? null : unit.getPrint(); - this.unitKindOfQty = unit == null ? null : unit.getKindofQty(); - this.paramTypeValueEncoded = typeValue.getSenML(); - this.value = value; - this.time = time; - this.sum = sum; - this.key = KeyFactory.createKey(Measure.class.getSimpleName(), - sensorKey + name); - this.type = type; - - } - - public void destroy() { - JDOStorage.getInstance().delete(this); - } - - public String getKey() { - return key == null ? null : KeyFactory.keyToString(key); - } - - public String getType() { - return type; - } - - public JSONObject toJSONSenML() { - try { - JSONObject entrySenML = new JSONObject(); - if (name != null) { - entrySenML.put(PARAM_NAME, name); - } - - if (sum != null) { - entrySenML.put(PARAM_SUM_VALUE, sum); - } - - entrySenML.put(PARAM_TYPE, type); - - entrySenML.put(PARAM_TIME, time); - if (this.unitPrint != null) { - entrySenML.put(PARAM_UNIT, unitCS); - } - - if (paramTypeValueEncoded != null) { - entrySenML.put(paramTypeValueEncoded, value); - } - return entrySenML; - } catch (Exception e) { - e.printStackTrace(); - log.warning("Error Encoding a measure"); - return null; - } - } - - public Node toXMLSenML(Document d) { - Element measure = d.createElement("e"); - measure.setAttribute(PARAM_NAME, name); - measure.setAttribute(PARAM_TYPE, type); - measure.setAttribute(PARAM_TIME, "" + time); - if (this.unitPrint != null) { - measure.setAttribute(PARAM_UNIT, unitCS); - } - - if (this.sum != null) { - measure.setAttribute(PARAM_SUM_VALUE, sum); - } - - if (paramTypeValueEncoded != null) { - measure.setAttribute(paramTypeValueEncoded, value); - } - return measure; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - if (this.unitCS != null) { - builder.append("key[" + getKey()).append("] name[" + name) - .append("] unitCS[" + unitCS) - .append("] unitPrint[" + unitPrint) - .append(this.sum == null ? "" : "] sum[" + sum) - .append("] unitKindOfQty[" + unitKindOfQty) - .append("] paramTypeEncoded[" + paramTypeValueEncoded) - .append("] value[" + value).append("] time[" + time) - .append("] sensorKey[" + sensorKey).append("]"); - } else { - // Check if we have to initialize the base unit - baseUnitInit(); - builder.append("key[" + getKey()) - .append("] name[" + name) - .append("] unitCS (base unit) [" + baseunitCS) - .append("] unitPrint (base unit) [" + baseunitPrint) - .append(this.sum == null ? "" : "] sum[" + sum) - .append("] unitKindOfQty (base unit) [" + baseunitKindOfQty) - .append("] paramTypeEncoded[" + paramTypeValueEncoded) - .append("] value[" + value).append("] time[" + time) - .append("] sensorKey[" + sensorKey).append("]"); - } - return builder.toString(); - } - - public String toPrettyString() { - StringBuilder builder = new StringBuilder(); - if (this.unitCS != null) { - builder.append(name).append(": ").append("(kind: ") - .append(unitKindOfQty).append(") ").append(value) - .append(this.sum == null ? "" : " sum: " + sum) - .append(" ").append(unitPrint).append(" @ ") - .append(formatDate(time)); - } else { - // Check if we have to initialize the base unit - baseUnitInit(); - builder.append(name).append(": ").append("(kind (baseunit): ") - .append(baseunitKindOfQty).append(") ").append(value) - .append(" ").append(baseunitPrint).append("(baseunit) @ ") - .append(formatDate(time)); - } - return builder.toString(); - } - - private void baseUnitInit() { - System.out.println("unit is null, parent sensor is " + sensorKey); - // Retrieve info about base unit from the parent sensor - Sensor parent = JDOStorage.getInstance().getById(sensorKey, - Sensor.class); - System.out.println("sensor is " + parent.getTitle()); - String bu = parent.getBaseUnit(); - System.out.println("sensor bu is " + bu); - Units baseUnits = Units.getUnit(bu); - this.baseunitCS = baseUnits.getCS(); - this.baseunitKindOfQty = baseUnits.getKindofQty(); - this.baseunitPrint = baseUnits.getPrint(); - System.out.println("base unit is: " + this.baseunitCS); - } - - private String formatDate(long ms) { - if (ms == 0) - return "now"; - if (ms < 0) - return ("now - " + ms); - - return df.format(new Date(ms)); - } - - public String getSensorKey() { - return sensorKey; - } - - private String generateName() { - return UUID.randomUUID().toString(); - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValAdmin.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValAdmin.java deleted file mode 100644 index f11c4e9f9c..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValAdmin.java +++ /dev/null @@ -1,21 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.UUID; - -import javax.jdo.annotations.Persistent; - -import fr.eurecom.senml.persistence.JDOStorage; - -public class PostValAdmin implements IPostVal { - - @Persistent - boolean active = true; - - public PostValType addPost(String name, String val, long timeMeasure) { - PostValType m = new PostValType(UUID.randomUUID().toString(), name, val, timeMeasure); - JDOStorage.getInstance().write(m); - //JDOStorage.getInstance().deleteAll(PostValType.class); - return m; - //return null; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValType.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValType.java deleted file mode 100644 index 65a7ff828f..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/PostValType.java +++ /dev/null @@ -1,173 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.sql.Date; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.UUID; -import java.util.logging.Logger; -import java.util.Map; - -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import org.json.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorage; - -/** - * Immutable object. Represents the SenML Measurement entry. - * - * - */ - -@PersistenceCapable(detachable="true") -public class PostValType { - - public enum ParamTypeValue { - STR("sv"); - - private String encoded; - private final static Map mTypeValue = new HashMap(); - - ParamTypeValue(String encoded) { - this.encoded = encoded; - } - - public String getSenML() { - return encoded; - } - - public static ParamTypeValue getParamTypeValue(String senmlEncoded) { - if (mTypeValue == null) { - initMapValue(); - } - return mTypeValue.get(senmlEncoded); - } - - private static synchronized void initMapValue() { - if (mTypeValue.size() > 0) { - return; - } - for (ParamTypeValue v : values()) { - mTypeValue.put(v.encoded, v); - } - } - }; - - @NotPersistent - private static final DateFormat df = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z"); - - @NotPersistent - private static final Logger log = Logger - .getLogger("sensors.entity.PostValType"); - - @NotPersistent - public static final String PARAM_STRING_VALUE = "sv"; - - @NotPersistent - public static final String PARAM_NAME = "n"; - - @PrimaryKey - @Persistent - Key key; - - @Persistent - private String name; - - @Persistent - private String value; - - @Persistent - private long time; - - public String getName() { - return name; - } - - public String getValue() { - return String.valueOf(value); - } - - public String getTime() { - return formatDate(time); - } - - public PostValType(String sensorKey, String name, - String val, long time) { - this.name = name == null || name.isEmpty() ? generateName() : name; - this.value = val; - this.time = time; - this.key = KeyFactory.createKey(PostValType.class.getSimpleName(), sensorKey + name +"" + time); - } - - public void destroy() { - JDOStorage.getInstance().delete(this); - } - - public String getKey() { - return key == null ? null : KeyFactory.keyToString(key); - } - - public JSONObject toJSONSenML() { - try { - JSONObject entrySenML = new JSONObject(); - if (name != null) { - entrySenML.put(PARAM_NAME, name); - } - entrySenML.put(PARAM_STRING_VALUE, value); - return entrySenML; - } catch (Exception e) { - e.printStackTrace(); - log.warning("Error Encoding a measure"); - return null; - } - } - - public Node toXMLSenML(Document d) { - Element measure = d.createElement("e"); - measure.setAttribute(PARAM_NAME, name); - measure.setAttribute(PARAM_STRING_VALUE, String.valueOf(value)); - return measure; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("key[" + getKey()) - .append("] name[" + name) - .append("] value[" + value) - .append("] time[" + formatDate(time)) - .append("]"); - return builder.toString(); - } - - public String toPrettyString() { - StringBuilder builder = new StringBuilder(); - builder.append(name) - .append(": ") - .append(") ") - .append(value) - .append(" @ ") - .append(formatDate(time)); - return builder.toString(); - } - - private String formatDate(long ms) { - if (ms == 0) return "now"; - if (ms < 0) return ("now - " + ms); - - return df.format(new Date(ms)); - } - - private String generateName() { - return UUID.randomUUID().toString(); - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/RegisteredDeviceType.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/RegisteredDeviceType.java deleted file mode 100644 index 5b6db90132..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/RegisteredDeviceType.java +++ /dev/null @@ -1,188 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.sql.Date; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.HashMap; -import java.util.UUID; -import java.util.logging.Logger; -import java.util.Map; - -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import org.json.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorage; - -/** - * Immutable object. Represents the registered device. - */ - -@PersistenceCapable(detachable="true") -public class RegisteredDeviceType { - - public enum ParamTypeValue { - STR("sv"); - - private String encoded; - private final static Map mTypeValue = new HashMap(); - - ParamTypeValue(String encoded) { - this.encoded = encoded; - } - - public String getSenML() { - return encoded; - } - - public static ParamTypeValue getParamTypeValue(String senmlEncoded) { - if (mTypeValue == null) { - initMapValue(); - } - return mTypeValue.get(senmlEncoded); - } - - private static synchronized void initMapValue() { - if (mTypeValue.size() > 0) { - return; - } - for (ParamTypeValue v : values()) { - mTypeValue.put(v.encoded, v); - } - } - }; - - @NotPersistent - private static final DateFormat df = new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z"); - - @NotPersistent - private static final Logger log = Logger - .getLogger("sensors.entity.RegisteredDeviceType"); - - @NotPersistent - public static final String PARAM_STRING_VALUE = "sv"; - - @NotPersistent - public static final String PARAM_NAME = "n"; - - @PrimaryKey - @Persistent - Key key; - - @Persistent - private String deviceType; - - @Persistent - private String registrationKey; - - @Persistent - private long time; - - private boolean isadmin = false; - - public String getDeviceType() { - return deviceType; - } - - public String getValue() { - return String.valueOf(registrationKey); - } - - public String getTime() { - return formatDate(time); - } - - public RegisteredDeviceType(String deviceKey, String deviceType, - String val, long time) { - this.deviceType = - deviceType == null || deviceType.isEmpty() ? generateName() : deviceType; - this.registrationKey = val; - this.time = time; - this.key = KeyFactory.createKey( - RegisteredDeviceType.class.getSimpleName(), - deviceKey + deviceType +"" + time); - } - - public void destroy() { - JDOStorage.getInstance().delete(this); - } - - public String getKey() { - return key == null ? null : KeyFactory.keyToString(key); - } - - public String getDeviceRegistrationKey() { - return this.registrationKey; - } - - public JSONObject toJSONSenML() { - try { - JSONObject entrySenML = new JSONObject(); - if (deviceType != null) { - entrySenML.put(PARAM_NAME, deviceType); - } - entrySenML.put(PARAM_STRING_VALUE, registrationKey); - return entrySenML; - } catch (Exception e) { - e.printStackTrace(); - log.warning("Error Encoding a measure"); - return null; - } - } - - public Node toXMLSenML(Document d) { - Element measure = d.createElement("e"); - measure.setAttribute(PARAM_NAME, deviceType); - measure.setAttribute(PARAM_STRING_VALUE, String.valueOf(registrationKey)); - return measure; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("key[" + getKey()) - .append("] name[" + deviceType) - .append("] value[" + registrationKey) - .append("] time[" + formatDate(time)) - .append("]"); - return builder.toString(); - } - - public String toPrettyString() { - StringBuilder builder = new StringBuilder(); - builder.append(deviceType) - .append(": ") - .append(") ") - .append(registrationKey) - .append(" @ ") - .append(formatDate(time)); - return builder.toString(); - } - - private String formatDate(long ms) { - if (ms == 0) return "now"; - if (ms < 0) return ("now - " + ms); - - return df.format(new Date(ms)); - } - - private String generateName() { - return UUID.randomUUID().toString(); - } - - public boolean isIsadmin() { - return isadmin; - } - - public void setIsadmin(boolean isadmin) { - this.isadmin = isadmin; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Sensor.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Sensor.java deleted file mode 100644 index e00eefefb6..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Sensor.java +++ /dev/null @@ -1,202 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.Iterator; -import java.util.List; - -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; - -import org.json.JSONObject; -import org.json.JSONArray; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import fr.eurecom.senml.persistence.JDOStorage; -import fr.eurecom.senml.persistence.JDOStorageZone; - -@PersistenceCapable(detachable="true") -public class Sensor implements ISensor { - - @Persistent - @PrimaryKey - protected String uuid; - - @Persistent - protected String title = null; - - @Persistent - protected String zoneKey = null; - - @Persistent - protected String baseUnit = null; - - @Persistent - protected String type = null; - -// Not supported. GAE load only lazy objects (empty objects) and does not support joins. -// @Persistent(defaultFetchGroup="true") -// protected Set measures; - - protected Sensor(String uuid, String title, String zoneKey) { - this.uuid = uuid; - this.title = title.trim(); - this.zoneKey = zoneKey; - } - - public Sensor(String uuid, String title, String zoneKey, String baseUnit, String type) { - this.uuid = uuid; - this.title = title.trim(); - this.zoneKey = zoneKey; - this.baseUnit = baseUnit; - this.type = type; - } - - @Override - public String getUUID() { - return uuid; - } - - @Override - public String zoneType() { - return type; - } - - @Override - public String getTitle() { - return title; - } - - @Override - public IZone getZone() { - if (zoneKey != null) { - return JDOStorage.getInstance().getById(zoneKey, ZoneAdmin.class); - } - return null; - } - - @Override - public String getBaseUnit() { - return baseUnit; - } - - @Override - public JSONObject toJSONSenML() { - JSONObject sensorSenML = new JSONObject(); - try { - sensorSenML.put("bn", getBaseName()); - sensorSenML.put("type", zoneType()); - if (getBaseUnit() != null) { - sensorSenML.put("bu", getBaseUnit()); - } - - JSONArray mArray = new JSONArray(); - for (Measure m : getMeasures()) { - mArray.put(m.toJSONSenML()); - } - if (mArray.length() > 0) { - sensorSenML.put("e", mArray); - } - } - catch (Exception e) { - e.printStackTrace(); - } -// System.out.println(sensorSenML.toString()); - return sensorSenML; - } - - @Override - public Document toXMLSenML() { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document d = builder.newDocument(); - d.appendChild(toXMLSenML(d)); - return d; - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public Element toXMLSenML(Document documentRoot) { - try { - Element senml = documentRoot.createElement("senml"); - senml.setAttribute("bn", getBaseName()); - senml.setAttribute("type", zoneType()); - if (getBaseUnit() != null) { - senml.setAttribute("bu", getBaseUnit()); - } - - for (Measure m : getMeasures()) { - senml.appendChild(m.toXMLSenML(documentRoot)); - } - return senml; - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("Title : " + title); - builder.append("\"bn\" :").append(" (" + type).append(") \"uuid:" + uuid + "\" Measures "); - builder.append("\r\n"); - for (Measure m : JDOStorageZone.getInstance().getMeasures(this)) { - builder.append("\t").append(m.toString()); - builder.append("\r\n"); - } - return builder.toString(); - } - -/* @Override - public List getMeasuresPrint() { - List mString = new ArrayList(); - - for (String mKey : measuresKey) { - Measure m = JDOStorage.getInstance().getById(mKey, Measure.class); - mString.add(m.toPrettyString()); - } - return mString; - } -*/ - -/* @Override - public List getMeasuresKey() { - return new ArrayList(measuresKey); - } -*/ - - @Override - public List getMeasures() { - return JDOStorageZone.getInstance().getMeasures(this); - } - -/* HACK: "Generic Sensor" when the sensor has been created receiving a senml file (sensorin resource). - else sensor has been entered by the jsp file the uuid is generated by this program. - this is a poor workaround to support both. in a future the jsp should disappears. - */ - private final String getBaseName() { - return uuid; - //return "Generic Sensor".equals(title) ? uuid : String.format("urn:%s:uuid:%s", title.toLowerCase(), uuid); - } - - public static Sensor getByUUID(String uuid) { - List sensors = JDOStorage.getInstance().getAll(Sensor.class); - Iterator iter = sensors.iterator(); - while (iter.hasNext()) { - Sensor current = iter.next(); - if (current.getUUID().equals(uuid)) { - return current; - } - } - return null; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorAdmin.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorAdmin.java deleted file mode 100644 index bd2ff2f8a7..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorAdmin.java +++ /dev/null @@ -1,141 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.UUID; - -import javax.jdo.annotations.Inheritance; -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; - -import org.json.JSONException; - -import fr.eurecom.pushing.GCMPushingServer; -import fr.eurecom.senml.entity.Measure.ParamTypeValue; -import fr.eurecom.senml.persistence.JDOStorage; - -@PersistenceCapable -@Inheritance(customStrategy = "complete-table") -public class SensorAdmin extends Sensor implements ISensorAdmin { - - @NotPersistent - private final static String ZONE_UPDATED = "ZoneUpdated"; - - @Persistent - boolean active = true; - - public SensorAdmin(String title, IZone zone, String baseUnit, String typeSensor) { - super(UUID.randomUUID().toString(), title, zone != null ? zone.getKey() - : null, baseUnit, typeSensor); - JDOStorage.getInstance().write(this); - } - - public SensorAdmin(String bn, String title, IZone zone) { - super(bn, title, zone != null ? zone.getKey() : null); - JDOStorage.getInstance().write(this); - } - - @Override - public void setTitle(String title) { - this.title = title; - JDOStorage.getInstance().write(this); - } - - @Override - public void destroy() { - try { - JDOStorage.getInstance().delete(getMeasures()); - } catch (Exception e) { - e.printStackTrace(); - } - - JDOStorage.getInstance().delete(this); - } - - @Override - public boolean linkZone(IZone zone) { - return zone == null ? false : linkZone(zone.getKey()); - } - - @Override - public boolean linkZone(String zoneKey) { - if (active && checkKey(zoneKey)) { - this.zoneKey = zoneKey; - JDOStorage.getInstance().write(this); - return active; - } - return false; - } - - @Override - public void unlinkZone() { - if (zoneKey != null) { - this.zoneKey = null; - JDOStorage.getInstance().write(this); - } - } - - @Override - public void deleteMeasure(String measureKey) { - if (measureKey != null) { - JDOStorage.getInstance() - .delete(JDOStorage.getInstance().getById(measureKey, - Measure.class)); - } - fr.eurecom.restlet.resources.common.ContactBaseResource - .sendUpdateSubscribers(ZONE_UPDATED + getZone().getName()); - } - - @Override - public void deleteMeasure(Measure measure) { - JDOStorage.getInstance().delete(measure); - fr.eurecom.restlet.resources.common.ContactBaseResource - .sendUpdateSubscribers(ZONE_UPDATED + getZone().getName()); - } - - private boolean checkKey(String key) { - return key != null && !key.trim().isEmpty(); - } - - @Override - public Measure addMeasure(String measureName, Units measureUnit, - ParamTypeValue measureTypeValue, String measureValue, - long timeMeasure, String type) { - - Measure m = new Measure(getUUID(), measureName, measureUnit, - measureTypeValue, measureValue, timeMeasure, type); - JDOStorage.getInstance().write(m); - - // fr.eurecom.restlet.resources.common.ContactBaseResource.sendUpdateSubscribers(ZONE_UPDATED - // + getZone().getName()); - GCMPushingServer GCM = GCMPushingServer.getInstance(); - try { - GCM.sendNotification(ZONE_UPDATED + getZone().getName()); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return m; - } - - @Override - public Measure addMeasure(String measureName, Units measureUnit, - ParamTypeValue measureTypeValue, String measureValue, - long timeMeasure, String type, String sum) { - - Measure m = new Measure(getUUID(), measureName, measureUnit, - measureTypeValue, measureValue, timeMeasure, type, sum); - JDOStorage.getInstance().write(m); - - // fr.eurecom.restlet.resources.common.ContactBaseResource.sendUpdateSubscribers(ZONE_UPDATED - // + getZone().getName()); - GCMPushingServer GCM = GCMPushingServer.getInstance(); - try { - GCM.sendNotification(ZONE_UPDATED + getZone().getName()); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return m; - } - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorCheckAlarm.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorCheckAlarm.java deleted file mode 100644 index e6b4ebd2f2..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/SensorCheckAlarm.java +++ /dev/null @@ -1,169 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.HashMap; -import java.util.List; -import java.util.logging.Logger; -import java.util.Map; - -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import org.json.JSONObject; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorage; - -/** - * Represents the list of the monitored sensors, and the relative - * minimum and maximum values (allowed range) - */ -@PersistenceCapable(detachable = "true") -public class SensorCheckAlarm { - - public enum ParamTypeValue { - BOOL("bv"), FLOAT("v"), STRING("sv"); - - private String encoded; - private final static Map mTypeValue = new HashMap(); - - ParamTypeValue(String encoded) { - this.encoded = encoded; - } - - public String getSenML() { - return encoded; - } - - public static ParamTypeValue getParamTypeValue(String senmlEncoded) { - if (mTypeValue == null) { - initMapValue(); - } - return mTypeValue.get(senmlEncoded); - } - - private static synchronized void initMapValue() { - if (mTypeValue.size() > 0) { - return; - } - for (ParamTypeValue v : values()) { - mTypeValue.put(v.encoded, v); - } - } - }; - - @NotPersistent - private static final Logger log = Logger - .getLogger("sensors.entity.SensorCheckAlarm"); - @NotPersistent - public static final String PARAM_NAME = "n"; - @NotPersistent - public static final String PARAM_VALUE = "v"; - @NotPersistent - public static final String PARAM_STRING_VALUE = "sv"; - @NotPersistent - public static final String PARAM_RT_ALLOWED = "rt-allowed"; - - @PrimaryKey - @Persistent - Key key; - - @Persistent - private String sensorKey; - - @Persistent - private String sensorName; - - @Persistent - private String zoneKey; - - // This should be an Object, and then through reflection setted to the correct type - @Persistent - private float minVal; - - @Persistent - private float maxVal; - - public SensorCheckAlarm(String sensorKey, float minVal, float maxVal) { - this.sensorKey = sensorKey; - - this.key = KeyFactory.createKey(SensorCheckAlarm.class.getSimpleName(), - sensorKey + "sensoralarm"); - this.setMinVal(minVal); - this.setMaxVal(maxVal); - } - - public void destroy() { - JDOStorage.getInstance().delete(this); - } - - public String getKey() { - return key == null ? null : KeyFactory.keyToString(key); - } - - public JSONObject toJSONSenML() { - try { - JSONObject entrySenML = new JSONObject(); - - HashMap rtAllowed = new HashMap(); - rtAllowed.put("min", getMinVal()); - rtAllowed.put("max", getMaxVal()); - entrySenML.put("key", getKey()); - entrySenML.put("sensorkey", getSensorKey()); - entrySenML.put("sensorName", getParentSensorName()); - JSONObject rtAllowedJSON = new JSONObject(rtAllowed); - entrySenML.put(PARAM_RT_ALLOWED, rtAllowedJSON); - return entrySenML; - } catch (Exception e) { - e.printStackTrace(); - log.warning("Error Encoding a measure"); - return null; - } - } - - public Node toXMLSenML(Document d) { - //TODO - return null; - } - - public String getParentSensorName() { - SensorAdmin sensor = JDOStorage.getInstance().getById(sensorKey, SensorAdmin.class); - return sensor.getTitle(); - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("key: " + this.sensorKey).append(", [" + getMinVal() + ", ") - .append(getMaxVal() + "]"); - return builder.toString(); - } - - public String getSensorKey() { - return sensorKey; - } - - public static List getAllMonitoredSensors() { - return JDOStorage.getInstance().getAll(SensorCheckAlarm.class); - } - - public float getMinVal() { - return minVal; - } - - public void setMinVal(float minVal) { - this.minVal = minVal; - } - - public float getMaxVal() { - return maxVal; - } - - public void setMaxVal(float maxVal) { - this.maxVal = maxVal; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Units.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Units.java deleted file mode 100644 index cdc44e4db6..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Units.java +++ /dev/null @@ -1,115 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.HashMap; -import java.util.Map; - -/** - * Units Definition from UCUM organization. - * - * @author dalmassi - * - */ -public enum Units { - ACIDITY("acidity", "pH", "pH"), // senml 10 Nota : ucum c/s = [pH] - ACCELERATION("acceleration", "m/s2", "m/s2"), // senml 10 - AMPERE("electric current", "A", "A"), - AREA("Area", "m2", "m2"), // senml 10 - BATTERY_LEVEL_PERCENT("Remaining percent battery", "%EL", "%EL"), // senml 10 - BATTERY_LEVEL_SECOND("Remaining seconds battery", "EL", "EL"), // senml 10 - BAR("pressure", "bar", "bar"), - BEATS_PER_MINUTE("beats/minute", "beet/m", "beet/m"), // senml 10 says beet/m, but ucum m = meter, min = minutes. This is confusing, also beet looks mispelled. Check next draft version. - BEATS("Cumulative beats", "beets", "beets"), // senml 10. - BECQUEREL("becquerel", "bq", "bq"), - BEL_SOUND_LEVEL("bel sound pressure level", "Bspl", "Bspl"), // senml 10 - BIT_SECOND("bits per second", "bit/s", "bit/s"), // senml 10 - CANDELA("luminous intensity", "cd","cd"), - COUNT("count", "count", "count"), // senml 10 - COULOMB("electric charge", "C", "C"), - DAY("time", "d", "d"), - DEGREE_ANGLE("Plan Angle", "°", "deg"), - DEGREE_CELSIUS("temperature", "°C", "Cel"), - DEGREE_FAHRENHEIT("temperature","°F", "[degF]"), - FARAD("electric capacitance", "F", "F"), - GRAM("mass", "g", "g"), - GRAM_PER_LITER("gram per liter", "g/L", "g/L"), - GRAY("gray", "Gy", "Gy"), // senml 10 - KATAL("katal", "kat", "kat"), // senml 10 - KELVIN("temperature", "K", "K"), - HENRY("henry", "H", "H"), // senml 10 - HERTZ("hertz", "Hz", "Hz"), - HUMIDITY_RELATIVE("humidity", "%RH", "%RH"), // senml 10 - HOUR ("time", "h", "h"), - IRRIDIANCE("irridiance", "W/m2", "W/m2"), // senml 10 - JOULE("joule", "J", "J"), - KILO_GRAM("mass", "kg", "kg"), // senml 10 - KILO_WATT_HOUR("kilo watt per hour", "kWh", "kW/h"), - LATITUDE("WGS84-Latitude", "lat", "lat"), // draft senml 10 - LITER("volume", "l", "l"), - LITER_SECOND("flow liters per seconds", "l/s", "l/s"), // senml 10 Nota ucum = L/s - LUMEN("luminous flux", "lm", "lm"), - LUMINANCE("luminance", "cd/m2", "cd/m2"), // senml 10 - LONGITUDE("WGS84-Longitude", "lon", "lon"), // draft senml 10 - LUX("illuminance", "lx", "lx"), - METER("length", "m", "m"), - MINUTE_ANGLE("Plan angle", "′", "′"), - MINUTE_TIME("time", "min", "min"), - MOLE("mole", "mol", "mol"), // senml 10 - NEWTON("newton", "N", "N"), // senml 10 - OHM("electric resistance", "Ω","Ohm"), - PASCAL("pressure", "Pa", "Pa"), // draft senml 10 - PERCENT("percent", "%", "UCUM:%"), // ucum - RADIAN("plane angle", "rad", "rad"), - SECOND_ANGLE("Plan Angle", "″", "″"), - SECOND_TIME("time", "s", "s"), - SIEMENS("Siemens", "S", "S"), // senml 10 - SIEVERT("Sievert", "Sv", "Sv"), // senml 10 - STERADIAN("steradian", "sr", "sr"), // senml 10 - SWITCH("switch", "switch", "%"), // senml 10 conflict with ucum percent - TONNE("mass", "t", "t"), - TESLA("magnetic flux density", "T", "T"), - VELOCITY("velocity", "m/s", "m/s"), - VOLT("electric potential", "V", "V"), - WATT("power", "W", "W"), - WEBER("wever", "Wb", "Wb"), // senml 10 - YEAR("time", "a", "a"); - - private final String print; - private final String cs; - private final String kindOfQty; - - private final static Map csMap = new HashMap(); - - Units(String kind, String print, String cs) { - this.print = print; - this.cs = cs; - this.kindOfQty = kind; - } - - public String getCS() { - return cs; - } - - public String getKindofQty() { - return kindOfQty; - } - - public String getPrint() { - return print; - } - - public static Units getUnit(String cs) { - if (csMap.size() == 0) { - initCsMap(); - } - return csMap.get(cs); - } - - private static synchronized void initCsMap() { - if (csMap.size() > 0 ) { - return; - } - for (Units u : values()) { - csMap.put(u.cs, u); - } - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Zone.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Zone.java deleted file mode 100644 index 7daba277d6..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/Zone.java +++ /dev/null @@ -1,104 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; -import javax.jdo.annotations.PrimaryKey; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorageZone; - -@PersistenceCapable(detachable="true") -public class Zone implements IZone { - @NotPersistent - private static final Logger log = Logger.getLogger("Zone"); - - @Persistent - @PrimaryKey - protected Key key; - - @Persistent - protected String name = ""; - - @Persistent - protected String parentKey = null; - - @Persistent - protected String zoneType = ""; - -/** - * Instantiates a zone. - * @param key Zone key - * @param name Zone name - * @param parentKey Zone parent key. Can be null. - * @param type - */ - protected Zone(Key key, String name, String parentKey, String type) { - this.key = key; - this.name = name; - this.parentKey = parentKey; - this.zoneType = type; - } - - @Override - public List getSubZones() { - long before = System.currentTimeMillis(); - - List childs = JDOStorageZone.getInstance().getSubZones(this); - - long after = System.currentTimeMillis(); - log.info("getSubzone " + name + " taken ms:" + (after - before)); - return childs; - } - - @Override - public List getSensors() { - long before = System.currentTimeMillis(); - - List sensors = JDOStorageZone.getInstance().getSensors(this); - - long after = System.currentTimeMillis(); - log.info("getSensors " + name + " taken ms:" + (after - before)); - return sensors; - } - - @Override - public String getName() { - return name; - } - - @Override - public String getKey() { - return KeyFactory.keyToString(key); - } - - @Override - public String getType() { - return zoneType; - } - - @Override - public int compareTo(IZone o) { - return this.name.compareTo(o.getName()); - } - - @Override - public IZone getParentZone() { - Zone p = null; - if (parentKey != null) { - try { - p = JDOStorageZone.getInstance().getById(parentKey, this.getClass()); - } - catch (Exception e) { - log.log(Level.WARNING, "Error retrieving parent zone", e); - } - } - return p; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ZoneAdmin.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ZoneAdmin.java deleted file mode 100644 index 2f08c22b9b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/entity/ZoneAdmin.java +++ /dev/null @@ -1,86 +0,0 @@ -package fr.eurecom.senml.entity; - -import java.util.Collections; -import java.util.List; -import java.util.SortedSet; -import java.util.logging.Logger; - -import javax.jdo.annotations.Index; -import javax.jdo.annotations.Inheritance; -import javax.jdo.annotations.NotPersistent; -import javax.jdo.annotations.PersistenceCapable; -import javax.jdo.annotations.Persistent; - -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; - -import fr.eurecom.senml.persistence.JDOStorage; -import fr.eurecom.senml.persistence.JDOStorageZone; - -/** - * Not thread-safe. - * - * @author dalmassi - * - */ -@PersistenceCapable -@Inheritance(customStrategy = "complete-table") -// @Index(name="index_parentKey", members={"parentKeyString"}) -public class ZoneAdmin extends Zone implements IZoneAdmin { - @NotPersistent - private static final Logger log = Logger.getLogger("Zone"); - - @Persistent - private boolean isActive = true; - - public ZoneAdmin(String name, ZoneAdmin parent, String type) { - super(KeyFactory.createKey(ZoneAdmin.class.getSimpleName(), name), - name, parent == null ? null : parent.getKey(), type); - JDOStorage.getInstance().write(this); - } - - @Override - public void destroy() { - isActive = false; - parentKey = null; - - List sensors = JDOStorageZone.getInstance().getSensors( - this); - - for (ISensorAdmin s : sensors) { - s.destroy(); - } - - JDOStorage.getInstance().delete(this); - // TODO: Possible Race condition here. The delete is not effective when - // method JDOStorage delete returns. - log.fine("Removed from database " + this.name); - } - - @Override - public boolean linkParentZone(String parentZoneKey) { - if (isActive && checkKey(parentZoneKey)) { - this.parentKey = parentZoneKey; - JDOStorage.getInstance().write(this); - return isActive; - } - return false; - } - - @Override - public boolean linkParentZone(IZone parentZone) { - return parentZone == null ? false : linkParentZone(parentZone.getKey()); - } - - @Override - public void unlinkParentZone() { - if (parentKey != null) { - parentKey = null; - JDOStorage.getInstance().write(this); - } - } - - private boolean checkKey(String key) { - return key != null && !key.trim().isEmpty(); - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ControllerJsp.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ControllerJsp.java deleted file mode 100644 index 676933e99a..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ControllerJsp.java +++ /dev/null @@ -1,285 +0,0 @@ -package fr.eurecom.senml.jspcontroller; - -import java.util.Calendar; -import java.util.List; -import java.util.TimeZone; -import java.util.concurrent.TimeUnit; - -import javax.servlet.http.HttpServletRequest; - -import org.springframework.stereotype.Controller; -import org.springframework.ui.ModelMap; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.servlet.ModelAndView; - -import fr.eurecom.pushing.GCMPushingServer; -import fr.eurecom.senml.entity.IPostVal; -import fr.eurecom.senml.entity.IZone; -import fr.eurecom.senml.entity.Measure; -import fr.eurecom.senml.entity.PostValAdmin; -import fr.eurecom.senml.entity.PostValType; -import fr.eurecom.senml.entity.Sensor; -import fr.eurecom.senml.entity.SensorAdmin; -import fr.eurecom.senml.entity.SensorCheckAlarm; -import fr.eurecom.senml.entity.Units; -import fr.eurecom.senml.entity.Zone; -import fr.eurecom.senml.entity.ZoneAdmin; -import fr.eurecom.senml.persistence.JDOStorage; - -@Controller -@RequestMapping("/") -public class ControllerJsp { - - @RequestMapping(value = "/zones", method = RequestMethod.GET) -// @ModelAttribute - public String listZone(ModelMap model) { - List zones = JDOStorage.getInstance().getAll(ZoneAdmin.class); - model.addAttribute("zoneList", zones); - return "zonelist"; - } - - @RequestMapping(value="/addZone", method = RequestMethod.POST) - public ModelAndView addZone(HttpServletRequest request) { - String name = request.getParameter("nameZone"); - String nameParent = request.getParameter("parentNameZone"); - String type = request.getParameter("typeZone"); - - ZoneAdmin parent = nameParent.isEmpty() - ? null - :JDOStorage.getInstance().getById(nameParent, ZoneAdmin.class); - - new ZoneAdmin(name, parent, type); - return new ModelAndView("redirect:zones"); - } - - @RequestMapping(value = "deleteZone/{zoneKey}", method = RequestMethod.GET) - public ModelAndView deleteZone(@PathVariable String zoneKey, HttpServletRequest request) { - - ZoneAdmin z = JDOStorage.getInstance().getById(zoneKey, ZoneAdmin.class); - if (z != null) { - z.destroy(); - } - return new ModelAndView("redirect:../zones"); - } - - - @RequestMapping(value="{zoneKey}/edit", method = RequestMethod.GET) - public String editZone(@PathVariable String zoneKey, HttpServletRequest request, - ModelMap model) { - ZoneAdmin z = JDOStorage.getInstance().getById(zoneKey, ZoneAdmin.class); - model.addAttribute("zone", z); - return "detailzone"; - } - - - @RequestMapping(value="{zoneKey}/addsubZone", method = RequestMethod.POST) - public String addSubzone(@PathVariable String zoneKey, HttpServletRequest request, ModelMap model) { - String subZone = request.getParameter("nameSubZone"); - String typeZone = request.getParameter("typeZone"); - - ZoneAdmin zone = JDOStorage.getInstance().getById( - zoneKey, ZoneAdmin.class); - - new ZoneAdmin(subZone, zone, typeZone); - model.addAttribute("zone", zone); - return "redirect:edit"; - } - - @RequestMapping(value="{zoneKey}/addSensor", method = RequestMethod.POST) - public String addSensor(@PathVariable String zoneKey, HttpServletRequest request, ModelMap model) { - String title = request.getParameter("title"); - String baseUnit = request.getParameter("baseunit"); - String typeSensor = request.getParameter("typeSensor"); - ZoneAdmin za = JDOStorage.getInstance().getById(zoneKey, ZoneAdmin.class); - new SensorAdmin(title, za, baseUnit, typeSensor); - - model.addAttribute("zone", za); - return "redirect:edit"; - } - - @RequestMapping(value= "{zoneKey}/deleteSensor/{sensorKey}", method = RequestMethod.GET) - public ModelAndView deleteSensor(@PathVariable String zoneKey, - @PathVariable String sensorKey, HttpServletRequest request, ModelMap model) { - - SensorAdmin s = JDOStorage.getInstance().getById(sensorKey, SensorAdmin.class); - s.destroy(); - - return new ModelAndView("redirect:../edit"); - } - - - @RequestMapping(value="{zoneKey}/delete/{subZoneKey}", method = RequestMethod.GET) - @ModelAttribute - public ModelAndView deleteZone(@PathVariable String zoneKey, @PathVariable String subZoneKey, - HttpServletRequest request, ModelMap model) { - ZoneAdmin z = JDOStorage.getInstance().getById(subZoneKey, ZoneAdmin.class); - if (z != null) { - z.destroy(); - } - - return new ModelAndView("redirect:../edit"); - } - - @RequestMapping(value="{zoneKey}/addMeasure", method = RequestMethod.POST) - public String addMeasure(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - - // Mandatory fields - String sensorKey = request.getParameter("sensorKey"); - String unit = request.getParameter("unit"); - String name = request.getParameter("name"); - String typeValue = request.getParameter("typeValue"); - String value = request.getParameter("value"); - long time = getSecondsSince1970UTC(request.getParameter("time")); - String strVersion = request.getParameter("version"); - // Optional values - String sumValue = request.getParameter("sum"); - String specMeasure = request.getParameter("specmeasure"); - if (specMeasure != null) System.out.println("spec measure: " + specMeasure.toString()); - String baseUnit = request.getParameter("bu"); - String allowed = request.getParameter("allowed"); - String rtallowed = request.getParameter("rtallowed"); - String type = request.getParameter("measureType"); - - // If version is not setted, automatically is 1 - if (strVersion == null) { - strVersion = "1.0"; - } - - float version = Float.parseFloat(strVersion); - - SensorAdmin sa = JDOStorage.getInstance().getById(sensorKey, SensorAdmin.class); - - if (sumValue == null) { - if ((specMeasure == null) || (specMeasure.equalsIgnoreCase("off"))) { - System.out.println("using baseUnit " + baseUnit); - sa.addMeasure( - name, - null, - Measure.ParamTypeValue.valueOf(typeValue.toUpperCase()), - value, time, type); - } else { - System.out.println("specMeasure is " + specMeasure); - sa.addMeasure( - name, - Units.getUnit(unit), - Measure.ParamTypeValue.valueOf(typeValue.toUpperCase()), - value, time, type); - } - } else { - if ((specMeasure == null) || (specMeasure.equalsIgnoreCase("off"))) { - System.out.println("using baseUnit " + baseUnit); - sa.addMeasure( - name, - null, - Measure.ParamTypeValue.valueOf(typeValue.toUpperCase()), - value, time, type, sumValue); - } else { - System.out.println("specMeasure is " + specMeasure); - sa.addMeasure( - name, - Units.getUnit(unit), - Measure.ParamTypeValue.valueOf(typeValue.toUpperCase()), - value, time, type, sumValue); - } - - } - - model.addAttribute("zone", sa.getZone()); - // Eventually notify the registered devices - - return "redirect:edit"; - } - - @RequestMapping(value="{zoneKey}/addAlertMonitor", method = RequestMethod.POST) - public String addAlertMonitor(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - - // Mandatory fields - String sensorKey = request.getParameter("sensorKey"); - float rtallowedmin = Float.parseFloat(request.getParameter("rtallowedmin")); - float rtallowedmax = Float.parseFloat(request.getParameter("rtallowedmax")); - - ZoneAdmin zone = JDOStorage.getInstance().getById(zoneKey, ZoneAdmin.class); - Sensor sensor = JDOStorage.getInstance().getById(sensorKey, SensorAdmin.class); - System.out.println("Adding monitoring for " + zone.getName() + ", " + sensor.getTitle()); - - SensorCheckAlarm checkAlarm = new SensorCheckAlarm(sensorKey, rtallowedmin, rtallowedmax); - JDOStorage.getInstance().write(checkAlarm); - return "redirect:edit"; - } - - // Admin website version - TODO, filter for sensors/zones - @RequestMapping(value="{zoneKey}/listAlertsMonitor", method = RequestMethod.GET) - public String listAlertsMonitor(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - //TODO IF NEEDED!!!! - return "alarms"; - } - - // Admin website version for all the monitors - @RequestMapping(value="/listAllAlertsMonitorJSON", method = RequestMethod.GET) - public String listAllAlertsMonitorJSON(HttpServletRequest request, ModelMap model) { - return "allalarmsJSON"; - } - - // Admin mobile app version - @RequestMapping(value="{zoneKey}/listAlertsMonitorJSON", method = RequestMethod.GET) - public String listAlertsMonitorJSON(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - return "alarmsJSON"; - } - - @RequestMapping(value="{zoneKey}/removemonitor", method = RequestMethod.GET) - public String removeMonitor(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - String sensorKey = request.getParameter("key"); - SensorCheckAlarm s = JDOStorage.getInstance().getById(sensorKey, SensorCheckAlarm.class); - JDOStorage.getInstance().delete(s); - return "alarms"; - } - - @RequestMapping(value="{zoneKey}/getmonitor", method = RequestMethod.GET) - public String getMonitor(@PathVariable String zoneKey, - HttpServletRequest request, ModelMap model) { - return "sensormonitorsjson"; - } - - /** - * To respect the senML directives, we need seconds since 1970 UTC - * @param parameter - * @return - */ - private long getSecondsSince1970UTC(String parameter) { - Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); - System.out.println("Calendar is: " + calendar); - int secondsSinceEpoch = (int) TimeUnit.MILLISECONDS.toSeconds(calendar.getTimeInMillis()); - System.out.println("seconds are " + secondsSinceEpoch); - return secondsSinceEpoch; - } - - @RequestMapping(value= "{zoneKey}/deleteMeasure/{keyMeasure}", - method = RequestMethod.GET) - public ModelAndView deleteMeasure(@PathVariable String zoneKey, @PathVariable String keyMeasure, - HttpServletRequest request, ModelMap model) { - - Measure m = JDOStorage.getInstance().getById(keyMeasure, Measure.class); -// m.destroy(); - SensorAdmin sa = JDOStorage.getInstance().getById(m.getSensorKey(), SensorAdmin.class); - sa.deleteMeasure(m); - return new ModelAndView("redirect:../edit"); - } - - @RequestMapping(value = "/postvals", method = RequestMethod.GET) - public String listPostVals(ModelMap model) { - List zones = JDOStorage.getInstance().getAll(PostValType.class); - model.addAttribute("postvalsList", zones); - return "postvalslist"; - } -// -// @RequestMapping(value = "/alertsadmin", method = Request.GET) -// public String listMonitoredSensors() -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ZoneTypes.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ZoneTypes.java deleted file mode 100644 index 30738fb665..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/jspcontroller/ZoneTypes.java +++ /dev/null @@ -1,14 +0,0 @@ -package fr.eurecom.senml.jspcontroller; - -public class ZoneTypes { - - // Refers to - // http://www.sensormeasurement.appspot.com/json/m3/featureOfInterest - private static String[] zoneTypes = {"City", "Environment", "Military", - "Tracking", "Health", "Place", "Building", "Transportation", - "BrainWave"}; - - public static String[] getZoneTypes() { - return zoneTypes; - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorage.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorage.java deleted file mode 100644 index 9400891959..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorage.java +++ /dev/null @@ -1,167 +0,0 @@ -package fr.eurecom.senml.persistence; - -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -import javax.jdo.PersistenceManager; -import javax.jdo.Query; - -import fr.eurecom.restlet.resources.persistence.PMF; -import fr.eurecom.senml.entity.Zone; -import fr.eurecom.senml.entity.ZoneAdmin; - -/** - * This class is a jdo wrapper. Implementing the persistence. - * @author dalmassi - * - */ -public class JDOStorage { - private static final JDOStorage instance = new JDOStorage(); - - protected JDOStorage() { - - } - - public static JDOStorage getInstance() { - return instance; - } - - @SuppressWarnings("unchecked") -/** - * Wrapper JDO PM.getById, return a detached object. - * @param key The String key - * @param c Class of the object - * @return a typed object of the class. - */ - public T getById(String key, Class c) { - PersistenceManager pm = PMF.get().getPersistenceManager(); - Object attached, detached = null; - - try { - attached = pm.getObjectById(c, key); - detached = pm.detachCopy(attached); - } - finally { - close(pm); - } - return (T) detached; - } - - public void refresh(String key, Class c) { - PersistenceManager pm = getPM(); - - try { - - Object attached = pm.getObjectById(c, key); - pm.refresh(attached); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - - Query q = null; - - @SuppressWarnings("unchecked") - public List getAll(Class c) { - List detached = Collections.EMPTY_LIST; - PersistenceManager pm = getPM(); - Query q = pm.newQuery(c); - - try { - List results = (List) q.execute(); - if (!results.isEmpty()) { - detached = (List) pm.detachCopyAll(results); - } - close(q); - close(pm); - } - catch (Exception e) { - e.printStackTrace(); - } - return detached; - } - -/** - * Save an object to dataStore. - * @param z object to save - * @return true if ok, false otherwise. - */ - public boolean write(T z) { - PersistenceManager pm = getPM(); - try { - pm.makePersistent(z); -// System.out.println("write jdo done! zone name|" + z.getName() + "| key |" + z.getKey() + "|"); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - finally { - close(pm); - } - } - - public void delete(T z) { - PersistenceManager pm = getPM(); - try { - pm.deletePersistent(z); - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - close(pm); - } - } - - public void delete(Collection z) { - PersistenceManager pm = getPM(); - try { - pm.deletePersistentAll(z); - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - close(pm); - } - } - - public long deleteAll(Class c) { - PersistenceManager pm = getPM(); - long count = -1; - try { - Query q = pm.newQuery(c); - count = q.deletePersistentAll(); - } - catch (Exception e) { - e.printStackTrace(); - } - finally { - close(q); - close(pm); - } - return count; - } - - - protected PersistenceManager getPM() { - return PMF.get().getPersistenceManager(); - } - - protected void close(PersistenceManager pm) { - if (pm != null) { - pm.close(); - } - } - - protected void close(Query q) { - if (q != null) { - q.closeAll(); - } - } - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorageZone.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorageZone.java deleted file mode 100644 index 627c95dfc9..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/fr/eurecom/senml/persistence/JDOStorageZone.java +++ /dev/null @@ -1,115 +0,0 @@ -package fr.eurecom.senml.persistence; - -import java.util.Collections; -import java.util.List; - -import javax.jdo.PersistenceManager; -import javax.jdo.Query; -import fr.eurecom.senml.entity.Measure; -import fr.eurecom.senml.entity.Sensor; -import fr.eurecom.senml.entity.SensorAdmin; -import fr.eurecom.senml.entity.Zone; -import fr.eurecom.senml.entity.ZoneAdmin; - - - -public class JDOStorageZone extends JDOStorage { - private static final JDOStorageZone instance = new JDOStorageZone(); - private Query Q_SUBZONE_ADMIN = null; - private Query Q_SENSOR_ADMIN = null; - private Query Q_MEASURE_ADMIN = null; - - - private JDOStorageZone() { - super(); - createQuerySubZone(); - createQueryZoneSensors(); - createQueryMeasures(); - } - - - public static JDOStorageZone getInstance() { - return instance; - } - - - @SuppressWarnings("unchecked") - public List getSubZones(Zone zone) { - List detached = Collections.EMPTY_LIST; - try { - List results = (List) Q_SUBZONE_ADMIN.execute(zone.getKey()); - if (!results.isEmpty()) { - detached = (List) Q_SUBZONE_ADMIN.getPersistenceManager().detachCopyAll(results); - } - } - catch (Exception e) { - e.printStackTrace(); - } - return detached; - } - - @SuppressWarnings("unchecked") - public List getSensors(Zone zone) { - List detached = Collections.EMPTY_LIST; - try { - List results = (List) Q_SENSOR_ADMIN.execute(zone.getKey()); - if (!results.isEmpty()) { - detached = (List) Q_SENSOR_ADMIN.getPersistenceManager().detachCopyAll(results); - } - } - catch (Exception e) { - e.printStackTrace(); - } - return detached; - } - - @SuppressWarnings("unchecked") - public List getMeasures(Sensor sensor) { - List detached = Collections.EMPTY_LIST; - try { - List results = (List) Q_MEASURE_ADMIN.execute(sensor.getUUID()); - if (!results.isEmpty()) { - detached = (List) Q_MEASURE_ADMIN.getPersistenceManager().detachCopyAll(results); - } - } - catch (Exception e) { - e.printStackTrace(); - } - return detached; - } - - - private void createQuerySubZone() { - if (Q_SUBZONE_ADMIN == null) { - Q_SUBZONE_ADMIN = getPM().newQuery(ZoneAdmin.class); - Q_SUBZONE_ADMIN.setFilter("parentKey == keyParentParam"); -// Q_SUBZONE.declareParameters(Key.class.getName() + " keyParentParam"); - Q_SUBZONE_ADMIN.declareParameters("String keyParentParam"); - Q_SUBZONE_ADMIN.compile(); - } - } - - private void createQueryZoneSensors() { - if (Q_SENSOR_ADMIN == null) { - PersistenceManager pm = getPM(); -// pm.getFetchPlan().setDetachmentOptions( FetchPlan.DETACH_LOAD_FIELDS | FetchPlan.DETACH_UNLOAD_FIELDS); -// pm.getFetchPlan().setMaxFetchDepth(4); - - Q_SENSOR_ADMIN = pm.newQuery(SensorAdmin.class); - Q_SENSOR_ADMIN.setFilter("zoneKey == zoneKeyParam"); - Q_SENSOR_ADMIN.declareParameters("String zoneKeyParam"); - Q_SENSOR_ADMIN.compile(); - } - } - - private void createQueryMeasures() { - if (Q_MEASURE_ADMIN == null) { - PersistenceManager pm = getPM(); - Q_MEASURE_ADMIN = pm.newQuery(Measure.class); - Q_MEASURE_ADMIN.setFilter("sensorKey == sensorKeyParam"); - Q_MEASURE_ADMIN.declareParameters("String sensorKeyParam"); - Q_MEASURE_ADMIN.compile(); - Q_MEASURE_ADMIN.setIgnoreCache(true); - } - } -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/log4j.properties b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/log4j.properties deleted file mode 100644 index d9c3edc9fe..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/src/log4j.properties +++ /dev/null @@ -1,24 +0,0 @@ -# A default log4j configuration for log4j users. -# -# To use this configuration, deploy it into your application's WEB-INF/classes -# directory. You are also encouraged to edit it as you like. - -# Configure the console as our one appender -log4j.appender.A1=org.apache.log4j.ConsoleAppender -log4j.appender.A1.layout=org.apache.log4j.PatternLayout -log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n - -# tighten logging on the DataNucleus Categories -log4j.category.DataNucleus.JDO=WARN, A1 -log4j.category.DataNucleus.Persistence=WARN, A1 -log4j.category.DataNucleus.Cache=WARN, A1 -log4j.category.DataNucleus.MetaData=WARN, A1 -log4j.category.DataNucleus.General=WARN, A1 -log4j.category.DataNucleus.Utility=WARN, A1 -log4j.category.DataNucleus.Transaction=WARN, A1 -log4j.category.DataNucleus.Datastore=WARN, A1 -log4j.category.DataNucleus.ClassLoading=WARN, A1 -log4j.category.DataNucleus.Plugin=WARN, A1 -log4j.category.DataNucleus.ValueGeneration=WARN, A1 -log4j.category.DataNucleus.Enhancer=WARN, A1 -log4j.category.DataNucleus.SchemaTool=WARN, A1 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml deleted file mode 100644 index fd44d7144b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-generated/datastore-indexes-auto.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-web.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-web.xml deleted file mode 100644 index 479f85751d..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/appengine-web.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - wlboxv2 - 2 - - - true - - - - - - - true - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/backends.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/backends.xml deleted file mode 100644 index 8dc317be17..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/backends.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - B1 - 1 - - false - true - - - \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-1.0-sdk-1.7.4.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-1.0-sdk-1.7.4.jar deleted file mode 100644 index 244505a1cf..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-1.0-sdk-1.7.4.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-labs.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-labs.jar deleted file mode 100644 index 1fe9f839e4..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-api-labs.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-endpoints.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-endpoints.jar deleted file mode 100644 index 5bbba4a3ef..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-endpoints.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-jsr107cache-1.7.4.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-jsr107cache-1.7.4.jar deleted file mode 100644 index f3d111c63f..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-jsr107cache-1.7.4.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-webapis.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-webapis.jar deleted file mode 100644 index ce00b7ea42..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/appengine-webapis.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/asm-4.0.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/asm-4.0.jar deleted file mode 100644 index cca0d9cebf..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/asm-4.0.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/commons-logging-api-1.1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/commons-logging-api-1.1.1.jar deleted file mode 100644 index bd4511684b..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/commons-logging-api-1.1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jdo-3.1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jdo-3.1.1.jar deleted file mode 100644 index 9f3aaf5e97..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jdo-3.1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jpa-3.1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jpa-3.1.1.jar deleted file mode 100644 index 15b9cf68b6..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-api-jpa-3.1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-appengine-2.1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-appengine-2.1.1.jar deleted file mode 100644 index e1a40c1bb8..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-appengine-2.1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-core-3.1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-core-3.1.1.jar deleted file mode 100644 index f8aac6aa32..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/datanucleus-core-3.1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/gcm-server.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/gcm-server.jar deleted file mode 100644 index 41264c8095..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/gcm-server.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/geronimo-jpa_2.0_spec-1.0.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/geronimo-jpa_2.0_spec-1.0.jar deleted file mode 100644 index 2ea9ca9c10..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/geronimo-jpa_2.0_spec-1.0.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jdo-api-3.0.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jdo-api-3.0.1.jar deleted file mode 100644 index 6318d329ca..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jdo-api-3.0.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/json_simple-1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/json_simple-1.1.jar deleted file mode 100644 index f395f41471..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/json_simple-1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jsr107cache-1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jsr107cache-1.1.jar deleted file mode 100644 index a94aa3184e..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jsr107cache-1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jta-1.1.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jta-1.1.jar deleted file mode 100644 index 7736ec9f08..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/jta-1.1.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.json.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.json.jar deleted file mode 100644 index 543438992f..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.json.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.json.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.json.jar deleted file mode 100644 index 49b2873525..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.json.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.servlet.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.servlet.jar deleted file mode 100644 index 5df964798b..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.servlet.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.wadl.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.wadl.jar deleted file mode 100644 index 5a96ccac00..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.wadl.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.xml.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.xml.jar deleted file mode 100644 index 213199baaa..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.ext.xml.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.jar deleted file mode 100644 index 32a3c8483f..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.restlet.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.asm-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.asm-3.1.1.RELEASE.jar deleted file mode 100644 index 20d7938510..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.asm-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.beans-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.beans-3.1.1.RELEASE.jar deleted file mode 100644 index a69bcb1f3d..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.beans-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.context-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.context-3.1.1.RELEASE.jar deleted file mode 100644 index a35e486989..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.context-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.core-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.core-3.1.1.RELEASE.jar deleted file mode 100644 index bdd8944a72..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.core-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.expression-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.expression-3.1.1.RELEASE.jar deleted file mode 100644 index 0e445b97fa..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.expression-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web-3.1.1.RELEASE.jar deleted file mode 100644 index 42ed92c7c2..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar deleted file mode 100644 index 8e27a5bc7e..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/lib/org.springframework.web.servlet-3.1.1.RELEASE.jar and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/logging.properties b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/logging.properties deleted file mode 100644 index 66e9625256..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/logging.properties +++ /dev/null @@ -1,39 +0,0 @@ -# A default java.util.logging configuration. -# (All App Engine logging is through java.util.logging by default). -# -# To use this configuration, copy it into your application's WEB-INF -# folder and add the following to your appengine-web.xml: -# -# -# -# -# - -# Set the default logging level for all loggers to WARNING -#.level = DEBUG - -# A default log4j configuration for log4j users. -# -# To use this configuration, deploy it into your application's WEB-INF/classes -# directory. You are also encouraged to edit it as you like. - -# Configure the console as our one appender -log4j.appender.A1=org.apache.log4j.ConsoleAppender -log4j.appender.A1.layout=org.apache.log4j.PatternLayout -log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n - -# tighten logging on the DataNucleus Categories -log4j.category.DataNucleus.JDO=WARN, A1 -log4j.category.DataNucleus.Persistence=WARN, A1 -log4j.category.DataNucleus.Cache=WARN, A1 -log4j.category.DataNucleus.MetaData=WARN, A1 -log4j.category.DataNucleus.General=WARN, A1 -log4j.category.DataNucleus.Utility=WARN, A1 -log4j.category.DataNucleus.Transaction=WARN, A1 -log4j.category.DataNucleus.Datastore=WARN, A1 -log4j.category.DataNucleus.ClassLoading=WARN, A1 -log4j.category.DataNucleus.Plugin=WARN, A1 -log4j.category.DataNucleus.ValueGeneration=WARN, A1 -log4j.category.DataNucleus.Enhancer=WARN, A1 -log4j.category.DataNucleus.SchemaTool=WARN, A1 - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/spring-dispatcher-servlet.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/spring-dispatcher-servlet.xml deleted file mode 100644 index 5062bb6286..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/spring-dispatcher-servlet.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - /pages/ - - - .jsp - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/web.xml b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/web.xml deleted file mode 100644 index a02428a323..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/WEB-INF/web.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - restlet-dispatcher - org.restlet.ext.servlet.ServerServlet - - org.restlet.application - fr.eurecom.restlet.resources.gae.Dispatcher - - - - - restlet-dispatcher - /contacts/* - - - - - restlet-dispatcher-senml - org.restlet.ext.servlet.ServerServlet - - org.restlet.application - fr.eurecom.restlet.resources.gae.DispatcherSenml - - - - - restlet-dispatcher-senml - /senml/* - - - - SystemServiceServlet - com.google.api.server.spi.SystemServiceServlet - - services - - - - - SystemServiceServlet - /_ah/spi/* - - - - - - - spring-dispatcher - org.springframework.web.servlet.DispatcherServlet - 1 - - - - spring-dispatcher - /senmladmin/* - - - - - DeviceManager - fr.eurecom.pushing.DeviceManager - - - DeviceManager - /pushing/* - - - - contextConfigLocation - /WEB-INF/spring-dispatcher-servlet.xml - - - - org.springframework.web.context.ContextLoaderListener - - - - - index.html - - - \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/css/template_style.css b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/css/template_style.css deleted file mode 100644 index 1cb94dfa53..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/css/template_style.css +++ /dev/null @@ -1,248 +0,0 @@ -/* -Based on a css from http://www.templatemo.com -*/ - -body{ - margin: 0; - padding: 0; - color: #555; - font-size: 12px; - line-height: 1.6em; - font-family: "Lucida Sans Unicode", "Lucida Grande", sans-serif; - background-color: #c7c8c1; - background-image: url(../images/noisy_grid.png); - background-repeat: repeat; - width: 100%: -} - -a, a:link, a:visited { - color: #525111; - font-weight: normal; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -ul, li { - padding:0; - margin:0; - list-style:none; -} - -h1, h2, h3, h4, h5, h6 { color: #525111; font-weight: normal; } -h1 { font-size: 36px; margin: 0 0 30px; padding: 5px 0 } -h2 { font-size: 24px; margin: 0 0 25px; padding: 5px 0 } -h3 { font-size: 20px; margin: 0 0 20px; padding: 0; } -h4 { font-size: 16px; margin: 0 0 15px; padding: 0; } -h5 { font-size: 14px; margin: 0 0 10px; padding: 0; } -h6 { font-size: 12px; margin: 0 0 5px; padding: 0; font-weight: 700 } - -p { - padding: 0; - margin: 0 0 15px 0; -} - -#zone-table -{ - margin: 0; - width: 98%; - text-align: left; - border-collapse: collapse; - font-size: 16px; - border-top: 1px solid #525111; - border-bottom: 1px solid #525111; - border-right: 1px solid #525111; - border-left: 1px solid #525111; -} -#zone-table thead -{ - padding: 8px 2px; - font-weight: bold; - font-size: 16px; -/* border-top: 1px solid #525111; - border-bottom: 1px solid #525111; - border-right: 1px solid #525111; - border-left: 1px solid #525111; -*/ - border-bottom: 1px solid #525111; - -} - -#zone-table td -{ - color: #000; - padding: 12px 2px 0px 2px; - font-weigth: normal; - font-size: 16px; -/* border-right: 30px solid #fff; - border-left: 30px solid #fff; -*/ -} - -#sensor td -{ - border-top: 1px solid #525111; -} - -#measure td -{ - color: #000; - padding: 0px 5px 5px 5px; - font-weigth: normal; - font-size: 14px; -} - -#zone-table caption -{ - font-size: 18px; - font-weight: bold; - padding: 8px 2px; - color:#525111; -} - - -.clear{ - clear:left; -} - - -cite { - font-size: 14px; - color:#525111; -} - - -.list_bullet { - margin: 10px 0 10px 15px; - padding: 0; - list-style: none; -} - -.no_bullet { - margin: 0; - padding: 0; - list-style: none; -} - -.no_bullet li { - margin: 0 0 20px 0; - padding: 0; -} - -a.header { - display: block; - font-weight: 700; -} - -.half { - width: 360px; -} - -.col_175 { - width: 175px; -} - -.h10 { height: 10px } -.h20 { height: 20px } -.h40 { height: 40px } - -.img { - margin: 0; - padding: 0; -} - -.left { - float: left; -} - -.right { - float: right; -} - -#template_header { - width: 100%; - min-height: 110px; - padding: 40px 20px 20px; - margin: 0 auto; - text-align: center; - margin-bottom: 40px; -} - -#template_main { - width: 100%; - margin: 0 auto; - padding: 0 10px; - overflow: hidden; - text-align: center; -} - -#template_footer { - width: 100%; - margin: 0 auto; - padding: 20px 20px; - text-align: center; -} - -#zone_form { - padding: 0; - width: 100%; -} - -#zone_form form { - margin: 0px; - padding: 0px; -} - - -#contact_form { - padding: 0; - width: 365px; -} - -#contact_form form { - margin: 0px; - padding: 0px; -} - -#contact_form form .input_field { - width: 163px; - padding: 5px; - color: #000; - border: 1px solid #adada3; - background: #e9e9e9; - font-family: Tahoma, Geneva, sans-serif; - font-size: 12px; - margin-top: 5px; -} - -#contact_form form label { - display: block; - font-size: 11px; -} - -#contact_form form textarea { - width: 353px; - height: 110px; - padding: 5px; - color: #000; - border: 1px solid #adada3; - background: #e9e9e9; - font-family: Tahoma, Geneva, sans-serif; - font-size: 12px; - margin-top: 5px; -} - -#contact_form form .submit_btn { - font-size: 12px; - color: #000; - border: 1px solid #adada3; - background: #e9e9e9; - padding: 5px 14px; - margin: 10px 0px; -} - -.hidden { - display: none; -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/favicon.ico b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/favicon.ico deleted file mode 100644 index 0062ab413e..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/favicon.ico and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/android.jpg b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/android.jpg deleted file mode 100644 index 54261265c7..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/android.jpg and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/apple.jpg b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/apple.jpg deleted file mode 100644 index 3b8da490ec..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/apple.jpg and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/noisy_grid.png b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/noisy_grid.png deleted file mode 100644 index ba6365e551..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/images/noisy_grid.png and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/index.html b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/index.html deleted file mode 100644 index 8bd82c35b3..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - Hello App Engine - - - -

Hello App Engine!

- Only authorized persons allowed! - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/js/main.js b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/js/main.js deleted file mode 100644 index 137f2cd88d..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/js/main.js +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Show a given element. It basically consists of removing the "hidden" class. - @param id the id of the DOM element to show - */ -function showDOMEl(id) { - document.getElementById(id).className = - document.getElementById(id).className.replace - ( /(?:^|\s)hidden(?!\S)/g , '' ); -} - -/** - * Hide a given element. It basically consists of adding the "hidden" class. - @param id the id of the DOM element to show - */ -function hideDOMEl(id) { - document.getElementById(id).className += "hidden"; -} - -/** - * Toggle the status of the element. - * Ex.: if the element is shown, hide it. And Viceversa. - * @param id the id of the DOM element to toggle - */ -function toggleDOMEl(id) { - if (document.getElementById(id).className.match(/(?:^|\s)hidden(?!\S)/)) { - showDOMEl(id); - } else { - hideDOMEl(id); - } -} - -/** - * Change the form action and register the sensor to be monitored. - */ -function registerForAlert(id) { - // change form action - f = document.getElementById("measureAdd" + id); - f.action = "addAlertMonitor"; - // remove required attribute from value, it's not needed for this action - var v = document.getElementById("value" + id); - v.required = false; - f.submit(); -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarms.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarms.jsp deleted file mode 100644 index 0224e69131..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarms.jsp +++ /dev/null @@ -1,44 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java"%> -<%@ page import="fr.eurecom.senml.entity.IZone"%> -<%@ page import="fr.eurecom.senml.entity.IZoneAdmin"%> -<%@ page import="fr.eurecom.senml.entity.ISensor"%> -<%@ page import="fr.eurecom.senml.entity.SensorCheckAlarm"%> -<%@ page import="java.util.List"%> -<%@ page import="java.util.Iterator"%> - - - - -Alarms - - - -
- - - - <% - List list = SensorCheckAlarm.getAllMonitoredSensors(); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - SensorCheckAlarm s = iter.next(); - %> - - - - - - - - - <% } %> -
NameMin valueMax valueJSONChangeRemove
- <%= s.getParentSensorName() %> <%= s.getMinVal() %> <%= s.getMaxVal() %>JSONEditRemove
-
- - -
Eurecom / background pattern draw - by vectorpile.com
- \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarmsJSON.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarmsJSON.jsp deleted file mode 100644 index 119c32a0b1..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/alarmsJSON.jsp +++ /dev/null @@ -1,22 +0,0 @@ -<%@ page trimDirectiveWhitespaces="true" %> -<%-- Set the content type header with the JSP directive --%> -<%@ page contentType="application/json"%> -<%-- Set the content disposition header --%> -<%response.setContentType("application/json");%> -<%@ page language="java"%> -<%@ page import="java.util.List"%> -<%@ page import="java.util.Iterator"%> -<%@ page import="org.json.JSONArray"%> -<%@ page import="fr.eurecom.senml.entity.SensorCheckAlarm"%> -<%@ page import="fr.eurecom.senml.persistence.JDOStorage"%> - - <% - JSONArray array = new JSONArray(); - List list = SensorCheckAlarm.getAllMonitoredSensors(); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - SensorCheckAlarm s = iter.next(); - array.put(s.toJSONSenML()); - } - %> -<%= array %> \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/allalarmsJSON.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/allalarmsJSON.jsp deleted file mode 100644 index 015c261e74..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/allalarmsJSON.jsp +++ /dev/null @@ -1,45 +0,0 @@ -<%@ page trimDirectiveWhitespaces="true" %> -<%-- Set the content type header with the JSP directive --%> -<%@ page contentType="application/json"%> -<%-- Set the content disposition header --%> -<%response.setContentType("application/json");%> -<%@ page language="java"%> -<%@ page import="java.util.List"%> -<%@ page import="java.util.Iterator"%> -<%@ page import="org.json.JSONArray"%> -<%@ page import="org.json.JSONObject"%> -<%@ page import="fr.eurecom.senml.entity.SensorAdmin"%> -<%@ page import="fr.eurecom.senml.entity.Measure"%> -<%@ page import="fr.eurecom.senml.entity.SensorCheckAlarm"%> -<%@ page import="fr.eurecom.senml.persistence.JDOStorage"%> - - <% - JSONArray array = new JSONArray(); - List list = SensorCheckAlarm.getAllMonitoredSensors(); - Iterator iter = list.iterator(); - while (iter.hasNext()) { - SensorCheckAlarm s = iter.next(); - SensorAdmin sensor = JDOStorage.getInstance().getById(s.getSensorKey(), SensorAdmin.class); - JSONObject element = new JSONObject(); - element.put("name", s.getParentSensorName()); - element.put("baseunit", sensor.getBaseUnit()); - element.put("monitor", s.toJSONSenML()); - - /* TODO: REMARK - CORELINKS will introduce intelligent sensors. - At that time, we'll be able to have different measures of different types - from the same sensor. - FOR NOW, 1 sensor corresponds to 1 measure of the same type, everytime! - */ - - // Retrieve value - List measures = sensor.getMeasures(); - if (measures.isEmpty()) { - System.out.println("Measures empty!"); - } else { - element.put("measure", measures.get(0).toJSONSenML()); - array.put(element); - } - } - %> -<%= array %> \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/detailzone.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/detailzone.jsp deleted file mode 100644 index 4add59fb00..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/detailzone.jsp +++ /dev/null @@ -1,357 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java"%> -<%@ page import="fr.eurecom.senml.entity.IZone"%> -<%@ page import="fr.eurecom.senml.entity.IZoneAdmin"%> -<%@ page import="fr.eurecom.senml.entity.ISensor"%> -<%@ page import="fr.eurecom.senml.entity.Measure"%> -<%@ page import="fr.eurecom.senml.entity.Units"%> -<%@ page import="fr.eurecom.senml.jspcontroller.ZoneTypes"%> -<%@ page import="java.util.List"%> - - - - -Zone Detail page - - - - <% - IZoneAdmin z = (IZoneAdmin) request.getAttribute("zone"); - List subZones = z.getSubZones(); - List sensors = z.getSensors(); - Units[] units = Units.values(); - %> -
-

- Zone: - <%=z.getName()%> - in: - <%=z.getParentZone() == null ? "" : z.getParentZone() - .getName()%> -

- Zones Full List -
-
- -
- -
- - -

- Choose a type: -

- -
- - - - - - - - - - - - - - - <% - for (IZone sz : subZones) { - %> - - - - - - - - <% - } - %> - - - - - - - - - - -
Sub Zones
NameSubZonesSensors
<%=sz.getName()%><%=sz.getSubZones().size() > 0 ? "Yes" : "No"%><%=sz.getSensors().size() > 0 ? "Yes" : "No"%>EditDelete
- - -

-
-
-
-

- -

- -
- - - - - - - - - - - - - - - - - - <% - for (ISensor s : sensors) { - %> - - - - - <% - if (s.getBaseUnit() != null) { - %> - - <% - } else { - %> - - <% - - } - String formID = "measureAdd" + s.getUUID(); - String valueID = "value" + s.getUUID(); - %> - - - - - - - <% - List measures = s.getMeasures(); - for (Measure m : measures) { - %> - - - - - - - - <% - } - } - %> - - - - - - - - - - - -
Sensors
TitleUUIDTypeBase UnitMeasures
<%=s.getTitle()%><%=s.getUUID()%><%=s.zoneType()%><%=s.getBaseUnit()%>No base unit
-
- Add the sensor to the list of monitored - sensors -
- - - -
- -

- Type: -

- - - Name: - <% - if (s.getBaseUnit() != null) { - %> -
-

-

- If not specified, the value is in the base - unit: - <%=s.getBaseUnit()%>

-

- Specify value type: -

-
- - -
When:

-
- Value - Value type: Value: -
-


Sum:

-
Delete
<%=m.toPrettyString()%><%=m.toJSONSenML().toString()%> - Delete
-
- - -
Eurecom / background pattern draw - by vectorpile.com
- \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/postvalslist.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/postvalslist.jsp deleted file mode 100644 index 66fbf527ad..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/postvalslist.jsp +++ /dev/null @@ -1,40 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ page import="fr.eurecom.senml.entity.PostValType" %> -<%@ page import="java.util.List" %> - - - -PostVal Main page - - - -

-
- - - - - - - - -<% List postvals = (List)request.getAttribute("postvalsList"); - if (postvals != null && !postvals.isEmpty()) { - for (PostValType z : postvals) { -%> - - - - -<% - } - } -%> - - -
Full list
Name Value
<%= z.getName() %> <%= z.getValue() %> @ <%= z.getTime() %>
-
- - -
Eurecom / background pattern draw by vectorpile.com
- diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/sensormonitorsjson.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/sensormonitorsjson.jsp deleted file mode 100644 index 34c0261316..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/sensormonitorsjson.jsp +++ /dev/null @@ -1,13 +0,0 @@ -<%@ page trimDirectiveWhitespaces="true" %> -<%-- Set the content type header with the JSP directive --%> -<%@ page contentType="application/json"%> -<%-- Set the content disposition header --%> -<%response.setContentType("application/json");%> -<%@ page language="java"%> -<%@ page import="fr.eurecom.senml.entity.SensorCheckAlarm"%> -<%@ page import="fr.eurecom.senml.persistence.JDOStorage"%> -<% - String sensorKey = request.getParameter("key"); - SensorCheckAlarm s = JDOStorage.getInstance().getById(sensorKey, SensorCheckAlarm.class); -%> -<%= s.toJSONSenML() %> \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/zonelist.jsp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/zonelist.jsp deleted file mode 100644 index 16e5f6e6e7..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/server-gae/restlet/war/pages/zonelist.jsp +++ /dev/null @@ -1,71 +0,0 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" %> -<%@ page import="fr.eurecom.senml.entity.IZone" %> -<%@ page import="fr.eurecom.senml.jspcontroller.ZoneTypes" %> -<%@ page import="java.util.List" %> - - - -Zone Main page - - - -
-

Supervisor Page

-

-
-

New Zone

-
-

- - -

-

Choose a type: -

-

-
-
-
- -

-
- - - - - - - - -<% List zones = (List)request.getAttribute("zoneList"); - if (zones != null && !zones.isEmpty()) { - for (IZone z : zones) { -%> - - - - - - - -<% - } - } -%> - - -
Full list
Name ParentType
<%= z.getName() %> <%= z.getParentZone() == null ? "" : z.getParentZone().getName() %> <%= z.getType() %>EditDelete
-
- - -
Eurecom / background pattern draw by vectorpile.com
- \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient deleted file mode 100644 index 29465e592a..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.cpp deleted file mode 100644 index 1d31bcf9c9..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.cpp +++ /dev/null @@ -1,251 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "cpprest/basic_types.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/uri.h" -#include - -using namespace std; -using namespace web; -using namespace web::http; -using namespace web::http::client; -using namespace utility; - -// Retrieves a JSON value from an HTTP request. -pplx::task RequestJSONValueAsync(char * url) -{ - http_client client (U(url)); - return client.request(methods::GET).then([](http_response response) -> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - ofstream myfile; - myfile.open ("outputGET.txt"); - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < StoreJSONValuePolicies(char * url, char * param1, char * param2, char * param3, char * param4) -{ - - http_client client (U(url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("pid"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < StoreJSONValuemeasurements(char * url, char * param1, char * param2, char * param3, char * param4, char * param5, char * param6) -{ - - http_client client (U(url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("key"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("type"), json::value(param3))); - putvalue.push_back(make_pair(json::value("unit"), json::value(param4))); - putvalue.push_back(make_pair(json::value("value"), json::value(param5))); - putvalue.push_back(make_pair(json::value("time"), json::value(param6))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < StoreJSONValuedecisions(char * url, char * param1, char * param2, char * param3, char * param4, char * param5) -{ - - http_client client (U(url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("did"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - putvalue.push_back(make_pair(json::value("time"), json::value(param5))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < Delete(char* url) -{ - return pplx::create_task([url] - { - http_client client(U(url)); - - return client.request(methods::DEL); - - }).then([](http_response response) - { - if(response.status_code() == status_codes::OK) - { - auto body = response.extract_string(); - - std::wcout << L"Deleted: " << body.get().c_str() << std::endl; - } - }); -} - - -int main(int argc,char *argv[]) -{ - char * policiesurl = (char*) malloc( 100 * sizeof(char) ); - strcpy(policiesurl,"http://1.gae-spectra.appspot.com/policies"); - char * measurementsurl = (char*) malloc( 100* sizeof(char) ); - strcpy(measurementsurl,"http://1.gae-spectra.appspot.com/measurements"); - char * decisionsurl = (char*) malloc( 100 * sizeof(char)); - strcpy(decisionsurl,"http://1.gae-spectra.appspot.com/decisions"); - int c; - - if (strcmp(argv[1], "GET") == 0) - { - c = atoi(argv[2]); - switch (c) - { - case 1: RequestJSONValueAsync(policiesurl).wait(); - break; - case 2: RequestJSONValueAsync(measurementsurl).wait(); - break; - case 3: RequestJSONValueAsync(decisionsurl).wait(); - break; - } - } - else if (strcmp(argv[1], "PUT") == 0) - { - c = atoi(argv[2]); - switch (c) - { - case 1: StoreJSONValuePolicies(policiesurl, argv[3], argv[4], argv[5], argv[6]).wait(); - break; - case 2: StoreJSONValuemeasurements(measurementsurl, argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]).wait(); - break; - case 3: StoreJSONValuedecisions(decisionsurl, argv[3], argv[4], argv[5], argv[6], argv[7]).wait(); - break; - } - } - else if (strcmp(argv[1], "DEL") == 0) - { - c = atoi(argv[2]); - switch (c) - { - case 1: Delete(policiesurl).wait(); - break; - case 2: Delete(measurementsurl).wait(); - break; - case 3: Delete(decisionsurl).wait(); - break; - } - } - - return 0; -} - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.java b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.java deleted file mode 100644 index 599b571ea9..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/CRMClient.java +++ /dev/null @@ -1,153 +0,0 @@ -package fr.eurecom.spectra.crrm.client; - -import java.io.IOException; - -import net.sf.json.JSONObject; -import net.sf.json.JSONSerializer; - -import org.restlet.Context; -import org.restlet.data.MediaType; -import org.restlet.ext.json.JsonRepresentation; -import org.restlet.representation.Representation; -import org.restlet.resource.ClientResource; -import org.restlet.resource.ResourceException; - -import com.google.gson.Gson; - -import fr.eurecom.spectra.crrm.entities.Decision; -import fr.eurecom.spectra.crrm.entities.Measurement; -import fr.eurecom.spectra.crrm.entities.Policy; - -public class CRMClient { - - private static final String BASE_URL = "http://1.gae-spectra.appspot.com/"; - - // http://localhost:8888/ - public static void main(String[] args) throws IOException, - ResourceException { - - final Context context = new Context(); - - // Define our Restlet client resources policies. - ClientResource policiesResource = new ClientResource(context, - BASE_URL + "policies"); - ClientResource policyResource = null; - - // Define our Restlet client resources measurements. - ClientResource measurementsResource = new ClientResource( - context, BASE_URL + "measurements"); - ClientResource measurementResource = null; - - // Define our Restlet client resources decisions. - ClientResource decisionsResource = new ClientResource( - context, BASE_URL + "decisions"); - ClientResource decisionResource = null; - - context.getParameters().set("maxConnectionsPerHost", "20"); - - // Create a new Policy - Policy p = new Policy("p1", "priority.", - "Priority of the user on the secondary user", 1); - - Gson gson = new Gson(); - String myp = gson.toJson(p); - - JSONObject jObject = (JSONObject) JSONSerializer.toJSON(myp); - Representation entity = new JsonRepresentation(jObject); - entity.setMediaType(MediaType.APPLICATION_JSON); - policiesResource.setRequestEntityBuffering(true); - Representation reply = policiesResource.post(entity, - MediaType.APPLICATION_JSON); - policiesResource.release(); - // Create a new measurement - Measurement m1 = new Measurement("m1", "SNIR", - "the signal noise interference ratio", 1, - "Physical measurement"); - - Gson gson2 = new Gson(); - String mym = gson2.toJson(m1); - JSONObject jObject2 = (JSONObject) JSONSerializer.toJSON(mym); - Representation entity2 = new JsonRepresentation(jObject2); - entity2.setMediaType(MediaType.APPLICATION_JSON); - measurementsResource.setRequestEntityBuffering(true); - Representation reply2 = measurementsResource.post(entity2, - MediaType.APPLICATION_JSON); - - // Create a new Decision - Decision d1 = new Decision("md1", "Band", - "the allocated band for the UE", 2, 10); - Gson gson3 = new Gson(); - String myd = gson3.toJson(d1); - JSONObject jObject3 = (JSONObject) JSONSerializer.toJSON(myd); - Representation entity3 = new JsonRepresentation(jObject3); - entity2.setMediaType(MediaType.APPLICATION_JSON); - decisionsResource.setRequestEntityBuffering(true); - Representation reply3 = decisionsResource.post(entity3, - MediaType.APPLICATION_JSON); - - if (policiesResource.getStatus().isSuccess()) { - policyResource = new ClientResource(context, - reply.getLocationRef() + "/" + p.getpID()); - - policiesResource.get(MediaType.APPLICATION_JSON); - if (policiesResource.getStatus().isSuccess() - && policiesResource.getResponseEntity() - .isAvailable()) { - - Representation rep = policiesResource - .getResponseEntity(); - Gson gtest = new Gson(); - String text = rep.getText(); - Policy[] ptest = gtest.fromJson(text, Policy[].class); - System.out.println("Extracted Policy " - + ptest[0].getpID()); - } - - } - // policiesResource.release(); - policiesResource.delete(); - measurementsResource.delete(); - decisionsResource.delete(); - } - - /** - * Prints the resource's representation. - * - * @param clientResource - * The Restlet client resource. - * @throws IOException - * @throws ResourceException - */ - public static void get(ClientResource clientResource) - throws IOException, ResourceException { - clientResource.get(MediaType.APPLICATION_JSON); - if (clientResource.getStatus().isSuccess() - && clientResource.getResponseEntity().isAvailable()) { - clientResource.get(MediaType.APPLICATION_JSON).write( - System.out); - // clientResource.getResponseEntity().write(System.out); - } - } - - /** - * Returns the Representation of an item. - * - * @param item - * the item. - * - * @return The Representation of the item. - * @throws IOException - */ - public static Representation getRepresentation(Policy p) - throws IOException { - - Gson gson = new Gson(); - String myp = gson.toJson(p); - - JSONObject js = (JSONObject) JSONSerializer.toJSON(myp); - Representation entity = new JsonRepresentation(js); - entity.setMediaType(MediaType.APPLICATION_JSON); - return entity; - } - -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/README b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/README deleted file mode 100644 index 6fba212daf..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/README +++ /dev/null @@ -1,26 +0,0 @@ -Two CRM clients are provided: - -1)The C++ client: - -Files -source: CRMClient.cpp -binary: CRMClient - -to execute the C++ CRM client: - -./CRMClient arg1 arg2 arg3 arg4 arg5.. - -arg1= "GET" if the operation is a GET from the server - "PUT" if the operation is a PUT to the sever - "DEL" if the opertion is a DEL in the server - -arg2= 1 if the operation is on the POLICIES - = 2 if the operation is on the MEASUREMENTS - = 3 if the operation is on the DECISIONS - -arg3 arg4.. are the parameters of each entity (Policy has 4 arguments, Measurement has 6 arguments, Decision has 5 arguments) - -2)An example of a JAVA Client - -Files -source: CRMClient.java diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/del_rules_on_server.sh b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/del_rules_on_server.sh deleted file mode 100644 index 200b12245e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/del_rules_on_server.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -./CRMClient DEL 1 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/put_rules_on_server.sh b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/put_rules_on_server.sh deleted file mode 100644 index b8899f5933..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/CRM/tosend/put_rules_on_server.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -./CRMClient PUT 1 p10 Fairness "Fairness among secondary users" 1 -./CRMClient PUT 1 p11 Priority "Priority of primary users against secondary users" 1 -./CRMClient PUT 1 p12 Pdetection "Probability of detection threshold" 3 -./CRMClient PUT 1 p14 Pfalse "Probability of false alarms trheshold" 5 - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/client b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/client deleted file mode 100644 index ad427a11b4..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/client and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/server b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/server deleted file mode 100644 index 8bea168ace..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/server and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra.h b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra.h deleted file mode 100644 index 92a8c20301..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * spectra.h - * - * Helper functions for the test server program. The functions are as - * close as possible to the ones used in the real server implementation - * that is supposed to be running in the board. - * - * Created on: Jun 26, 2014 - * Author: camara - * Copyright (c) 2008-2014 Institut Mines-Telecom / Telecom ParisTech - */ - -#ifndef SPECTRA_H_ -#define SPECTRA_H_ -#include - -#define IP_ADDRESS "10.42.0.104" -#define IP_MASK "255.255.255.0" -#define PORT 4546 - -/** - * Maximum packet size, dependent on the size of the - * number of elements field on the header, at the present 8 bits - * i.e. (256 * 4 bytes + the header that is 4 bytes) - */ -#define MAX_PACKET_SIZE 1028 - -/** - * Aligns packet, internally, into 32 bits, or 4 bytes - */ -#define PACKET_ALIGNEMENT_BYTES 4 - -//#define DEBUG -#ifdef DEBUG -#define PRINTD printf("-> %s:%d: ", __FUNCTION__, __LINE__); printf -#else -#define PRINTD(format, args...) ((void)0) -#endif - -/** - * Which is the type of the message, if it is, for example, an start sensing, - * or an answer to a previously requested score - */ -typedef enum { - Sense, //!< Sense - Classifying, //!< Classifying - ScoreResponse, //!< ScoreResponse - EndProcessing -} messageType; - -/** - * Which is the functions that should be performed by the embb - */ - -//! An enum. -/*! More detailed enum description. */ -typedef enum { - EnergyDetection, //!< EnergyDetection - WelchPeriodograms //!< WelchPeriodograms -} functionToBePerformed; - -/** - * Definition of the spectra control packets - */ -typedef struct { - uint16_t messageID; //!< Operation ID, used to identify an request and its answer - messageType type :4; //!< 16 different types of message possible - functionToBePerformed function :4; //!< Embb function to be performed 16 possible different functions - unsigned char numberOfparameters; //!< up to 255 parameters per message - uint32_t * parameters; //!< variable number of parameters, depending -} __attribute__((packed)) SpectraMessage; - -/** - * \typedef SpectraMsgHelper - * Helper structure to handle control packets - */ -typedef struct { - uint16_t messageID; //!< Operation ID - unsigned char type_function; //!< Assembled type and function for easier treatment - unsigned char numberOfparameters; //!< Number of parameters - uint32_t parameters[256]; //!< Parameters in sequence -} __attribute__((packed)) SpectraMsgHelper; - -/** - * Helper union structure to make easier to pack and unpack messages - */ -union uSpectraPackets { - SpectraMessage spectraMsg; //!< spectraMsg - SpectraMsgHelper spectraMsgHelper; //!< spectraMsgHelper - unsigned char spectraMsgStream[MAX_PACKET_SIZE]; //!< spectraMsgStream -}; - -union FuncPtr { - void (*fp)(); // function pointer - unsigned char c[1]; // address of the pointer as a vector of chars -}; - - -/** - * Serialize and send packet over the indicated socket - * - * @param sock - in use socket descriptor - * @param msg - message to be transmitted - * @return error status 0 if OK, 1 if something went wrong - */ -int returnSpectraPacket(SpectraMsgHelper msg, - int desc, - struct sockaddr remote) -{ - - int i; - - // returns the response value to the OpenAirInterface - if ((i = sendto(desc,&msg, PACKET_ALIGNEMENT_BYTES + (msg.numberOfparameters * sizeof(uint32_t)), - 0, &remote, sizeof(remote)))<0) { - printf("Send failed (%i - %s)\n", i, strerror(errno)); - return -1; - } - - // // to avoid memory leaking - // free(msg.parameters); - return 0; -} - -/** - * Verifies if the machine architecture is big endian - * - * @return true if the machine architecture is big endian - */ -int isBigEndian(void) -{ - union { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0]; -} - -/** - * Network order, byte swap function for 64bits size numbers - * - * @param value - the 64 bits number to swap, depending on the architecture - * @return the same value in the network order - */ -uint64_t htonll(uint64_t value) -{ - // Check the endianness - if (!isBigEndian()) { - uint32_t high_part = htonl((uint32_t)(value >> 32)); - uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFULL)); - value = low_part & 0xffffffffULL; - value = (value<<32) | high_part; - value = (uint64_t)(((uint64_t)low_part) << 32) | high_part; - return (uint64_t)(((uint64_t)low_part) << 32) | high_part; - } else { - return value; - } -} - -/** - * Host order, byte swap function for 64bits size numbers - * - * @param value - the 64 bits number to swap, depending on the architecture - * @return the same value in the host order - */ -uint64_t ntohll(uint64_t value) -{ - - // Check the endianness - if (!isBigEndian()) { - uint32_t high_part = ntohl((uint32_t)(value >> 32)); - uint32_t low_part = ntohl((uint32_t)(value & 0xFFFFFFFFULL)); - - return (uint64_t)(((uint64_t)low_part) << 32) | high_part; - } else { - return value; - } -} - -#endif /* SPECTRA_H_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectraClient b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectraClient deleted file mode 100644 index bfe90331b3..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectraClient and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.c b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.c deleted file mode 100644 index 68f93fd6e3..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * spectra_client.c - * - * Client part of the spectra demo control system. It is - * supposed to run on the OpenAirInterface machine that - * will send commands to configure Embb and collect the - * answers sent by the Embb "server", running on the - * board. - * - * Considering this compiled with gcc -o spectraClient spectra_client.c. - * - * Use: spectraClient [server IP] [port] [nSamples] - * e.g: spectraClient 127.0.0.1 4546 10 - * - This will tell the client to try to find the server in the - * address 127.0.0.1 at the port 4546 and that the score should be - * calculated over 10 samples. - * - * Created on: Dec 11, 2013 - * Author: camara - * Copyright (c) 2008-2014 Institut Mines-Telecom / Telecom ParisTech - */ -#include // printf -#include // strlen -#include // close -#include // socket -#include // inet_addr -#include // malloc -#include "spectra_client.h" // The types and generic functions of spectra - -/** - * Creates the test message - * - * @param id messsage identificatior - * @return example message - */ -SpectraMessage createTestMessageClient(int id, int type, int nSamples) { - SpectraMessage msg; - - msg.type = type; - msg.function = EnergyDetection; - msg.messageID = id; - msg.numberOfparameters = 1; - - msg.parameters = malloc(msg.numberOfparameters * sizeof(uint32_t)); - msg.parameters[0] = nSamples; - - return msg; -} - -/** - * Creates the socket and connects to the server - * - * @return - the socket descriptor - */ -int createsSocket(int argc, char *argv[]) { - int sock; - struct sockaddr_in server; - //Create socket - - sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - - if (sock == -1) { - printf("Could not create socket"); - return -1; - } - - puts("Socket created"); - - // treats the parameters - if (argc >= 2) - server.sin_addr.s_addr = inet_addr(argv[1]); - else - server.sin_addr.s_addr = inet_addr(SERVER_ADDRESS); - - server.sin_family = AF_INET; - - if (argc >= 3) - server.sin_port = htons(atoi(argv[2])); - else - server.sin_port = htons(CONNECTION_PORT); - - printf("Target address: %s, port %d : addr\n", inet_ntoa(server.sin_addr), - server.sin_port); - - //Connect to remote server - if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { - perror("connect failed. Error"); - return -2; - } - - puts("Connected\n"); - return sock; -} - -/** - * Main function for the client - * - * @param argc - * @param argv - * @return - */ -int main(int argc, char *argv[]) { - char server_reply[MAX_PACKET_SIZE]; - int nSamples = 10; - - int sock = createsSocket(argc, argv), id; - - if (argc >= 4) - nSamples = atoi(argv[3]); - - if (sock < 0) - return sock; - - int type = Classifying; - - // Just for test purposes send 2 packets to the server, changing only the packet id - for (id = 33; id < 36; ++id) { - printf("-->\nSending message ID : %d\n", id); - - if (id == 35) - type = EndProcessing; - - SpectraMessage message = createTestMessageClient(id, type, nSamples); - - //Send some data - if (sendClientSpectraPacket(sock, message) != 0) { - return 1; - } - - //Receive a reply from the server - if (recv(sock, server_reply, MAX_PACKET_SIZE, 0) < 0) { - puts("recv failed"); - break; - } - - printf("<--\nServer reply :\n"); - printReturnValueMessage(assembleMessage(&server_reply)); - } - - close(sock); - return 0; -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.h b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.h deleted file mode 100644 index d63705ddd7..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_client.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * spectra_client.h - * - * Generic functions and types for the spectra demonstration - * control system. These functions are used by the client side. - * - * Created on: Dec 11, 2013 - * Author: camara - * Copyright (c) 2008-2014 Institut Mines-Telecom / Telecom ParisTech - */ - -#ifndef SPECTRA_H_ -#define SPECTRA_H_ - -/** - * The IP address of the Embb server (e.g the Embb board) - */ -//#define SERVER_ADDRESS "192.168.0.2" -#define SERVER_ADDRESS "127.0.0.1" - -/** - * Connection port - */ -#define CONNECTION_PORT 4546 - -/** - * Alinges packet, internally, into 32 bits, or 4 bytes - */ -#define PACKET_ALIGNEMENT_BYTES 4 - -/** - * Maximum packet size, dependent on the size of the - * number of elements field on the header, at the present 8 bits - * i.e. (256 * 4 bytes + the header that is 4 bytes) - */ -#define MAX_PACKET_SIZE 1028 - -/** - * Which is the type of the message, if it is, for example, an start sensing, - * or an answer to a previously requested score - */ -typedef enum { - Sense, //!< Sense - Classifying, //!< Classifying - ScoreResponse, //!< ScoreResponse - EndProcessing -} messageType; - -/** - * Which is the functions that should be performed by the embb - */ -//! An enum. -/*! More detailed enum description. */ -typedef enum { - EnergyDetection, //!< EnergyDetection - WelchPeriodograms //!< WelchPeriodograms -} functionToBePerformed; - -/** - * Definition of the spectra control packets - */ -typedef struct { - uint16_t messageID; //!< Operation ID, used to identify an request and its answer - messageType type :4; //!< 16 different types of message possible - functionToBePerformed function :4; //!< Embb function to be performed 16 possible different functions - unsigned char numberOfparameters; //!< up to 255 parameters per message - uint32_t * parameters; //!< variable number of parameters, depending - //!< on what we are doing and the default values -} __attribute__((packed)) SpectraMessage; - -/** - * \typedef SpectraMsgHelper - * Helper structure to handle control packets - */ -typedef struct { - uint16_t messageID; //!< Operation ID - unsigned char type_function; //!< Assembled type and function for easier treatment - unsigned char numberOfparameters; //!< Number of parameters - // uint32_t parameter; //!< Parameters in sequence - uint32_t parameters[256]; //!< Parameters in sequence -} __attribute__((packed)) SpectraMsgHelper; - -/** - * Helper union structure to make easier to pack and unpack messages - */ -union uSpectraPackets { - SpectraMessage spectraMsg; //!< spectraMsg - SpectraMsgHelper spectraMsgHelper; //!< spectraMsgHelper - unsigned char spectraMsgStream[MAX_PACKET_SIZE]; //!< spectraMsgStream -}; - -/** - * Verifies if the machine architecture is big endian - * - * @return true if the machine architecture is big endian - */ -int isBigEndian(void) -{ - union { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0]; -} - -/** - * Network order, byte swap function for 64bits size numbers - * - * @param value - the 64 bits number to swap, depending on the architecture - * @return the same value in the network order - */ -uint64_t htonll(uint64_t value) -{ - // Check the endianess - if (!isBigEndian()) { - uint32_t high_part = htonl((uint32_t)(value >> 32)); - uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFULL)); - return (uint64_t)(((uint64_t)low_part) << 32) | high_part; - } else { - return value; - } -} - -/** - * Host order, byte swap function for 64bits size numbers - * - * @param value - the 64 bits number to swap, depending on the architecture - * @return the same value in the host order - */ -uint64_t ntohll(uint64_t value) -{ - - // Check the endianess - if (!isBigEndian()) { - uint32_t high_part = ntohl((uint32_t)(value >> 32)); - uint32_t low_part = ntohl((uint32_t)(value & 0xFFFFFFFFULL)); - - return (uint64_t)(((uint64_t)low_part) << 32) | high_part; - } else { - return value; - } -} - - -/** - * Serialize and send packet over the indicated socket - * - * @param sock - in use socket descriptor - * @param msg - message to be transmitted - * @return error status 0 if OK, 1 if something went wrong - */ -int sendClientSpectraPacket(int sock, SpectraMessage msg) -{ - int i; - union uSpectraPackets toTransmitPacket; - toTransmitPacket.spectraMsg = msg; - - // Puts the values bigger than one byte on Internet format - toTransmitPacket.spectraMsgHelper.messageID = htons(msg.messageID); - - toTransmitPacket.spectraMsgHelper.type_function = (msg.type << 4) | msg.function; - - for (i = 0; i < msg.numberOfparameters; i++) { - toTransmitPacket.spectraMsgHelper.parameters[i] = htonl(msg.parameters[i]); - printf("Value %d=%d\n", i, htonl(msg.parameters[i])); - } - - // sends the package - if ( (i = send(sock, toTransmitPacket.spectraMsgStream, PACKET_ALIGNEMENT_BYTES + (msg.numberOfparameters * sizeof(uint32_t)), 0)) < 0) { - printf("Send failed (%i)\n", i); - // to avoid memory leaking - free(msg.parameters); - return -1; - } - - int k = (int)(PACKET_ALIGNEMENT_BYTES + (msg.numberOfparameters * sizeof(uint32_t))); - printf("Sent message size: %d\n >", k); - - for (i=0; i>4; - returnMessage.function = (((*(SpectraMsgHelper*) var).type_function << 4)>>4) & 0xF; - returnMessage.numberOfparameters = nParameters; - - for (i = 0; i < nParameters; i++) { - returnMessage.parameters[i] = (*(SpectraMsgHelper*) var).parameters[i]; - } - - return returnMessage; -} - -/** - * Prints the test message, only for debugging purposes - * - * @param msg - message to print the components - */ -void printReturnValueMessage(SpectraMessage msg) -{ - // int i; - - printf("msg.messageID: %d\n", msg.messageID); - printf("msg.type: %d\n", msg.type); - printf("msg.function: %d\n", msg.function); - // printf("msg.numberOfparameters: %d\n", msg.numberOfparameters); - // for (i = 0; i < msg.numberOfparameters; i++) { - // printf("[%d] parameters: %d\n", i, msg.parameters[i]); - // } - - // To transform the 2x32bits in on 64bits value - uint64_t realValue = (uint64_t)(((uint64_t)msg.parameters[0]) << 32) | msg.parameters[1]; - - printf("packet value: 0x%016llx\n", (long long int)realValue); - printf("Network to host value: 0x%016llx\n", (long long int)ntohll(realValue)); - printf("SCORE: %lld\n", (long long int)ntohll(realValue)); -} - -#endif /* SPECTRA_H_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_deamon.c b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_deamon.c deleted file mode 100644 index e3c0a8b2d3..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/client/spectra_deamon.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * spectra_deamon.c - * - * Server part of the spectra demo control system. - * - * The real code is supposed to run on the board waiting from the - * OpenAirInterface configuration messages. This is just a "stub" - * version of the real server. It emulates the behavior of the - * server for tests purposes only. It has a list of scores that - * it plays over and over. - * - * Created on: Dec 11, 2013 - * Author: camara - * Copyright (c) 2008-2014 Institut Mines-Telecom / Telecom ParisTech - */ - -#include -#include //strlen -#include //malloc -#include -#include //inet_addr -#include //write -#include //for threading , link with lpthread -#include "spectra.h" // The types and generic functions of spectra - -/** - * List of fake scores that will be sent to the application - */ -uint64_t scoresList[] = { - 81886716, - 94073410, - 147421016, - 117364836, - 104805562, - 142811370, - 107986264, - 100032514 -}; - -/** - * Index of the score to send - */ -int scoreIndex = 0; - -/** - * Creates the return packet - * - * Fills the packet that will be returned to the OpenAir interface with the - * score or with the end of connection - * - * @param request - The original request message - * @param score - The score value - * @param request - The type of this message - * - * @return - A new spectra message filled with the right fields - */ -SpectraMsgHelper createReturnPacket(SpectraMessage* request, uint64_t score, - messageType type) -{ - SpectraMsgHelper returnMessage; - - returnMessage.messageID = htons(request->messageID); // copy the request id - returnMessage.type_function = (type << 4) | request->function; - returnMessage.numberOfparameters = 2; // it is a 64bits number (2 x uint32_t) - score = htonll(score); - returnMessage.parameters[0] = score >> 32; // the score number to send back but it is a 64 bit - returnMessage.parameters[1] = score & 0xFFFFFFFFULL; - - return returnMessage; -} - -/** - * Assemble the packet from the raw input packet - * @param var - void pointer to the memory area the message is stored - * @return a formated Spectra message - */ -SpectraMessage assembleMessage(void * var) -{ - int i; - SpectraMessage returnMessage; - char nParameters = (*(SpectraMessage*) var).numberOfparameters; - - // Alocates enough memory area for the variable parameters field - returnMessage.parameters = malloc(nParameters * sizeof(uint32_t)); - - returnMessage.messageID = ntohs((*(SpectraMessage*) var).messageID); - returnMessage.type = ((*(SpectraMsgHelper*) var).type_function) >> 4; - returnMessage.function = (((*(SpectraMsgHelper*) var).type_function << 4)>> 4) & 0xF; - returnMessage.numberOfparameters = nParameters; - - for (i = 0; i < nParameters; i++) { - returnMessage.parameters[i] = (*(SpectraMsgHelper*) var).parameters[i]; - } - - return returnMessage; -} - -/** - * Responsible for handling the client connections - * - * @param sock - socket descriptor - */ -void *connection_handler(int fd) -{ - SpectraMessage request; // received message in the spectra format - SpectraMsgHelper returnMessage; // message in the format we want to send - char rawPacket[MAX_PACKET_SIZE]; // raw packet - struct sockaddr remaddr; // remote address - socklen_t addrlen = sizeof(remaddr); // length of addresses - int recvlen; // # bytes received - int i=0; - - /* now loop, receiving data and printing what we received */ - for (;;) { - printf("\n[SPECTRA Sensing Module] Started!\n[SPECTRA Sensing Module] ---\n[SPECTRA Sensing Module] Waiting on port %d\n", PORT); - recvlen = recvfrom(fd, rawPacket, MAX_PACKET_SIZE, 0, - (struct sockaddr *) &remaddr, &addrlen); - printf("\n[SPECTRA Sensing Module] Received Data (%d bytes) > ", recvlen); - - for (i=0; i Received spectra packet %i of type %i for function %i with %i parameters\n", - request.messageID, - (uint32_t) request.type, (uint32_t) request.function, - (uint32_t) request.numberOfparameters); - - // Process the requested operation - if (request.type == EndProcessing) { - - returnMessage = createReturnPacket(&request, 0, EndProcessing); - printf("\n[SPECTRA Sensing Module] Received: End of cognitive algorithm processing!\n"); - fflush(stdout); - } else { - if (request.function == EnergyDetection) { - - // circular loop over the score list - scoreIndex = (scoreIndex < (sizeof(scoresList)/ sizeof(scoresList[0]))) ? - scoreIndex : 0; - printf("\n[SPECTRA Sensing Module] Received: Energy Detection Request!\n"); - printf("\n[SPECTRA Sensing Module] Processing Score value: %16llx (%lld)\n", - (long long int)scoresList[scoreIndex], - (long long int)scoresList[scoreIndex]); - printf("\n[SPECTRA Sensing Module] Processing Score host to network value: 0x%016llx (%lld)\n", - (long long int)htonll(scoresList[scoreIndex]), - (long long int)htonll(scoresList[scoreIndex])); - - returnMessage = createReturnPacket(&request, - scoresList[scoreIndex++], ScoreResponse); - } - } - - // Sends the answer - printf("\n[SPECTRA Sensing Module] Sending: Reply Message!\n"); - int retError = returnSpectraPacket(returnMessage, fd, remaddr); - - if (retError == -1) { - perror("Send failed!!!\n"); - } - - // If the command was an end processing exits!! - if (request.type == EndProcessing) { - break; - } - - free(request.parameters); - } - - } - - //Free the socket pointer - close(fd); - return 0; -} - -/** - * Creates the socket and binds it to the defined port - * - * @return the socket descriptor - */ -int socketBind() -{ - - struct sockaddr_in myaddr; /* our address */ - // struct sockaddr_in remaddr; /* remote address */ - int fd; /* our socket */ - - /* create a UDP socket */ - - if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { - perror("cannot create socket\n"); - return 0; - } - - /* bind the socket to any valid IP address and a specific port */ - memset((char *) &myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; - myaddr.sin_addr.s_addr = htonl(INADDR_ANY); - myaddr.sin_port = htons(PORT); - - if (bind(fd, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { - perror("bind failed"); - return 0; - } - - puts("\n[SPECTRA Sensing Module] Initialization done"); - return fd; -} - -/** - * The main function for the server - * - * @param argc - * @param argv - * @return - */ -int main(int argc, char *argv[]) -{ - // int client_sock; - int socket_desc; - - socket_desc = socketBind(); - connection_handler(socket_desc); - - return 0; -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/clientToFatma.zip b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/clientToFatma.zip deleted file mode 100644 index a9539173e6..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/clientSensing/clientToFatma.zip and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/0001-SPECTRA-patch-for-ODTONE-v0.1.patch b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/0001-SPECTRA-patch-for-ODTONE-v0.1.patch deleted file mode 100644 index 73c6bf9a8c..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/0001-SPECTRA-patch-for-ODTONE-v0.1.patch +++ /dev/null @@ -1,17622 +0,0 @@ -From e4048b1089cb2dff78898358d6de7638554bf204 Mon Sep 17 00:00:00 2001 -From: nikaia -Date: Wed, 17 Sep 2014 17:27:20 +0200 -Subject: [PATCH] SPECTRA patch for ODTONE v0.1 - ---- - app/lte_test_user/CRMClient.cpp | 260 +++++ - app/lte_test_user/CRMClient.hpp | 94 ++ - app/lte_test_user/Jamfile | 44 + - app/lte_test_user/Makefile | 19 + - app/lte_test_user/eNB_lte_user_tcs.cpp | 1412 ++++++++++++++++++++++++++ - app/lte_test_user/enb_lte_user.conf | 40 + - app/lte_test_user/enb_lte_user.cpp | 1695 ++++++++++++++++++++++++++++++++ - app/lte_test_user/libcrmclient.so.1.0 | Bin 0 -> 2273132 bytes - app/lte_test_user/ue_lte_user.conf | 42 + - app/lte_test_user/ue_lte_user.cpp | 1399 ++++++++++++++++++++++++++ - boost-build.jam | 1 + - inc/odtone/conf.hpp | 670 +++++++++++++ - inc/odtone/mih/detail/archive.hpp | 142 +++ - inc/odtone/mih/types/address.hpp | 19 +- - inc/odtone/mih/types/bin_query.hpp | 1 + - inc/odtone/mih/types/link.hpp | 419 ++++++-- - lib/odtone/CMakeLists.txt | 1 + - lib/odtone/Jamfile | 3 +- - lib/odtone/conf.cpp | 43 + - src/mihf/command_service.cpp | 1 + - src/mihf/dst_transaction.cpp | 7 + - src/mihf/event_service.cpp | 16 +- - src/mihf/link_book.cpp | 59 +- - src/mihf/main.cpp | 32 +- - src/mihf/service_access_controller.cpp | 6 +- - src/mihf/service_management.cpp | 1 + - src/mihf/src_transaction.cpp | 7 + - src/mihf/transaction_pool.cpp | 7 + - 28 files changed, 6366 insertions(+), 74 deletions(-) - create mode 100644 app/lte_test_user/CRMClient.cpp - create mode 100644 app/lte_test_user/CRMClient.hpp - create mode 100644 app/lte_test_user/Jamfile - create mode 100644 app/lte_test_user/Makefile - create mode 100644 app/lte_test_user/eNB_lte_user_tcs.cpp - create mode 100644 app/lte_test_user/enb_lte_user.conf - create mode 100644 app/lte_test_user/enb_lte_user.cpp - create mode 100644 app/lte_test_user/libcrmclient.so.1.0 - create mode 100644 app/lte_test_user/ue_lte_user.conf - create mode 100644 app/lte_test_user/ue_lte_user.cpp - create mode 100644 boost-build.jam - create mode 100644 inc/odtone/conf.hpp - create mode 100644 lib/odtone/conf.cpp - -diff --git a/app/lte_test_user/CRMClient.cpp b/app/lte_test_user/CRMClient.cpp -new file mode 100644 -index 0000000..8e384e7 ---- /dev/null -+++ b/app/lte_test_user/CRMClient.cpp -@@ -0,0 +1,260 @@ -+#include -+#include -+#include -+#include -+#include -+#include -+#include "cpprest/basic_types.h" -+#include "cpprest/asyncrt_utils.h" -+#include "cpprest/uri.h" -+#include -+ -+#include "CRMClient.hpp" -+ -+using namespace std; -+using namespace web; -+using namespace web::http; -+using namespace web::http::client; -+using namespace utility; -+ -+ -+CRMClient::CRMClient(char* url) -+{ -+ m_url = (char*) (malloc (200* sizeof (char))); -+ m_url = url; -+} -+ -+CRMClient::CRMClient() -+{ -+} -+ -+CRMClient::~CRMClient() -+{ -+} -+ -+void CRMClient::SetUrl(char* url) -+{ -+ m_url = url; -+} -+ -+ -+/****************************************************** -+* Retrieves a JSON value from an HTTP request -+* The JSON value is stored in the file "outputGET.txt" -+*******************************************************/ -+ -+pplx::task CRMClient::RequestJSONValueAsync() -+{ -+ http_client client (U(m_url)); -+ return client.request(methods::GET).then([](http_response response) -> pplx::task -+ { -+ if(response.status_code() == status_codes::OK) -+ { -+ return response.extract_json(); -+ } -+ -+ return pplx::task_from_result(json::value()); -+ }) -+ .then([](pplx::task previousTask) -+ { -+ try -+ { -+ ofstream myfile; -+ myfile.open ("outputGET.txt"); -+ const json::value& v = previousTask.get(); -+ string_t jsonString = v.to_string(); -+ cout << U("Response...") << jsonString <second; -+ -+ for(auto iterInner = arrayValue.cbegin(); iterInner != arrayValue.cend(); ++iterInner) -+ { -+ const json::value &propertyValue = iterInner->second; -+ for(auto iterlast = propertyValue.cbegin(); iterlast != propertyValue.cend(); ++iterlast) -+ { -+ const json::value &Name = iterlast->first; -+ const json::value &Value = iterlast->second; -+ cout<< U("Parameter: ") << Name.to_string()< CRMClient::StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4) -+{ -+ http_client client (U(m_url)); -+ json::value::field_map putvalue; -+ -+ putvalue.push_back(make_pair(json::value("pid"), json::value(param1))); -+ putvalue.push_back(make_pair(json::value("name"), json::value(param2))); -+ putvalue.push_back(make_pair(json::value("description"), json::value(param3))); -+ putvalue.push_back(make_pair(json::value("value"), json::value(param4))); -+ -+ const string_t& s = "/"; -+ json::value object = json::value::object(putvalue); -+ return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task -+ { -+ if(response.status_code() == status_codes::OK) -+ { -+ return response.extract_json(); -+ } -+ -+ return pplx::task_from_result(json::value()); -+ }) -+ .then([](pplx::task previousTask) -+ { -+ try -+ { -+ const json::value& v = previousTask.get(); -+ string_t jsonString = v.to_string(); -+ cout << U("Response...") << jsonString < CRMClient::StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6) -+{ -+ -+ http_client client (U(m_url)); -+ json::value::field_map putvalue; -+ -+ putvalue.push_back(make_pair(json::value("key"), json::value(param1))); -+ putvalue.push_back(make_pair(json::value("name"), json::value(param2))); -+ putvalue.push_back(make_pair(json::value("type"), json::value(param3))); -+ putvalue.push_back(make_pair(json::value("unit"), json::value(param4))); -+ putvalue.push_back(make_pair(json::value("value"), json::value(param5))); -+ putvalue.push_back(make_pair(json::value("time"), json::value(param6))); -+ -+ const string_t& s = ""; -+ json::value object = json::value::object(putvalue); -+ return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task -+ { -+ if(response.status_code() == status_codes::OK) -+ { -+ return response.extract_json(); -+ } -+ -+ return pplx::task_from_result(json::value()); -+ }) -+ .then([](pplx::task previousTask) -+ { -+ try -+ { -+ const json::value& v = previousTask.get(); -+ string_t jsonString = v.to_string(); -+ cout << U("Response...") << jsonString < CRMClient::StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5) -+{ -+ -+ http_client client (U(m_url)); -+ json::value::field_map putvalue; -+ -+ putvalue.push_back(make_pair(json::value("did"), json::value(param1))); -+ putvalue.push_back(make_pair(json::value("name"), json::value(param2))); -+ putvalue.push_back(make_pair(json::value("description"), json::value(param3))); -+ putvalue.push_back(make_pair(json::value("value"), json::value(param4))); -+ putvalue.push_back(make_pair(json::value("time"), json::value(param5))); -+ -+ const string_t& s = "/"; -+ json::value object = json::value::object(putvalue); -+ return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task -+ { -+ if(response.status_code() == status_codes::OK) -+ { -+ return response.extract_json(); -+ } -+ -+ return pplx::task_from_result(json::value()); -+ }) -+ .then([](pplx::task previousTask) -+ { -+ try -+ { -+ const json::value& v = previousTask.get(); -+ string_t jsonString = v.to_string(); -+ cout << U("Response...") << jsonString < CRMClient::Delete() -+{ -+ char* url = m_url; -+ return pplx::create_task([url] -+ { -+ http_client client (U(url)); -+ -+ return client.request(methods::DEL); -+ -+ }).then([](http_response response) -+ { -+ if(response.status_code() == status_codes::OK) -+ { -+ auto body = response.extract_string(); -+ -+ std::wcout << L"Deleted: " << body.get().c_str() << std::endl; -+ } -+ }); -+} -diff --git a/app/lte_test_user/CRMClient.hpp b/app/lte_test_user/CRMClient.hpp -new file mode 100644 -index 0000000..a49f2e6 ---- /dev/null -+++ b/app/lte_test_user/CRMClient.hpp -@@ -0,0 +1,94 @@ -+//============================================================================== -+// Brief : MIH-User -+// Authors : FATMA HRIZI -+//------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2012 Universidade Aveiro -+// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//============================================================================== -+ -+#ifndef ODTONE_CRM_CLIENT_HPP -+#define ODTONE_CRM_CLIENT_HPP -+ -+ -+#include -+#include -+#include -+#include -+#include -+#include "cpprest/basic_types.h" -+#include "cpprest/asyncrt_utils.h" -+#include "cpprest/uri.h" -+#include -+ -+ -+/** -+ * CRM Client Class -+ * -+ * Defines the required functions to Get/Store Data from/in the CRRM -+ * -+ **/ -+class CRMClient { -+ -+public: -+ -+ CRMClient(); -+ CRMClient(char* url); -+ ~CRMClient(); -+ -+ void SetUrl(char* url); -+ -+ /** -+ * Get the data from the CRRM -+ * -+ * Returns JSON Format -+ */ -+ pplx::task RequestJSONValueAsync(); -+ -+ /** -+ * Store Policies data from the CRRM -+ * -+ * Takes 4 parameters: P_ID, Name, Description, Value -+ * Returns the JSON format of the stored entity -+ */ -+ pplx::task StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4); -+ -+ /** -+ * Store Measurements data from the CRRM -+ * -+ * Takes 5 parameters: M_ID, Name, Type, Unit, Value, Time -+ * Returns the JSON format of the stored entity -+ */ -+ pplx::task StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6); -+ -+ /** -+ * Store Decisions data from the CRRM -+ * -+ * Takes 4 parameters: D_ID, Name, Description, Value -+ * Returns the JSON format of the stored entity -+ */ -+ pplx::task StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5); -+ -+ -+ -+ /** -+ * Delete Entities from the CRRM -+ * -+ * Returns the JSON format of the deleted entity -+ */ -+ pplx::task Delete(); -+ -+ -+private: -+ char * m_url; -+ -+}; -+#endif -diff --git a/app/lte_test_user/Jamfile b/app/lte_test_user/Jamfile -new file mode 100644 -index 0000000..c2a6aec ---- /dev/null -+++ b/app/lte_test_user/Jamfile -@@ -0,0 +1,44 @@ -+#=============================================================================== -+# Brief : MIH-User SAP Application Sample Project Build -+# Authors : Carlos Guimaraes -+# Bruno Santos -+#------------------------------------------------------------------------------- -+# ODTONE - Open Dot Twenty One -+# -+# Copyright (C) 2009-2012 Universidade Aveiro -+# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+# -+# This software is distributed under a license. The full license -+# agreement can be found in the file LICENSE in this distribution. -+# This software may not be copied, modified, sold or distributed -+# other than expressed in the named license agreement. -+# -+# This software is distributed without any warranty. -+#=============================================================================== -+ -+project enb_lte_user -+ ; -+ -+exe enb_lte_user -+ : enb_lte_user.cpp -+ ../../lib/odtone//odtone -+ /boost//program_options -+ ; -+ -+install install -+ : enb_lte_user -+ enb_lte_user.conf -+ ue_lte_user -+ ue_lte_user.conf -+ : ../../dist -+ ; -+ -+project ue_lte_user -+ ; -+ -+exe ue_lte_user -+ : ue_lte_user.cpp -+ ../../lib/odtone//odtone -+ /boost//program_options -+ ; -+ -diff --git a/app/lte_test_user/Makefile b/app/lte_test_user/Makefile -new file mode 100644 -index 0000000..b6837ad ---- /dev/null -+++ b/app/lte_test_user/Makefile -@@ -0,0 +1,19 @@ -+main: main.cpp -+ g++-4.8 -Wall main.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -L. -std=c++11 -lcrmclient -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -o CRMClientmain -+ -+lib: CRMClient.cpp -+ -+# 64 bits compilation -+# g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -m64 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -+# g++-4.8 -shared -m64 -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o -+# ln -sf libcrmclient.so.1.0 libcrmclient.so -+# ln -sf libcrmclient.so.1.0 libcrmclient.so.1 -+ -+# 32 bits compilation -+ g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -+ g++-4.8 -shared -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o -+ ln -sf libcrmclient.so.1.0 libcrmclient.so -+ ln -sf libcrmclient.so.1.0 libcrmclient.so.1 -+ -+clean: -+ rm *.o *.so* -diff --git a/app/lte_test_user/eNB_lte_user_tcs.cpp b/app/lte_test_user/eNB_lte_user_tcs.cpp -new file mode 100644 -index 0000000..72d46e7 ---- /dev/null -+++ b/app/lte_test_user/eNB_lte_user_tcs.cpp -@@ -0,0 +1,1412 @@ -+//============================================================================== -+// Brief : MIH-User -+// Authors : Bruno Santos -+// Fatma HRIZI EURECOM fr> -+//------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2012 Universidade Aveiro -+// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//============================================================================== -+ -+//This file is the implementation of the MIH user in the eNB -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+// Definition of the scenario to execute -+#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -+//#define SCENARIO_1 // Sequentially activate and deactivate each resource -+#define SCENARIO_2 // Activate all resources, then deactivate all resources -+#define NUM_PARM_REPORT 10 -+ -+/////////////////////////////////////////////////////////////////////////////// -+// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -+// +--------+ +-----+ -+// |MIH_USER| |MIH-F| -+// +---+----+ +--+--+ -+// | | _current_link_action_request = 0 -+// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -+// | | -+// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -+// |<--------- Capability_Discover.confirm --------------| (success) -+// | | -+// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -+// |<--------- Event_Subscribe.confirm ------------------| (success) -+// | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// Scenario 1: Sequentially activate and deactivate each resource -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | -+// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -+// | | Handler next msg=receive_MIH_Link_Actions_confirm -+// |<--------- Link_Actions.confirm ---------------------| (success) -+// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -+// | | Handler next msg=receive_MIH_Link_Actions_confirm -+// | | _current_link_action_request = _current_link_action_request + 1 -+// |<--------- Link_Actions.confirm ---------------------| (success) -+// | . | -+// | . | -+// | . | -+// | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// Scenario 2: Activate all resources, then deactivate all resources -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | -+// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -+// | | Handler next msg=receive_MIH_Link_Actions_confirm -+// | | _current_link_action_request = _current_link_action_request + 1 -+// |<--------- Link_Actions.confirm ---------------------| (success) -+// | . | -+// | . | -+// | . | _current_link_action_request = 0 -+// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -+// | | Handler next msg=receive_MIH_Link_Actions_confirm -+// | | _current_link_action_request = _current_link_action_request + 1 -+// |<--------- Link_Actions.confirm ---------------------| (success) -+// | . | -+// | . | -+// | . | -+// | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | -+// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -+// |<--------- Event_Subscribe.confirm ------------------| (success) -+// | | -+// | | -+/////////////////////////////////////////////////////////////////////////////// -+ -+static const char* const kConf_MIH_Commands = "user.commands"; -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+namespace po = boost::program_options; -+ -+using odtone::uint; -+using odtone::ushort; -+using odtone::sint8; -+ -+odtone::logger log_("[mih_usr]", std::cout); -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+//----------------------------------------------------------------------------- -+void __trim(odtone::mih::octet_string &str, const char chr) -+//----------------------------------------------------------------------------- -+{ -+ str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -+} -+//----------------------------------------------------------------------------- -+template std::string StringOf(T object) { -+//----------------------------------------------------------------------------- -+ std::ostringstream os; -+ os << object; -+ return(os.str()); -+} -+//----------------------------------------------------------------------------- -+std::string getTimeStamp4Log() -+//----------------------------------------------------------------------------- -+{ -+ std::stringstream ss (std::stringstream::in | std::stringstream::out); -+ struct timespec time_spec; -+ unsigned int time_now_micros; -+ unsigned int time_now_s; -+ clock_gettime (CLOCK_REALTIME, &time_spec); -+ time_now_s = (unsigned int) time_spec.tv_sec % 3600; -+ time_now_micros = (unsigned int) time_spec.tv_nsec/1000; -+ ss << time_now_s << ':' << time_now_micros; -+ return ss.str(); -+} -+//----------------------------------------------------------------------------- -+std::string status2string(odtone::mih::status statusP){ -+//----------------------------------------------------------------------------- -+ switch (statusP.get()) { -+ case odtone::mih::status_success: return "SUCCESS";break; -+ case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; -+ case odtone::mih::status_rejected: return "REJECTED";break; -+ case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; -+ case odtone::mih::status_network_error: return "NETWORK_ERROR";break; -+ default: return "UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; -+ case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; -+ case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; -+ case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; -+ case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; -+ default: return "DN_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; -+ case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; -+ case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; -+ default: return "GD_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string evt2string(odtone::mih::mih_evt_list evtP){ -+//----------------------------------------------------------------------------- -+ std::string s; -+ if(evtP.get(odtone::mih::mih_evt_link_detected)) s = std::string("DETECTED "); -+ if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; -+ if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; -+ if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; -+ if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -+//----------------------------------------------------------------------------- -+ std::string s; -+ if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s = std::string("Link_Get_Parameters "); -+ if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; -+ if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string link_type2string(const odtone::mih::link_type& lt) -+//----------------------------------------------------------------------------- -+{ -+ switch (lt.get()) { -+ case odtone::mih::link_type_gsm: return "GSM"; break; -+ case odtone::mih::link_type_gprs: return "GPRS"; break; -+ case odtone::mih::link_type_edge: return "EDGE"; break; -+ case odtone::mih::link_type_ethernet: return "Ethernet"; break; -+ case odtone::mih::link_type_wireless_other: return "Other"; break; -+ case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; -+ case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; -+ case odtone::mih::link_type_umts: return "UMTS"; break; -+ case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; -+ case odtone::mih::link_type_lte: return "LTE"; break; -+ case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; -+ case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; -+ case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; -+ default: break; -+ } -+ return "Unknown link type"; -+} -+//----------------------------------------------------------------------------- -+std::string link_addr2string(const odtone::mih::link_addr *addr) -+//----------------------------------------------------------------------------- -+{ -+ if (const odtone::mih::mac_addr *la = boost::get(addr)) { -+ return la->address(); -+ } -+ else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d") % plmn % la->_cell_id); -+ } -+ else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); -+ } -+ else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ return "null"; -+} -+//----------------------------------------------------------------------------- -+std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -+//----------------------------------------------------------------------------- -+{ -+ char buffer[256]; -+ int index = 0; -+ -+ index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); -+ index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string link_id2string(odtone::mih::link_id linkP) -+//----------------------------------------------------------------------------- -+{ -+ std::string s; -+ s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ switch (ip_addrP.type()) { -+ case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; -+ case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; -+ default: s = "Unkown type "; -+ } -+ s += ip_addrP.address(); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -+//----------------------------------------------------------------------------- -+ char buffer[128]; -+ std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string ip_proto2string(odtone::mih::proto ip_protoP) { -+//----------------------------------------------------------------------------- -+ switch (ip_protoP.get()) { -+ case odtone::mih::proto_tcp: return "TCP"; -+ case odtone::mih::proto_udp: return "UDP"; -+ default: break; -+ } -+ return "Unknown IP protocol"; -+} -+// TEMP : next 2 functions are commented to restore flow_id as a uint32 -+// full structure will be updated later -+/*//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::flow_id flowP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ odtone::mih::ip_tuple ip; -+ ip = flowP.src; -+ s = "SRC = " + ip_tuple2string(flowP.src); -+ s += ", DST = " + ip_tuple2string(flowP.dst); -+ s += ", PROTO = " + ip_proto2string(flowP.transport); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -+//----------------------------------------------------------------------------- -+ if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(res->fid); -+ } -+ else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(flow->id); -+ } -+ return "null"; -+}*/ -+//----------------------------------------------------------------------------- -+std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -+//----------------------------------------------------------------------------- -+{ -+ switch (resultP.get()) { -+ case odtone::mih::link_ac_success: return "SUCCESS"; break; -+ case odtone::mih::link_ac_failure: return "FAILURE"; break; -+ case odtone::mih::link_ac_refused: return "REFUSED"; break; -+ case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; -+ default: break; -+ } -+ return "Unknown action result"; -+} -+//----------------------------------------------------------------------------- -+std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ -+ s = link_id2string(link_act_reqP.id); -+ -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; -+ -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; -+ -+ s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string net_type_addr_list2string(boost::optional ntalP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ odtone::mih::link_id link_id; -+ -+ for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) -+ { -+ link_id.type = boost::get(i->nettype.link); -+ link_id.addr = i->addr; -+ if (i != ntalP->begin()) { -+ s += " / "; -+ } -+ s += link_id2string(link_id); -+ } -+ -+ return s; -+} -+ -+/** -+ * Parse supported commands. -+ * -+ * @param cfg Configuration options. -+ * @return An optional list of supported commands. -+ */ -+boost::optional parse_supported_commands(const odtone::mih::config &cfg) -+{ -+ using namespace boost; -+ -+ odtone::mih::mih_cmd_list commands; -+ -+ std::map enum_map; -+ enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; -+ enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; -+ enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; -+ enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; -+ enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; -+ enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; -+ enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; -+ enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; -+ enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; -+ enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; -+ enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; -+ -+ std::string tmp = cfg.get(kConf_MIH_Commands); -+ __trim(tmp, ' '); -+ -+ char_separator sep1(","); -+ tokenizer< char_separator > list_tokens(tmp, sep1); -+ -+ BOOST_FOREACH(std::string str, list_tokens) { -+ if(enum_map.find(str) != enum_map.end()) { -+ commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); -+ } -+ } -+ -+ return commands; -+} -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * This class provides an implementation of an IEEE 802.21 MIH-User. -+ */ -+class mih_user : boost::noncopyable { -+public: -+ /** -+ * Construct the MIH-User. -+ * -+ * @param cfg Configuration options. -+ * @param io The io_service object that the MIH-User will use to -+ * dispatch handlers for any asynchronous operations performed on the socket. -+ */ -+ mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); -+ -+ /** -+ * Destruct the MIH-User. -+ */ -+ ~mih_user(); -+ -+protected: -+ /** -+ * User registration handler. -+ * -+ * @param cfg Configuration options. -+ * @param ec Error Code. -+ */ -+ void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); -+ /** -+ * Default MIH event handler. -+ * -+ * @param msg Received event notification. -+ * @param ec Error code. -+ */ -+ void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ /** -+ * MIH receive message handler. -+ * -+ * @param msg Received message. -+ * @param ec Error code. -+ */ -+ void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+ void send_MIH_User_Register_indication(const odtone::mih::config& cfg); -+ -+ void send_MIH_Capability_Discover_request(const odtone::mih::config& cfg); -+ void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); -+ void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Unsubscribe_request(void); -+ void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); -+ void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); -+ void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); -+ void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+ void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); -+ void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+private: -+ odtone::sap::user _mihf; /**< User SAP helper. */ -+ odtone::mih::id _mihfid; /**< MIHF destination ID. */ -+ odtone::mih::id _mihuserid; /**< MIH_USER ID. */ -+ -+ odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ -+ odtone::mih::port _mihf_lport; /**< MIHF local port number */ -+ -+ odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ -+ odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ -+ -+ odtone::mih::link_ac_type _last_link_action_type; -+ odtone::uint _current_link_action_request, _nb_of_link_action_requests; -+ odtone::uint link_threshold_request, link_measures_request, link_measures_counter; -+ odtone::mih::link_id rcv_link_id; -+ -+ static const odtone::uint _max_link_action_requests = 4; -+ -+ void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Up_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Down_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); -+ -+}; -+ -+//----------------------------------------------------------------------------- -+mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) -+ : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), -+ _last_link_action_type(odtone::mih::link_ac_type_none), -+ _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES) -+//----------------------------------------------------------------------------- -+{ -+ -+ odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); -+ _mihuserid.assign(user_id.c_str()); -+ -+ odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); -+ _mihfid.assign(dest_id.c_str()); -+ -+ odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); -+ boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); -+ if (ip.is_v4()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); -+ _mihf_ip = ip_addr; -+ } -+ else if (ip.is_v6()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); -+ _mihf_ip = ip_addr; -+ } -+ -+ _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); -+ -+ //_nb_of_link_action_requests = NB_OF_RESOURCES; -+ if (_nb_of_link_action_requests > _max_link_action_requests) { -+ _nb_of_link_action_requests = _max_link_action_requests; -+ } -+ -+ _link_id_list.clear(); -+ _subs_evt_list.clear(); -+ link_threshold_request = 0; -+ link_measures_request =0; -+ link_measures_counter =0; -+ log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); -+ -+ // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F -+ mih_user::send_MIH_User_Register_indication(cfg); -+} -+ -+//----------------------------------------------------------------------------- -+mih_user::~mih_user() -+//----------------------------------------------------------------------------- -+{ -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH-User register result: ", ec.message(), "\n"); -+ log_(0, ""); -+ -+ // -+ // Local Capability Discover Request -+ // -+ odtone::mih::message msg; -+ _mihfid.assign("mihf2"); -+ msg << odtone::mih::request(odtone::mih::request::capability_discover, _mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Capability_Discover.request --->]["+msg.destination().to_string()+"]\n"); -+ _mihf.async_send(msg, boost::bind(&mih_user::receive_MIH_Capability_Discover_confirm, this, _1)); -+ log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)"); -+ log_(0, ""); -+ -+ //****eNB***** -+ // Remote Capability Discover Request -+ // -+ mih_user::send_MIH_Capability_Discover_request(cfg); -+ -+ //Trigger Link_Configure_Thresholds Request -+ // odtone::mih::message m; -+ //m.destination(msg.source()); -+ //mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ //****eNB***** -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ case odtone::mih::indication::link_detected: -+ mih_user::receive_MIH_Link_Detected_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_up: -+ mih_user::receive_MIH_Link_Up_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_down: -+ mih_user::receive_MIH_Link_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_going_down: -+ mih_user::receive_MIH_Link_Going_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_handover_imminent: -+ log_(0, "MIH-User has received a local event \"link_handover_imminent\""); -+ break; -+ -+ case odtone::mih::indication::link_handover_complete: -+ log_(0, "MIH-User has received a local event \"link_handover_complete\""); -+ break; -+ -+ case odtone::mih::indication::link_parameters_report: -+ //log_(0, "MIH-User has received a local event \"link_parameters_report\""); -+ mih_user::receive_MIH_Link_Parameters_Report(msg, ec); -+ if (link_threshold_request == 0){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ link_threshold_request =1; -+ } else if (link_threshold_request == 1){ -+ link_measures_counter ++; -+ // Stop measures after 5 reports -+ if (link_measures_counter == NUM_PARM_REPORT){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ } -+ } -+ break; -+ -+ case odtone::mih::indication::link_pdu_transmit_status: -+ log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); -+ break; -+ -+ case odtone::mih::confirm::link_configure_thresholds: -+ mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); -+ break; -+ -+ default: -+ log_(0, "MIH-User has received UNKNOWN local event"); -+ break; -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ -+ case odtone::mih::confirm::capability_discover: -+ mih_user::receive_MIH_Capability_Discover_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_subscribe: -+ mih_user::receive_MIH_Event_Subscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_unsubscribe: -+ mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::link_actions: -+ mih_user::receive_MIH_Link_Actions_confirm(msg); -+ -+ break; -+ default: -+ log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); -+ break; -+ } -+} -+/* -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_det_info_list ldil; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_det_info_list(ldil); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ // TODO: for each link_det_info in the list {display LINK_DET_INFO} -+ -+ log_(0, "MIH_Link_Detected.indication - End\n"); -+} -+*/ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ -+ log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_det_info_list ldil; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_det_info_list(ldil); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+boost::system::error_code ec; -+ for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) -+ { -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(i->id).c_str()); -+ log_(0, " - Network ID: ", i->network_id); -+ log_(0, " - SINR: ", i->sinr); -+ log_(0, " - Data_rate: ", i->data_rate); -+ } -+ -+ send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ -+ -+ log_(0, "MIH_Link_Detected.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+// odtone::mih::tlv_old_access_router oldAR; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link); -+// & odtone::mih::tlv_old_access_router(oar); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+ -+ -+ log_(0, "MIH_Link_Up.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+ boost::optional addr; -+ odtone::mih::link_dn_reason ldr; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_old_access_router(addr) -+ & odtone::mih::tlv_link_dn_reason(ldr); -+ -+// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ //Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Down.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_gd_reason lgd; -+ odtone::mih::link_ac_ex_time ex_time; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_time_interval(ex_time) -+ & odtone::mih::tlv_link_gd_reason(lgd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - Time Interval:", (ex_time/256)); -+ log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Going_Down.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_param_rpt_list lprl; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_link_param_rpt_list(lprl); -+ -+ log_(0, ""); -+ log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ -+ -+ for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) -+ { -+ if (const odtone::mih::threshold *th = boost::get(&i->thold)) { -+ -+ log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); -+ //link_action if free channel is available -+ } -+ else{ -+ log_(0, " -Regular Report for BW Threshold "); -+ //update MEAS -+ } -+ } -+ -+ log_(0, "MIH_Link_Parameters_Report.indication - End"); -+} -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ boost::optional supp_cmd = parse_supported_commands(cfg); -+ -+ m << odtone::mih::indication(odtone::mih::indication::user_register) -+ & odtone::mih::tlv_command_list(supp_cmd); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); -+ -+ log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Capability_Discover_request(const odtone::mih::config& cfg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ //boost::optional ntal; -+ //boost::optional evt; -+ boost::optional supp_cmd = parse_supported_commands(cfg); -+ -+ m << odtone::mih::request(odtone::mih::request::capability_discover) -+ //& odtone::mih::tlv_net_type_addr_list(ntal) -+ //& odtone::mih::tlv_event_list(evt) -+ & odtone::mih::tlv_command_list(supp_cmd); -+ m.source(_mihuserid); -+ _mihfid.assign("mihf2"); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH_Capability_Discover.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, ""); -+ log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional ntal; -+ boost::optional evt; -+ boost::optional cmd; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_net_type_addr_list(ntal) -+ & odtone::mih::tlv_event_list(evt) -+ & odtone::mih::tlv_command_list(cmd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ if (cmd) { -+ log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); -+ } -+ if (ntal) { -+ log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); -+ //Store link address -+ for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -+ { -+ rcv_link_id.addr = i->addr; -+ rcv_link_id.type = boost::get(i->nettype.link); -+ } -+ } -+ log_(0, ""); -+ -+ // -+ // event subscription -+ // -+ // For every interface the MIHF sent in the -+ // Capability_Discover.response send an Event_Subscribe.request -+ // for all availabe events -+ // -+ if (ntal && evt) { -+ _subs_evt_list = evt.get(); // save the list of subscribed link events -+ for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { -+ if (i->nettype.link.which() == 1) -+ { -+ odtone::mih::link_tuple_id li; -+ -+ li.addr = i->addr; -+ li.type = boost::get(i->nettype.link); -+ _link_id_list.push_back(li); // save the link identifier of the network interface -+ -+ mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); -+ } -+ } -+ } -+ -+ log_(0, "MIH_Capability_Discover.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ m << odtone::mih::request(odtone::mih::request::event_subscribe) -+ & odtone::mih::tlv_link_identifier(li) -+ & odtone::mih::tlv_event_list(evt); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ -+ "\\nLink="+link_id2string(li).c_str()+ -+ "\\nEvent list="+evt2string(evt).c_str()+ -+ " --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); -+ -+ log_(0, "MIH_Event_Subscribe.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ odtone::mih::link_tuple_id link; -+ boost::optional evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); -+ log_(0, "TEMP : Resource scenario deactivated\n"); -+ -+ log_(0, "MIH_Event_Subscribe.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id li; -+ -+ // For every interface the MIH user received in the -+ // Capability_Discover.confirm, send an Event_Unsubscribe.request -+ // for all subscribed events -+ for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -+ li.type = i->type; -+ li.addr = i->addr; -+ mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ m << odtone::mih::request(odtone::mih::request::event_unsubscribe) -+ & odtone::mih::tlv_link_identifier(li) -+ & odtone::mih::tlv_event_list(evt); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ -+ "\\nLink="+link_id2string(li).c_str()+ -+ "\\nEvent list="+evt2string(evt).c_str()+ -+ " --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); -+ -+ log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ odtone::mih::link_tuple_id link; -+ boost::optional evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ log_(0, "MIH_Event_Unsubscribe.confirm - End"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::link_action_list lal; -+ odtone::mih::link_action_req link_act_req; -+ -+ link_act_req.id = link; -+ link_act_req.action.type = type; -+ -+ _last_link_action_type = type; -+ -+ // Initialize resource parameters -+ odtone::mih::resource_desc res; -+ -+ res.lid = link; // Link identifier -+ res.data_rate = 128000; // bit rate -+ res.jumbo = false; // jumbo disable -+ res.multicast = false; // multicast disable -+ -+ odtone::mih::qos qos; // Class Of Service -+ qos.value = 56; -+ res.qos_val = qos; -+ res.fid = 555 + _current_link_action_request; -+ -+// // Flow identifier -+// res.fid.src.ip = _mihf_ip; -+// res.fid.src.port_val = _mihf_lport; -+// -+// if (mih_user::_current_link_action_request == 0) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 1) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 2) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -+// res.multicast = true; -+// } -+// else if (mih_user::_current_link_action_request == 3) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -+// } -+// res.fid.dst.port_val = 1235; // DUMMY -+// res.fid.transport = odtone::mih::proto_udp; -+ -+ link_act_req.action.param.param = res; -+ -+ link_act_req.ex_time = 0; -+ -+ lal.push_back(link_act_req); -+ -+ m << odtone::mih::request(odtone::mih::request::link_actions) -+ & odtone::mih::tlv_link_action_list(lal); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -+//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); -+ log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); -+ -+ log_(0, "MIH_Link_Actions.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional larl; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_action_rsp_list(larl); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ if (larl) { -+ log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -+ for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -+ { -+ log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -+ ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -+ } -+ } -+ log_(0, ""); -+ -+ // 1st scenario: Sequentially activate and deactivate each resource -+#ifdef SCENARIO_1 -+ if (larl) { -+ odtone::mih::link_action_rsp *rsp = &larl->front(); -+ if (_current_link_action_request < _nb_of_link_action_requests) { -+ if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ if (rsp->result.get() == odtone::mih::link_ac_success) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ _current_link_action_request += 1; -+ } -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+ } -+ } -+ else { // Ends the scenario -+ mih_user::send_MIH_Event_Unsubscribe_request(); -+ } -+ } -+#endif // SCENARIO_1 -+ -+#ifdef SCENARIO_2 -+ // 2nd scenario: Activate all resources, then deactivate all resources -+ if (larl.get().size() > 0) { -+ odtone::mih::link_action_rsp *rsp = &larl->front(); -+ if (++_current_link_action_request < _nb_of_link_action_requests) { -+ if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ } -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ _current_link_action_request = 0; -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ } -+ else { // Ends the scenario -+ mih_user::send_MIH_Event_Unsubscribe_request(); -+ } -+ } -+#endif // SCENARIO_2 -+ -+ log_(0, "MIH_Link_Actions.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ odtone::mih::threshold th; -+ std::vector thl; -+ -+ odtone::mih::link_tuple_id lti; -+// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -+ -+ -+ odtone::mih::link_cfg_param_list lcpl; -+ odtone::mih::link_cfg_param lcp; -+ odtone::mih::link_param_lte lp; -+ -+ -+ log_(0,""); -+ log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -+ -+ -+ odtone::mih::link_det_info_list ldil; -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_det_info_list(ldil); -+ for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) -+ { -+ -+ -+ lti.type = i->id.type; -+ lti.addr = i->id.addr; -+ lp = odtone::mih::link_param_lte_bandwidth; -+ lcp.type = lp; -+ if ( link_measures_request ==0){ -+ lcp.timer_interval = 10; -+ lcp.action = odtone::mih::th_action_normal; -+ link_measures_request = 1; -+ } -+ else{ -+ lcp.timer_interval = 0; -+ lcp.action = odtone::mih::th_action_cancel; -+ link_measures_request = 0; -+ } -+ th.threshold_val = 5; -+ th.threshold_x_dir = odtone::mih::threshold::above_threshold; -+ thl.push_back(th); -+ lcp.threshold_list = thl; -+ lcpl.push_back(lcp); -+ -+ m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -+ & odtone::mih::tlv_link_identifier(lti) -+ & odtone::mih::tlv_link_cfg_param_list(lcpl); -+ -+ m.destination(msg.source()); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -+ link_id2string(lti).c_str()+ -+ " --->]["+_mihfid.to_string()+"]\n"); -+ _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); -+ -+ -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); -+ -+ log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); -+ -+ } -+ -+/* -+ if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} -+ -+ log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); -+ -+ if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} -+ if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} -+ if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} -+ -+ log_(0, "\t Threshold value: ", th.threshold_val); -+ -+ if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} -+ if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} -+ -+ log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -+*/ -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, ""); -+ log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); -+ -+ // T odtone::uint iter; -+ // T odtone::mih::status st; -+ -+ //boost::optional lcsl; -+ // Todtone::mih::link_cfg_status_list lcsl; -+ // Todtone::mih::link_cfg_status lcp; -+ //odtone::mih::link_param_gen lp; -+ -+ // T odtone::mih::link_tuple_id lti; -+ -+ //msg >> odtone::mih::confirm() -+ // & odtone::mih::tlv_status(st) -+ // & odtone::mih::tlv_link_identifier(lti) -+ // & odtone::mih::tlv_link_cfg_status_list(lcsl); -+ -+ -+ log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); -+ log_(0,""); -+} -+ -+//----------------------------------------------------------------------------- -+int main(int argc, char** argv) -+//----------------------------------------------------------------------------- -+{ -+ odtone::setup_crash_handler(); -+ -+ try { -+ boost::asio::io_service ios; -+ -+ // declare MIH Usr available options -+ po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); -+ desc.add_options() -+ ("help", "Display configuration options") -+ (odtone::sap::kConf_File, po::value()->default_value("lte_user.conf"), "Configuration file") -+ (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") -+ (odtone::sap::kConf_Port, po::value()->default_value(1234), "Listening port") -+ (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") -+ (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") -+ (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") -+ (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") -+ (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1"), "MIHF destination"); -+ -+ odtone::mih::config cfg(desc); -+ cfg.parse(argc, argv, odtone::sap::kConf_File); -+ -+ if (cfg.help()) { -+ std::cerr << desc << std::endl; -+ return EXIT_SUCCESS; -+ } -+ -+ mih_user usr(cfg, ios); -+ -+ ios.run(); -+ -+ } catch(std::exception& e) { -+ log_(0, "exception: ", e.what()); -+ } -+} -+ -+// EOF //////////////////////////////////////////////////////////////////////// -+ -diff --git a/app/lte_test_user/enb_lte_user.conf b/app/lte_test_user/enb_lte_user.conf -new file mode 100644 -index 0000000..b9bbf27 ---- /dev/null -+++ b/app/lte_test_user/enb_lte_user.conf -@@ -0,0 +1,40 @@ -+#=============================================================================== -+# Brief : MIH-User configuration file -+# Authors : Carlos Guimaraes -+# Bruno Santos -+#------------------------------------------------------------------------------- -+# ODTONE - Open Dot Twenty One -+# -+# Copyright (C) 2009-2012 Universidade Aveiro -+# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+# -+# This software is distributed under a license. The full license -+# agreement can be found in the file LICENSE in this distribution. -+# This software may not be copied, modified, sold or distributed -+# other than expressed in the named license agreement. -+# -+# This software is distributed without any warranty. -+#=============================================================================== -+ -+## -+## User id -+## -+[user] -+id = user_enb -+ -+## -+## Commands supported by the MIH-User -+## -+commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete -+ -+## -+## Port used for communication with MIHF -+## -+[conf] -+port = 1635 -+ -+## -+## MIHF configuration. For the default demonstration leave as is. -+## -+[mihf] -+local_port = 1025 -diff --git a/app/lte_test_user/enb_lte_user.cpp b/app/lte_test_user/enb_lte_user.cpp -new file mode 100644 -index 0000000..80fbfe7 ---- /dev/null -+++ b/app/lte_test_user/enb_lte_user.cpp -@@ -0,0 +1,1695 @@ -+//============================================================================== -+// Brief : MIH-User -+// Authors : Bruno Santos -+//------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2012 Universidade Aveiro -+// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//============================================================================== -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+// Definition of the scenario to execute -+#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -+//#define SCENARIO_1 // Sequentially activate and deactivate each resource -+#define SCENARIO_2 // Activate all resources, then deactivate all resources -+#define NUM_PARM_REPORT 10 -+ -+//The thresholds for the Energy Detection Sensing algorithm respectively for 10 and 100 samples -+#define ED_THRESHOLD_10 23695432 -+#define ED_THRESHOLD_100 230445932 -+/////////////////////////////////////////////////////////////////////////////// -+// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -+// +--------+ +-----+ +---------+ -+// |MIH_USER| |MIH-F| |LINK_SAP | -+// +---+----+ +--+--+ +----+----+ -+// | | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// Initiallization of the MIH-USER and the MIHF -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | | -+// ... (start of MIH-F here) ... ... -+// | |---------- Link_Capability_Discover.request --------X| -+// ... (start of LINK_SAP here) ... ... -+// | |<--------- Link_Register.indication -----------------| -+// | |---------- Link_Capability_Discover.request -------->| -+// | |<--------- Link_Capability_Discover.confirm ---------| -+// | | | -+// ... (start of MIH USER here) ... ... -+// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -+ -+// ------------------------------------------------------------------------------------------------------------------------ -+// Locally send the Capability Discover and the Event Subscribe primitives -+// (from MIH USER to local MIHF) -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | | -+// |---------- MIH_Capability_Discover.request --------->| | -+// |<--------- MIH_Capability_Discover.confirm ----------| | -+// | | | -+// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -+// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -+// | | | -+// | | | -+ -+// ------------------------------------------------------------------------------------------------------------------------ -+// Remotely send the Capability Discover and the Event Subscribe primitives -+// (from MIH USER to remote MIHF of the UE) -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | | -+// |---------- MIH_Capability_Discover.request --------->| | -+// |<--------- MIH_Capability_Discover.confirm ----------| | -+// | | | -+// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -+// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -+// | | | -+// | | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// Detect the connection of the UE to the eNB + Start the measurement report process -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | | -+// | | | -+// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -+// | | (RRC Connection reconfiguration notification) | -+// | | | -+// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -+// | | | -+// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -+// | | | -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -+// | (Success) | | -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... | | -+// | | | -+// ------------------------------------------------------------------------------------------------------------------------ -+// Activate the TVWS link (After running the cognitive algorithms) -+// ------------------------------------------------------------------------------------------------------------------------ -+// | | | -+// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -+// | | | -+// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -+// | | | -+ -+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -+ -+ -+static const char* const kConf_MIH_Commands = "user.commands"; -+ -+///////////////////////////////////////////////////////////////////////////////////////// -+ -+std::string exec(char* cmd) { -+ FILE* pipe = popen(cmd, "r"); -+ if (!pipe) return "ERROR"; -+ char buffer[128]; -+ std::string result = ""; -+ while(!feof(pipe)) { -+ if(fgets(buffer, 128, pipe) != NULL) -+ result += buffer; -+ } -+ pclose(pipe); -+ return result; -+} -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+namespace po = boost::program_options; -+ -+using odtone::uint; -+using odtone::ushort; -+using odtone::sint8; -+ -+odtone::logger log_("[mih_usr]", std::cout); -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+//----------------------------------------------------------------------------- -+void __trim(odtone::mih::octet_string &str, const char chr) -+//----------------------------------------------------------------------------- -+{ -+ str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -+} -+//----------------------------------------------------------------------------- -+template std::string StringOf(T object) { -+//----------------------------------------------------------------------------- -+ std::ostringstream os; -+ os << object; -+ return(os.str()); -+} -+//----------------------------------------------------------------------------- -+std::string getTimeStamp4Log() -+//----------------------------------------------------------------------------- -+{ -+ std::stringstream ss (std::stringstream::in | std::stringstream::out); -+ struct timespec time_spec; -+ unsigned int time_now_micros; -+ unsigned int time_now_s; -+ clock_gettime (CLOCK_REALTIME, &time_spec); -+ time_now_s = (unsigned int) time_spec.tv_sec % 3600; -+ time_now_micros = (unsigned int) time_spec.tv_nsec/1000; -+ ss << time_now_s << ':' << time_now_micros; -+ return ss.str(); -+} -+//----------------------------------------------------------------------------- -+std::string status2string(odtone::mih::status statusP){ -+//----------------------------------------------------------------------------- -+ switch (statusP.get()) { -+ case odtone::mih::status_success: return "SUCCESS";break; -+ case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; -+ case odtone::mih::status_rejected: return "REJECTED";break; -+ case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; -+ case odtone::mih::status_network_error: return "NETWORK_ERROR";break; -+ default: return "UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; -+ case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; -+ case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; -+ case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; -+ case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; -+ default: return "DN_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; -+ case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; -+ case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; -+ default: return "GD_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string evt2string(odtone::mih::mih_evt_list evtP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; -+ if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; -+ if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; -+ if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; -+ if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; -+ if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; -+ if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string link_type2string(const odtone::mih::link_type& lt) -+//----------------------------------------------------------------------------- -+{ -+ switch (lt.get()) { -+ case odtone::mih::link_type_gsm: return "GSM"; break; -+ case odtone::mih::link_type_gprs: return "GPRS"; break; -+ case odtone::mih::link_type_edge: return "EDGE"; break; -+ case odtone::mih::link_type_ethernet: return "Ethernet"; break; -+ case odtone::mih::link_type_wireless_other: return "Other"; break; -+ case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; -+ case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; -+ case odtone::mih::link_type_umts: return "UMTS"; break; -+ case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; -+ case odtone::mih::link_type_lte: return "LTE"; break; -+ case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; -+ case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; -+ case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; -+ default: break; -+ } -+ return "Unknown link type"; -+} -+//----------------------------------------------------------------------------- -+std::string link_addr2string(const odtone::mih::link_addr *addr) -+//----------------------------------------------------------------------------- -+{ -+ if (const odtone::mih::mac_addr *la = boost::get(addr)) { -+ return la->address(); -+ } -+ else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d") % plmn % la->_cell_id); -+ } -+ else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); -+ } -+ else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ return "null"; -+} -+//----------------------------------------------------------------------------- -+std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -+//----------------------------------------------------------------------------- -+{ -+ char buffer[256]; -+ int index = 0; -+ -+ index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); -+ index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string link_id2string(odtone::mih::link_id linkP) -+//----------------------------------------------------------------------------- -+{ -+ std::string s; -+ s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ switch (ip_addrP.type()) { -+ case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; -+ case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; -+ default: s = "Unkown type "; -+ } -+ s += ip_addrP.address(); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -+//----------------------------------------------------------------------------- -+ char buffer[128]; -+ std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string ip_proto2string(odtone::mih::proto ip_protoP) { -+//----------------------------------------------------------------------------- -+ switch (ip_protoP.get()) { -+ case odtone::mih::proto_tcp: return "TCP"; -+ case odtone::mih::proto_udp: return "UDP"; -+ default: break; -+ } -+ return "Unknown IP protocol"; -+} -+// TEMP : next 2 functions are commented to restore flow_id as a uint32 -+// full structure will be updated later -+/*//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::flow_id flowP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ odtone::mih::ip_tuple ip; -+ ip = flowP.src; -+ s = "SRC = " + ip_tuple2string(flowP.src); -+ s += ", DST = " + ip_tuple2string(flowP.dst); -+ s += ", PROTO = " + ip_proto2string(flowP.transport); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -+//----------------------------------------------------------------------------- -+ if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(res->fid); -+ } -+ else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(flow->id); -+ } -+ return "null"; -+}*/ -+//----------------------------------------------------------------------------- -+std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -+//----------------------------------------------------------------------------- -+{ -+ switch (resultP.get()) { -+ case odtone::mih::link_ac_success: return "SUCCESS"; break; -+ case odtone::mih::link_ac_failure: return "FAILURE"; break; -+ case odtone::mih::link_ac_refused: return "REFUSED"; break; -+ case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; -+ default: break; -+ } -+ return "Unknown action result"; -+} -+//----------------------------------------------------------------------------- -+std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ -+ s = link_id2string(link_act_reqP.id); -+ -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; -+ -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; -+ -+ s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; -+ return s; -+} -+ -+ -+/*//----------------------------------------------------------------------------- -+std::string net_type_addr_list2string(boost::optional ntalP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ odtone::mih::link_id link_id; -+ -+ for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) -+ { -+ link_id.type = boost::get(i->nettype.link); -+ link_id.addr = i->addr; -+ if (i != ntalP->begin()) { -+ s += " / "; -+ } -+ s += link_id2string(link_id); -+ } -+ -+ return s; -+} -+*/ -+ -+//Updated from UE code -+//----------------------------------------------------------------------------- -+std::string net_type_addr_list2string(boost::optional ntalP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ std::ostringstream stream; -+ odtone::mih::net_type_addr net_type_addr; -+ -+ for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) -+ { -+ net_type_addr = boost::get(*i); -+ stream << net_type_addr; -+ if (i != ntalP->begin()) { -+ stream << " / "; -+ } -+ } -+ s = stream.str(); -+ return s; -+} -+ -+/** -+ * Parse supported commands. -+ * -+ * @param cfg Configuration options. -+ * @return An optional list of supported commands. -+ */ -+boost::optional parse_supported_commands(const odtone::mih::config &cfg) -+{ -+ using namespace boost; -+ -+ odtone::mih::mih_cmd_list commands; -+ -+ std::map enum_map; -+ enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; -+ enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; -+ enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; -+ enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; -+ enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; -+ enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; -+ enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; -+ enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; -+ enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; -+ enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; -+ enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; -+ -+ std::string tmp = cfg.get(kConf_MIH_Commands); -+ __trim(tmp, ' '); -+ -+ char_separator sep1(","); -+ tokenizer< char_separator > list_tokens(tmp, sep1); -+ -+ BOOST_FOREACH(std::string str, list_tokens) { -+ if(enum_map.find(str) != enum_map.end()) { -+ commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); -+ } -+ } -+ -+ return commands; -+} -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * This class provides an implementation of an IEEE 802.21 MIH-User. -+ */ -+class mih_user : boost::noncopyable { -+public: -+ /** -+ * Construct the MIH-User. -+ * -+ * @param cfg Configuration options. -+ * @param io The io_service object that the MIH-User will use to -+ * dispatch handlers for any asynchronous operations performed on the socket. -+ */ -+ mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); -+ -+ /** -+ * Destruct the MIH-User. -+ */ -+ ~mih_user(); -+ -+protected: -+ /** -+ * User registration handler. -+ * -+ * @param cfg Configuration options. -+ * @param ec Error Code. -+ */ -+ void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); -+ /** -+ * Default MIH event handler. -+ * -+ * @param msg Received event notification. -+ * @param ec Error code. -+ */ -+ void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ /** -+ * MIH receive message handler. -+ * -+ * @param msg Received message. -+ * @param ec Error code. -+ */ -+ void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+ void send_MIH_User_Register_indication(const odtone::mih::config& cfg); -+ -+ void send_MIH_Capability_Discover_request(void); -+ void send_MIH_Capability_Discover_request_remote(void); -+ void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); -+ void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Unsubscribe_request(void); -+ void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); -+ void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); -+ void send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link); -+ void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); -+ -+ //Measurements report methods -+ void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); -+ int receive_Sensing_Report(); -+ void receive_CRRM_Data(); -+ -+ void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); -+ void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); -+ void forward_Parameters_Report_indication(odtone::mih::message& m); -+ -+private: -+ odtone::sap::user _mihf; /**< User SAP helper. */ -+ odtone::mih::id _mihfid; /**< MIHF destination ID. */ -+ odtone::mih::id _mihuserid; /**< MIH_USER ID. */ -+ -+ odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ -+ odtone::mih::port _mihf_lport; /**< MIHF local port number */ -+ -+ odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ -+ odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ -+ -+ odtone::mih::link_ac_type _last_link_action_type; -+ odtone::uint _current_link_action_request, _nb_of_link_action_requests; -+ odtone::uint link_threshold_request, link_measures_request, link_measures_counter; -+ odtone::mih::link_id rcv_link_id; -+ -+ static const odtone::uint _max_link_action_requests = 4; -+ odtone::uint _num_thresholds_request; -+ odtone::uint second_link_activated; -+ odtone::uint count; -+ odtone::uint sensing_done; -+ odtone::uint sensing_score; -+ void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Up_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Down_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); -+ -+}; -+ -+//----------------------------------------------------------------------------- -+mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) -+ : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), -+ _last_link_action_type(odtone::mih::link_ac_type_none), -+ _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); -+ _mihuserid.assign(user_id.c_str()); -+ -+ odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); -+ _mihfid.assign(dest_id.c_str()); -+ -+ odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); -+ boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); -+ if (ip.is_v4()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); -+ _mihf_ip = ip_addr; -+ } -+ else if (ip.is_v6()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); -+ _mihf_ip = ip_addr; -+ } -+ -+ _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); -+ -+ //_nb_of_link_action_requests = NB_OF_RESOURCES; -+ if (_nb_of_link_action_requests > _max_link_action_requests) { -+ _nb_of_link_action_requests = _max_link_action_requests; -+ } -+ -+ _link_id_list.clear(); -+ _subs_evt_list.clear(); -+ link_threshold_request = 0; -+ second_link_activated = 0; -+ count = 0; -+ sensing_done = 0; -+ sensing_score = 0; -+ link_measures_request =0; -+ link_measures_counter =0; -+ log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); -+ -+ // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F -+ mih_user::send_MIH_User_Register_indication(cfg); -+} -+ -+//----------------------------------------------------------------------------- -+mih_user::~mih_user() -+//----------------------------------------------------------------------------- -+{ -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH-User register result: ", ec.message(), "\n"); -+ -+ // -+ // Let's fire a capability discover request to get things moving -+ // -+ mih_user::send_MIH_Capability_Discover_request(); -+ -+ //send a capability discover request to the remote UE -+ mih_user::send_MIH_Capability_Discover_request_remote(); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ case odtone::mih::indication::link_detected: -+ mih_user::receive_MIH_Link_Detected_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_up: -+ mih_user::receive_MIH_Link_Up_indication(msg); -+ if (_num_thresholds_request == 0) { -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ _num_thresholds_request += 1; -+ } -+ break; -+ -+ case odtone::mih::indication::link_down: -+ mih_user::receive_MIH_Link_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_going_down: -+ mih_user::receive_MIH_Link_Going_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_handover_imminent: -+ log_(0, "MIH-User has received a local event \"link_handover_imminent\""); -+ break; -+ -+ case odtone::mih::indication::link_handover_complete: -+ log_(0, "MIH-User has received a local event \"link_handover_complete\""); -+ break; -+ -+ case odtone::mih::indication::link_parameters_report: -+ //log_(0, "MIH-User has received a local event \"link_parameters_report\""); -+ mih_user::receive_MIH_Link_Parameters_Report(msg, ec); -+ /*if (link_threshold_request == 0){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ link_threshold_request =1; -+ } else if (link_threshold_request == 1){ -+ link_measures_counter ++; -+ // Stop measures after 5 reports -+ if (link_measures_counter == NUM_PARM_REPORT){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ } -+ }*/ -+ break; -+ -+ case odtone::mih::indication::link_pdu_transmit_status: -+ log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); -+ break; -+ -+ case odtone::mih::confirm::link_configure_thresholds: -+ mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); -+ break; -+ -+ default: -+ log_(0, "MIH-User has received UNKNOWN local event"); -+ break; -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ -+ case odtone::mih::confirm::capability_discover: -+ mih_user::receive_MIH_Capability_Discover_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_subscribe: -+ mih_user::receive_MIH_Event_Subscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_unsubscribe: -+ mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::link_actions: -+ mih_user::receive_MIH_Link_Actions_confirm(msg); -+ break; -+ -+ default: -+ log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); -+ break; -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); -+ odtone::mih::link_det_info ldi; -+ odtone::mih::link_det_info_list ldil; -+ odtone::mih::link_det_info_list::iterator it_ldil; -+ odtone::mih::link_id lid; -+ boost::system::error_code ec; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_det_info_list(ldil); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); -+ for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { -+ ldi = *it_ldil; -+ log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); -+ log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); -+ log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); -+ log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); -+ log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); -+ -+ } -+ -+ // Display message parameters -+ // TODO: for each link_det_info in the list {display LINK_DET_INFO} -+// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ -+ log_(0, "MIH_Link_Detected.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+// odtone::mih::tlv_old_access_router oldAR; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link); -+// & odtone::mih::tlv_old_access_router(oar); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Up.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id link; -+ boost::optional addr; -+ odtone::mih::link_dn_reason ldr; -+ -+ log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_old_access_router(addr) -+ & odtone::mih::tlv_link_dn_reason(ldr); -+ -+// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ //Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Down.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_gd_reason lgd; -+ odtone::mih::link_ac_ex_time ex_time; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_time_interval(ex_time) -+ & odtone::mih::tlv_link_gd_reason(lgd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - Time Interval:", (ex_time/256)); -+ log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Going_Down.indication - End\n"); -+} -+ -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ boost::optional supp_cmd = parse_supported_commands(cfg); -+ -+ m << odtone::mih::indication(odtone::mih::indication::user_register) -+ & odtone::mih::tlv_command_list(supp_cmd); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); -+ -+ log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Capability_Discover_request(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ m << odtone::mih::request(odtone::mih::request::capability_discover); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Capability_Discover_request_remote(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ m << odtone::mih::request(odtone::mih::request::capability_discover); -+ m.source(_mihuserid); -+ odtone::mih::id mid_ue; -+ mid_ue.assign("mihf2_ue"); -+ m.destination(mid_ue); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional ntal; -+ boost::optional evt; -+ boost::optional cmd; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_net_type_addr_list(ntal) -+ & odtone::mih::tlv_event_list(evt) -+ & odtone::mih::tlv_command_list(cmd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ if (cmd) { -+ log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); -+ } -+ if (ntal) { -+ log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); -+ //Store link address -+ //for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -+ //{ -+ // rcv_link_id.addr = i->addr; -+ // rcv_link_id.type = boost::get(i->nettype.link); -+ //} -+ } -+ log_(0, ""); -+ -+ // -+ // event subscription -+ // -+ // For every interface the MIHF sent in the -+ // Capability_Discover.response send an Event_Subscribe.request -+ // for all availabe events -+ // -+ -+ if (ntal && evt) { -+ _subs_evt_list = evt.get(); // save the list of subscribed link events -+ -+ std::cout<<"NTALL "<begin(); i != ntal->end(); i++) { -+ if (i->nettype.link.which() == 1) -+ { -+ odtone::mih::link_tuple_id li; -+// std::ostringstream stream; -+// std::stringstream st; -+// odtone::mih::net_type_addr net_type_addr; -+// net_type_addr = boost::get(*i); -+// stream << net_type_addr; -+// std::string s; -+// std::stringstream st (stream.str()); -+// while (getline (st, s, '\n')) -+// { -+// std::stringstream ss(s); -+// getline (ss, name, ':'); -+// getline (ss, value, '\n'); -+// // ss>>name>>value; -+// std::cout<<" name "<addr; -+ getline (st, s, ' '); -+ std::cout<<"LINK_TUPLE_ID s "<(*/i->addr/*)*/; -+ li.type = boost::get(i->nettype.link); -+ if (std::find(_link_id_list.begin(), _link_id_list.end(), li)==_link_id_list.end()) -+ _link_id_list.push_back(li); // save the link identifier of the network interface -+ -+ std::cout<<"LINK_TUPLE_ID - Link identifier:after "<]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); -+ std::cout<<"LINK_TUPLE_ID - Link identifier: "< evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); -+ //log_(0, "TEMP : Resource scenario deactivated\n"); -+ -+ log_(0, "MIH_Event_Subscribe.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id li; -+ -+ // For every interface the MIH user received in the -+ // Capability_Discover.confirm, send an Event_Unsubscribe.request -+ // for all subscribed events -+ for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -+ li.type = i->type; -+ li.addr = i->addr; -+ mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ m << odtone::mih::request(odtone::mih::request::event_unsubscribe) -+ & odtone::mih::tlv_link_identifier(li) -+ & odtone::mih::tlv_event_list(evt); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ -+ "\\nLink="+link_id2string(li).c_str()+ -+ "\\nEvent list="+evt2string(evt).c_str()+ -+ " --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); -+ -+ log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ odtone::mih::link_tuple_id link; -+ boost::optional evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ log_(0, "MIH_Event_Unsubscribe.confirm - End"); -+} -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::link_action_list lal; -+ odtone::mih::link_action_req link_act_req; -+ //struct null n; -+ -+// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -+// std::cout<<"_link_id_list addr "<addr<<" TYPE "<type<addr<<" TYPE "<type<]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); -+ -+ log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::link_action_list lal; -+ odtone::mih::link_action_req link_act_req; -+ -+ link_act_req.id = link; -+ link_act_req.action.type = type; -+ -+ _last_link_action_type = type; -+ -+ // Initialize resource parameters -+ odtone::mih::resource_desc res; -+ -+ res.lid = link; // Link identifier -+ res.data_rate = 128000; // bit rate -+ res.jumbo = false; // jumbo disable -+ res.multicast = false; // multicast disable -+ -+ odtone::mih::qos qos; // Class Of Service -+ qos.value = 56; -+ res.qos_val = qos; -+ res.fid = 555 + _current_link_action_request; -+ -+// // Flow identifier -+// res.fid.src.ip = _mihf_ip; -+// res.fid.src.port_val = _mihf_lport; -+// -+// if (mih_user::_current_link_action_request == 0) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 1) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 2) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -+// res.multicast = true; -+// } -+// else if (mih_user::_current_link_action_request == 3) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -+// } -+// res.fid.dst.port_val = 1235; // DUMMY -+// res.fid.transport = odtone::mih::proto_udp; -+ -+// link_act_req.action.param.param = res; -+ -+// link_act_req.ex_time = 0; -+ link_act_req.ex_time = 5000; -+ -+ lal.push_back(link_act_req); -+ -+ m << odtone::mih::request(odtone::mih::request::link_actions) -+ & odtone::mih::tlv_link_action_list(lal); -+ m.source(_mihuserid); -+ -+// odtone::mih::id mid_ue; -+// mid_ue.assign("mihf2_ue"); -+ m.destination(/*mid_ue*/_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -+//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); -+ log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); -+ -+ log_(0, "MIH_Link_Actions.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional larl; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st); -+// & odtone::mih::tlv_link_action_rsp_list(larl); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+// if (larl) { -+// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -+// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -+// { -+// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -+// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -+// } -+// } -+ log_(0, ""); -+ -+ // 1st scenario: Sequentially activate and deactivate each resource -+// #ifdef SCENARIO_1 -+// if (larl) { -+// odtone::mih::link_action_rsp *rsp = &larl->front(); -+// if (_current_link_action_request < _nb_of_link_action_requests) { -+// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+// if (rsp->result.get() == odtone::mih::link_ac_success) { -+// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+// _current_link_action_request += 1; -+// } -+// } -+// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+// } -+// } -+// else { // Ends the scenario -+// mih_user::send_MIH_Event_Unsubscribe_request(); -+// } -+// } -+// #endif // SCENARIO_1 -+// -+// #ifdef SCENARIO_2 -+// // 2nd scenario: Activate all resources, then deactivate all resources -+// if (larl.get().size() > 0) { -+// odtone::mih::link_action_rsp *rsp = &larl->front(); -+// if (++_current_link_action_request < _nb_of_link_action_requests) { -+// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+// } -+// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+// } -+// } -+// else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+// _current_link_action_request = 0; -+// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+// } -+// else { // Ends the scenario -+// mih_user::send_MIH_Event_Unsubscribe_request(); -+// } -+// } -+// #endif // SCENARIO_2 -+ -+ log_(0, "MIH_Link_Actions.confirm - End\n"); -+} -+ -+void mih_user::receive_CRRM_Data() -+{ -+ -+ //CRRM data report -+ std::string result = exec ("./CRMClientmain 0 1"); -+} -+ -+//----------------------------------------------------------------------------- -+int mih_user::receive_Sensing_Report() -+//----------------------------------------------------------------------------- -+{ -+ std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); -+ std::string tmp; -+ int value; -+ std::stringstream ss(result); -+ ss >> tmp >> value; -+ std::cout<<"Result of Sensing "<> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_link_param_rpt_list(lprl); -+ -+ log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); -+ log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ std::cout<<"LINK_TUPLE_ID - Link identifier: "< RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); -+ if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) -+ { -+ log_(0, "Meausrement Value: ", (short) *value ); -+ } -+ } -+ log_(0, "MIH_Link_Parameters_Report.indication - End"); -+ -+ -+ //eNB1: Forward the message to UE 2 -+ forward_Parameters_Report_indication(msg); -+ -+ //eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm -+ -+ //First Phase: Collect the data as input fot the cognitive algorithm -+ //Sensing data -+ if (sensing_done == 0) -+ sensing_score = receive_Sensing_Report(); -+ -+ //CRRM Data -+ receive_CRRM_Data(); -+ -+ for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) -+ { -+ if (odtone::mih::threshold *th = boost::get(&i->thold)) { -+// log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); -+ //link_action if free channel is available -+// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -+// if(*i==link) -+ odtone::mih::l2_3gpp_addr add; -+ odtone::mih::link_type type; -+ type = odtone::mih::link_type_lte; -+// add.value = "l2_3gpp_addr"; -+ link1.addr = add; -+ link1.type = type; -+// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); -+ -+ //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 -+ if (second_link_activated==0) -+ { -+ if (count == 20) -+ { -+ send_MIH_Link_Action_Power_Up_request(_link_id_list[1]);//Link LTE -+ second_link_activated = 1; -+ } -+ } -+ -+ count++; -+// continue; -+// send_MIH_Link_Action_Power_Up_request(link); -+// if (link_id2string(link).c_str() == "LTE") -+// } -+ } -+ } -+ -+} -+ -+ -+//Forward the MIH_Link_Parameters_Report to the UE of the CPE -+//----------------------------------------------------------------------------- -+void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_param_rpt_list lprl; -+ -+ m >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_link_param_rpt_list(lprl); -+ -+ odtone::mih::message msg; -+ msg.source(_mihuserid); -+ odtone::mih::id mid_ue; -+ mid_ue.assign("mihf3_ue"); -+ msg.destination(mid_ue); -+ -+ //mn_ho_candidate_query is used to constuct/send the message containing parameters reports -+ msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_link_param_rpt_list(lprl); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+ -+ _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); -+ -+ log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); -+ -+} -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::threshold th1; -+ odtone::mih::threshold th2; -+ std::vector thl1; -+ std::vector thl2; -+ odtone::mih::link_tuple_id lti; -+ odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -+ //List of the link threshold parameters -+ odtone::mih::link_cfg_param_list lcpl; -+ odtone::mih::link_cfg_param lcp1; -+ odtone::mih::link_cfg_param lcp2; -+ odtone::mih::link_param_lte lp1; -+ odtone::mih::link_param_lte lp2; -+ //odtone::mih::link_param_gen lp; -+ -+ odtone::mih::link_param_type typr; -+ -+ log_(0,""); -+ log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -+ -+ //link_tuple_id -+ lti.type = rcv_link_id.type; -+ lti.addr = rcv_link_id.addr; -+ -+ //local_l2_3gpp_addr = boost::get(lti.addr); -+ -+ //link_param_gen_data_rate = 0, /**< Data rate. */ -+ //link_param_gen_signal_strength = 1, /**< Signal strength. */ -+ //link_param_gen_sinr = 2, /**< SINR. */ -+ //link_param_gen_throughput = 3, /**< Throughput. */ -+ //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -+ //lp = odtone::mih::link_param_lte_bandwidth; -+ lp1 = odtone::mih::link_param_lte_rsrp; -+ lp2 = odtone::mih::link_param_lte_rsrq; -+ lcp1.type = lp1; -+ lcp2.type = lp2; -+ -+ link_measures_request = 0; -+ if (link_measures_request ==0){ -+ // Set Timer Interval (in ms) -+ lcp1.timer_interval = 3000; -+ lcp2.timer_interval = 3000; -+ //th_action_normal = 0, /**< Set normal threshold. */ -+ //th_action_one_shot = 1, /**< Set one-shot threshold. */ -+ //th_action_cancel = 2 /**< Cancel threshold. */ -+ lcp1.action = odtone::mih::th_action_normal; -+ lcp2.action = odtone::mih::th_action_normal; -+ link_measures_request = 1; -+ } else if ( link_measures_request==1){ -+ // Set Timer Interval (in ms) -+ lcp1.timer_interval = 0; -+ lcp2.timer_interval = 0; -+ lcp1.action = odtone::mih::th_action_cancel; -+ lcp2.action = odtone::mih::th_action_cancel; -+ link_measures_request = 0; -+ } -+ -+ //above_threshold = 0, /**< Above threshold. */ -+ //below_threshold = 1, /**< Below threshold. */ -+ th1.threshold_val = -105; -+ th2.threshold_val = -19; -+ th1.threshold_x_dir = odtone::mih::threshold::above_threshold; -+ th2.threshold_x_dir = odtone::mih::threshold::above_threshold; -+ -+ thl1.push_back(th1); -+ thl2.push_back(th2); -+ lcp1.threshold_list = thl1; -+ lcp2.threshold_list = thl2; -+ -+ lcpl.push_back(lcp1); -+ lcpl.push_back(lcp2); -+ -+ -+ -+ m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -+ & odtone::mih::tlv_link_identifier(lti) -+ & odtone::mih::tlv_link_cfg_param_list(lcpl); -+ -+ m.source(_mihuserid); -+ odtone::mih::id mid_ue; -+ mid_ue.assign("mihf2_ue"); -+ m.destination(mid_ue); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -+ // link_tupple_id2string(lti).c_str() + -+ link_id2string(lti).c_str()+ " --->][ ADDR LINK " -+ + m.destination().to_string() +"]\n"); -+ std::cout<<"LINK TUPLE ID "< lcsl; -+ odtone::mih::link_cfg_status_list lcsl; -+ odtone::mih::link_cfg_status lcp; -+ odtone::mih::link_param_gen lp; -+ -+ odtone::mih::link_tuple_id lti; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(lti); -+// & odtone::mih::tlv_link_cfg_status_list(lcsl); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); -+ log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); -+ -+ log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); -+ -+ for(iter=0; iter()->default_value("enb_lte_user.conf"), "Configuration file") -+ (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") -+ (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") -+ (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") -+ (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") -+ (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") -+ (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") -+ (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1_enb"), "MIHF destination"); -+ -+ odtone::mih::config cfg(desc); -+ cfg.parse(argc, argv, odtone::sap::kConf_File); -+ -+ if (cfg.help()) { -+ std::cerr << desc << std::endl; -+ return EXIT_SUCCESS; -+ } -+ -+ mih_user usr(cfg, ios); -+ -+ ios.run(); -+ -+ } catch(std::exception& e) { -+ log_(0, "exception: ", e.what()); -+ } -+} -+ -+// EOF //////////////////////////////////////////////////////////////////////// -+ -diff --git a/app/lte_test_user/libcrmclient.so.1.0 b/app/lte_test_user/libcrmclient.so.1.0 -new file mode 100644 -index 0000000000000000000000000000000000000000..c3c182c85c84468692552a29a6755784abc8971f -GIT binary patch -literal 2273132 -zcmZ_W2RPM#A3y%jInLpj9Wx{yBbkLXq;c$#bcj+$2pJ724XtC3D5Q)^luBAedzpn) -zG_(s*i6-s!e}2Bb{V&)3`~9Bx_4qzt@7L!XN#|JI+HC7=$6zq1!H7^I6n)}LN>gTN -zPdlamE}2n0N{rH_)Tt5wT_3zX-A=uV|6$VyF7@Aag#krMfu;1Hb^-RT6eUWoGwGX2 -zDpA}K|9r!lMqg(U3V0<3X=6tlye8;g6=>KgM-3WSM^UuF>#n$toBtmfeEDv;KJ@kL -z8$nSt`u_Cqoo)pX0ecq@DoA_vEWeLtY6Y#klnP`{pR}oK%@D!wGY!}28xKQu8H_fu -zAD(M16f!tGRsxmHXHra|9HlyELj2Wsqg;o)v@8zpBV_Ug3{5LGhiMSzuH6+&@x<8y -zapE092|iWB-pOGmB}DQ?*uFvQ2gvvI&Ka{7kINtU=n{C?SQoOYq4zhC6T#k)Mur`-BM?x4!-B6_xB8R>9 -z&QaOJYvwUxX7|4{KIuKDV?e~JCO0jYhd(1>5>s|US!Gk2&T%cS2&G^pwM^D8mBHds -zd=C~SqEaMk6VGlk=Iq)f6caGqm6@G7qBnO0j6P`sFN -zPRP`@j -z)og}8xl~;d9-qsjs3vY|rVL-GcvUy%!x$m{NV#IdRN0ICIU+oPS-jNKK1SmD -ztPxs5p>(WHb(J=!fX`sW@Zu?@X6;-TwFNvWmfj-`DFqpdVon&%=5Z-z3_IgFTRT9Z -zN{?xFfZ9+f6l%JOT1vN4QZsWYL!MEgUq+!f#iV#6C%Z8C@stq%m3K>$dcI|Q^@#j_4H^t27$(afZBY3i= -z4%;}6oY&%NGKDP4jdGz<@mRYp)KAqd8NH5^p^&UCw36a{R^TKkv$+BrF7qUlC+yIm -zSn4eIGI6{zOhL0Ovx;&^+%CLc7b3=zqC6QAwu_RtQvu_}W5w91#&@^!Z5Rv(Av50C -zk1Le487;24TZU&SG|vj=NJKEj=2Kl<&LWm^r4nD1sX3BWI@nRI;l@fBPSV|~U<{W44*DBjA)E>s4E^AK7+xR8wQd0{%l_`N$EdCS~t>m0_ -zbcG=-hf}dsnQ^ghE|ZGoaVwm4x30`c&?{8AtZX#JUY1dV8*|j~PJ`jBoHd|4q9zb` -zj^PUNY&~BnJnqKeida)@7UgM0$?`H}(;o;Y?xytEsj@33)bS()67@6qe-;_++Txwl -zYQxOS5=t8iZCM{mc^vZ$Wu_&c!({Sfm>f>3IM1Mbgt&1jtGUNne5ILui}uwbz3Kl3{Ocsa5Vz3-ySTd9)pYnCkXYrGT3Nk`Uz|Z4q -zaJ3JJu{b>DK2D4vUXCly$(<;Ssi9&Oj&SNJRVynzWT^H8yZ}8W{q9ZEHW{x)6qTx% -zon#rSm$)d#in+oeL|jvY$6&`U5TC-biDA3%V>1`>quMR@^CpNgcoZ{J<%X~@o}%A~ -z6oW-kc5#KORZg~4e4~PP3^&APMYy~OyGbNVS3j$X;&Z66s%o#zs6Yn0gh$D7sj(wu -zi#?Q0HR5e4%EMbCHW5!Or_5%dhLuzeRmc=J?n@Pf1h$A?DRUJO_iJ$pp{PK>cu0N6N~6A`Bi|ETpJ~uSFS&xYki3)A-txd3Fib4vcM7MZPYFim2tp$f;JB -zst1XyGUY8bi?f*&iz=jqg*6Rv+FUnzP5Nav>QJH#%>bsZFx5dEZ#PPlx|kuPSTQU= -zmQXyG7qg1*rlD0BF|Syq+E~Vnugs+4Ss4_E6+1i4nV}$=GR}Z4W@Fi>rt2W`v>}$s -z*S_m6;A!oX7wU6)+CoMlU$cr&QQ0hG4$ojRCDpb&{vPGd*WhUyCfA+RXR#VAPU()# -zpbi^mC&ZS=%LL|*#M8!%(g@(|G9eG6LAHRyB9n0bJLi`xq-K?s8g+<1?oE95q -z28WUm%5XS5u6UeJqio?FEcnU_{M}r41tyrkq}zsI0#DTTIQjuPBJ9gPrgDPCcAVTgb$86=+i0&jJS!LIILaM&EVyMD#G3nj&E -z12|OP=yU~k09RgyZCORtF(}i0CX!Z`ylhuKrDvm@N(prNRtb2ovoltMwKL7vlaiL} -zl}PAIcAXh6@4tVzZD>tRJf)cFryw-#y1ZW~l)HUEm#-@xs~y8RpOHZ&uT_~U9?Ohp -z*xaUMLRcM%`>U1-ta@$-*tn{z7Wk>zarfn^#Zzoeafw7~b%qKf)sJ%ZixFxHvs&>xIj6FZsA@CijHF`>_fdLWhb)Du -zqR#l83inWd%~FCKCHOq4n|}I~b_*3UKUtb5WE~ZY;n+G*d6R@K5u;;r5AAr;m=w-LEM4jQ%q`+vW7^fj`3txloLx_Tu+qJkX95rgoxZ0@-^IB -z?5HJkQj#f#4R5}$h)}rAN@iDI9>sHV4%H0#mQ^?TILnEWEezKFxs$^glfvX^Y9(8@ -zZISY0C@VatvIA3MYa9wM=+>0hP+5$?LT**IkRPSN;c_|5qYky0khiRC?Tpp@*B{oFD}FihL2hFvi%d1V$puIbEE -zm$jk%VhmGewTe4OPz({4TRfLy$+Hpz@$sNcfg{eSvEtfTP3BX&($W;KZn7>uJo8!( -zGIf_#l+V&xZmCBK2S#h-EsS_Ed -z%oVfn#fh++%V#7?Xy;RSbK3}{nw@JjKB>r2Oddy^ijR$z$TD*0T852qrd09`^OchQ -zWS1%I#0wYNR3%s0@$p_wnM*Bn=JEE)WpwDPI3;tb$vOd&JSK}$;W8M794mz)zN>PAO^LA;KJ`iFNbn4_7f~#Vg?GsrBHERH -z3_c~YRnu56F;82O;<6|M2`*ogBff#6gc1Ud991r7X~|4hxXqg1#bjGj;?ES9^HvxO -zv@86hC^HFWhK{>Nk)m;fAJ;YZX@<~hqCSVop(cyO;R!`0H^?0iiC>bbCNC|=%i{P6 -zg~yrHOiGy&=deO*;tV+rrZP+khD6e8d|k0XbZg~f%0KNq$Af8hGtO2-Lxtj0`SSuP -zw)jkmd)Z@lNig(Sv8mSX4HQd}>%ny&LD^)mYV8f@Mo>>QwB@M4MxH9)I8@}VD?8g( -zoZ%|uTKhYy>L|1@RYn+hd0OK^=EMjwJEnY#vKQj{uFaQ?<>RCOer}_n6e3 -zJ9N)gQRa+%Ed@QdYOeOZVGgl8N`;jnp!m(AeDN&PdWzjd<;vm{Z&T)iks7**BEoE8 -zjh_lXS+ym`lq#>{)ac%&l=&KzEX7!jKXXQ)Ujn~@Yh1_`+GQ~~-o}2++^KwCq_OW@ -zo`J4VhKjNATPJBrSt;>^fqY6+Shs_vEW#+^`n6k8T>Y&S_git4xPme#i6zJ43HS`W -zVTCpviR26$o`WN+J()>W^21D|SooYgAnhf~&XdU!#xr8}g_j6fmdZkRW`>^>zN{%t -zU{(i-Nl@|l9EZo{$Ku8C2AJ;JDO~T-l74==o{Ur`MysWa$(GV%F-{dzd|4~K@ms98wq=?6_?`gQQma@y+0xMUu0nIvT>lg+zW0rI -z2A|J8>J;%)N%BZYOI;zCUliNt#CFva%5hnI_ZYnxzKuIqs<2W!)L1G!O&i}t;L*Pq -zzMVw8_AF&%uBg;ho{f;t=NqarrMMz~0tXw3d~NEsd-_ZVCM$kLb?{uS70*sG6VFry -zCdZuOe#rClOWVPu7?hqkS0LbvQ&gNV51(Sn8cR^NBeyvC-(IrrqcY`GKPpH20sB$m@LsXW=W=wo?2s< -zt~MjqR+Nd)Ze_x?q>>LdUDFn|)wbX@a(Sb*DQ*^%UoK=Nixf)#uSK%5o!F9L^EpP|g;64n^LmVEF#S`>1=!7nK33Oh=8+c0} -zkPq`8mNP-a2=ZA1`N$joNqxZ -z+=08$2KV71JOVmT&`;qRw8IPN20E|MJ@5v4p%31{d-w$XFaV$73w(ud@Ez#gx7lnRU>J9YFZ;DILDX`@GjE*QXA -z7zf5+0)rWkc_K^(bC?1aFf`L}wgfA%9&*iw%(iGdZ~!Nm3C{4paUr|eXaTr^J9xl6 -zpfexs4GY1K>;lk>$V}fR2y-Ze!4g;o%OL{jM50%bnLbBj-UKla2T70uTVOD0n72X( -zWI`6;3wR12qo^FfccuQzF7zHU??vx}VmL^4^of_#QST2MVABbd=E}$gDuR$l0AVeH#zV^S~44!vgREZ}5cx2!_QF26V#F%V0S~ -zzzT?jC|C`2)}hzK26Enr-ULF3CA)ZZA|#PBeZOQfr;tuXr^7bLfK14OY{&sRdFXsH -z|J&esf%9G{f_+d7bPl3RpcIb4F`#oCeFDnhBve2p&^bl=4Ej7=f-6u3)lds{P!Ct( -z8Z^RnxB+x-qFdoM+=06=m^RE0;1N85r_c@^K&KP^0=l7x?B1Z?!aMi?{V)JufX-L+ -zFZc`ew^Ij0fAYx!(IGoA%n~34GB6DOZ;{1bj$D%;avKHAO5}_$&M8$G0V6>jctA%B -ztxe{C8$AAT9z%AzXgx3hLl_5xF~)2<(EPeo4$J~>;XZNL`n -zzyTcLf8#V{HxsinxPTkk&q2Eb{^E+72lK%f7J?rvff1-c7f!fSW~bl#HwcfxZG=a29S -z2FSI~q`#4-Z~J}7{1fvp_zO(>+n5N8G#f1nV!$E0f49KL8k{9T2Dn46$zhf!X9cw4 -zkZXhYRl;sKj2LolBxZHsfhK6dV6-uhhB0KPht?;v0oo9ZU>umjcrb&BFbSrB1xy7# -zSOFayv^_Y26F7ql%mx9t!W^LEfu0ARFdw|Y2Nr@K1i&Jo6NnCm5C|u`Nc2ir4Qn78 -z2D1tCW{80}h=)W-f)v;S>97qlAQQ4+JM4h}%}(s-Z%OZh-LMDf6rc-XKO7*tL!?X5 -zN8lJ7hZ9f+Gpc7s|H@t*b -z&;xIPP9OR$d?4qK=uglO1MnHX!4LQebbgWkjs8Q=qW`TaHkw0bNwgH1rO`5E=Avam -zj-3D96OU<}6+j7;$+Zz^br=Oa&;U)KGa5aH%=B3ovpzW+pp9T0In&ooF;9R=U=9{A -z4Wh37Lg7@ -zFNP2Zg)j(*B`}z!n3s|Ba?&eEuS7?|T383supTx+48%b^BmkWxbTXup^A>a(nbXl3 -zupM?n4$#?)-Veoa5Dq~J9D$=i=NS4poFL~)^cgq{=ink-f-6u9bm~c8B~9-d$$TB% -z47bR+1$~>$chGI{fSezqACZ}U8BZ`jg=f$XUGNg~+xkU;u_N7EHht%wQr+0&|!GbS%(QVFp-|-M=gN{D_?G(DvX2Ghr6Y23K%{p_wz} -z?2g$3=D~dM0)JQpiy;*LUs-}{%V0UV&C36|?JAt3U=2jWde{J)AO>O~4(P;_PCzF@ -z5;-TMQy~p9$u0}M9d<$vy$_1vAe6viCww;nodM>tFdocc0??UAdNO(%%m6E}gTdHi -zb^s@s3A11}xWZuEFnho}m=6npjyKwe%nM1=dq2$n5I}Z8=wMh3ArK1TupA;`6|4a| -z(dhMLrq3HNZ-h-`w;3G+@sJ3qum#d#8)U+Epp!#754{U^lXC%jFBC!%?1N%B0Ed81 -zDf%dxPoT@70xHSw6zS9GGjJBp!Fjj{m*9VMh3u+^T&u=h1GP{OjXu>{e -zE8K=VWPg|RJ@f;33eTY(I-m>abd&yf!t(>?*JRg2x)=Qx-oYp62RZ}j&+rX?!f*Hk -zlq8-DKt}}422tREI7omb(2+q8BQqB*4~n1!!$BETU@&T!)j(OCbSUZA(8CpeG=wWNQ14g4YtD$*a?Hl!JG%XU^naqI)&&WGVeq0 -zhl6kk4#N>R4s^=Uc9Wq!LIFp_V;mq -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 -zL(cf84ym{Bj-214Kav^$1t=b$$9c? -z?|JV}&RC|c<8oqT@b25@A~h;Iva8QEWy)o@Em9Ju-FgelZhkniVgTcjH-s{+Wj-F7zIBtZ%r)Xr5-wE!<0gKvO=XV+^xsBfD -zyVlG|JHW8Qz+`32Wp77b)bC=W+U=UI6>lS7%qq@)Y-8b7`f0vHxc&8E&zp@^R^58C -zTk&&`t#4tzM4QeA`A2VW>uwRhb;_%4?8YBi5oadLiqx4oFOn0VF>Ba?1|)gGtoz6)WW8Dnq2dj_Pl}bM^JjCHwRSR_O8y -z$F%wSX;x5r#ibQ*rtz314~FlNbn$+dAvJELvq$)wYxc!42|KFX&C|!sdVTyGXY}@J -zh06GC>_0bt{yL>&(Bk`Z*vbg`fUBFCBQl#gxfUxHs`7VEEAUyq;SF!bntK;!L91t&4Kkz6Fh)8$8}%>s7lA!|kvDlZ~od_Jve_=g+2^B`T+-?g`E?ig+qhWc18BOy>Ir8PzMUe^x&6 -zExdgvZh>>u5F9VN5m=aSNeo4;EH?Ch~!o@4P& -zFXmO7hDN7Z&j|OcV(>LFSCDgUs!zW%_48jhgClvI>t#{8F^JJE7)Mq -z(*qNA@=o-mZhh5vm7}(@ryN@U -z=*xP!cAclL$Afo|{`*IB_zA}N;V!+u2!k(^N(#^Q@)sJu6f87)m9TyS -zr{=toXMJK!e~k7XQ>|&ge@06_v$GexU)Xv73df02YkFZ;q(@4IP4!GCLErFHr_8Sz -z>k3XBlD6h-^O_sxR@@_LYy9_QsD4!MEBWabKZULaQ|0bIw2e5q)9S2PX^M1q!}BR~ -z%B3f5?|*b6%=YCO$M`9?cOAGYF8!Esq{Z^q{@zw!?uu2LR(O15i5EDBK7TnrL_(!F -z^`ddU&&$2t1;0fO>P)^cPUGf?eYL*X33XKM*-YOfFP0j2uuOM$Ki+Lwp?S@JS5Ewt -zXpu0@#s|+Q|H(g)+WYHDyW26(DDDj2v+x0v;)i-O1e8Ia#i2G`vvvOEvg0pDJdIsz -zI{ww%z0aQ8KekBweYRBoxSQo>{a3~@Yj))Ab6+*ZsGwrQrt(McdSWN`1ev>D$^Uvw -z?1yHc{3o*|qOI&5*LE16naT1FYM+#;7#30(S^9f=_>mtXqg7 -zO!xa7c(RRg?{-jDi!a|x^1}CuDc>_L -z``9aliWR?a`fPrpcp+tA>U=mZMe4KNp`8Vmnk_VMjWH7~s^_0EV+ -zKQhlQk}cNN{rXmy09i~l-s-$d%Q -z^d{Hp<(5p2l-6hK9~sZX4`#`q6?q{onRj`btMj|+D!*HLj+t_`*MicXFWMktn^JOk -z`l$D|dB5+@{=~H?8)G^rv~zR`Um-Tvt>?Z(e_x^Pl)NLaA3HvlUSAQNw9-Yy-}bCs -z`OWY9N_{%3<}ND?T6XZRFv-+Xe0*uCqKQb#G}LJxb@P8PCq@qvC3d -zicyhgliuvx%)=B~U^$vY?S>CFybjQtJx~9J?w$_WUJbrdt -zwlMK|LFJ}qpQ4G~r!x<|G~B6hrf1?5$?A(sB6hP%_PWSb1WSHd)1UNa_eVz~hJ5t< -zXx=j4jMf;H%`-J?f)&2G{^&^AyC>&I(avT@h}QzP^|uSNeSD(3H%I!M9q&5P{b{v@ -z$&%P5V(Bqs6|0AB&OcleP|J%xQtG@z;#yJ!<8x;tEA@ASe%el>z3ySkt+k_5B1LVx -zw^?+LaAN9R)z-_;v1s)+nVHh%d9y!6Z_g#qxCR5q!2LlTWdnKl8TPL75e=hUqz^}# -zUs-l0`{?7(^~zyaA4b}p(p@n!P=A+8DdXW7`Nq}94y<)_T>5vdLi5Yvw#KIe=jGfS -zIeJS`^4N}x%d}=@O?s52k-0}KCG6AhFXkO#pOdBE^e$~@TfaMYyS4IHl(xhEfz0dl4kbF -zsP|{$Z7Y6um{GiE-m#RhA19MVH@Sc4TEBXHpt|3;j5*wmXZCbfJYUh)XK#I>yWYH} -zE^=I#^nJTmo^#c;;@;2qR?5p*o-`vU_ub@V`|vMQ&QIYkJ#M{(+P|~S{zph&LHYg% -zk1U_+s4Hl`P+jV}dbx~B^>L#;Z)`VxT2a5%M3wn^-p08p$BcgsOYh6zu61_u4}G{v -ze9|hzW2d)#47?`xz?o&Hf5=NTQtkIfnJaSwV@fuCy6iLAzbfVXn`C*PXp7nLYZ@2_ -zcWRnlnp5L^uHf_N(TlFFedLs)B7SLxs;<55b1(18y9=F53s$wQv*FfkY`b6L)Exh< -zC-?Tcy~kp{wkJ?(uMKX_UNg`WS)n-KmBCB0F+7m(s(#$oNB(`r(~_uB4dzLb-IE_J -zVR%pQKPLZf)rHEBOKPNNB-Gx>jCU{?$9C6 -zeKV*2y1V1520x8n_c~pnm*=Qim%psOYWbqXp=W!v<71QieRhscch_#V`GUvq50MVn -z&l(GkdCjnL$nNZ$+rK=Vt$z06miv0PkJR!eYhFu9=`irD?q1!Vvu2Cgu!jq8{MfuE -zQbb?m?iHJnvlg}vkK*ik(6uR7HaJvJefQg@7Ex&BuVnO-*B{TY^ -zM@c5hw3uBQaboH3C_i;4GZFP)K}YrXmopT`Ufr)3r!6s|cEa|jy(7kqar~WrXQ^NR -zF819*ot2{OqxcI?cf*q#${<+)a4_k^7tu!?%qr6JaKKkgXX*S9; -zbn%74%rKu{>#7&0#=c#5_>Fak$OM;^!@piAr4@S^WZAt>7->FwDn6jEpWFKEYWneh -z!&7&PKYHpNDPO!M5U;nT;KI)GH^<(V{IZ#~nw9!|`MM+)zvDudQs~4I=u~B -zWS0HNj@%Km=?ll(e%X^p&5;M -zrNz-UY`*GUs&?fLtC_C_Ydpd=c`3!c8m&jhUMOSD8hG+{x`<4#ti#LX!;+atC)~KT -z{K@W$JD1Y3u9q#gANXsRoUl+Orv98+t+!I6XTiOm-K9lJs~_!JCpPeF^L(d9pG9Tj -z`#IYSHe7q2DP|mUVo9grmxnz+yPAViE_(evyrA*6(Z|@%z^_edj$~-F?SPq~QID)kius?r|D#DcmpPW}Z*&bT}T`yJP;u?mMzxeJkIu -zSvT%b(AY!Nw=q`sKkSdP*H~Qr+{rsyyWq>o*^Rf=1zjtaADH?x=VpzR-M-Ve7MxzS -z*zn$?pEnsPvwtjH6g=ziVf#vl%&(N=YGuvo2I*6eH1|1qcHiCAbyB0UOhjVT59u5& -zt#|UD%8!VC)Tq6>P0G2~y=l1h<82b9Z+bnqL~Yy`eW#Y?kB6|XOycLJ0L75B?bjYn -znpw}%N-};fRi=a2N7Irm=&HQxD=U#~bAGSOWIajSr1BjhDxu~x@;fvuClu5*t{D~+ -ze#~}W&)v6kd!Ci;V`)lf2boV_ST`_f!ZN!Qod;W&CCAQF556cmW_bPZ&fsk<@ -z9Jsl&?Ummv8#%dz=d5mCyQ5n@dpEcO-2+H -z)I2s(5dE<9@#lpX&py60w)?H|h!*D68=-e0={mZZY{UiRwZgE88z+=vJsqp2_)2`K}e%vspTy0Fi^&9)T$7B|stlRz2C*XP6 -z+4h8myDZm;Dk%ANWJfG=e(Q1UhQhk-)h&l6Yo0H2o$h#I(gx&FWK4VT#y`Q+pftf5`Rf&)e$svt#p!-C37ZbTtv691Mv{f1noV<-^Pk!~)Y>%bo$&iOV@6L=1p3v%=e@kSH^$D#n -zk=l2ZbgwB%95g)iHb5mWqJWX#@xE@rV_N=v2UYuv2CL3Z`}K2@Mep6@zE{Fon)Oe* -zjJ5RBmp8Yv-6}NpOY`@5KRz|z$j18q$Vt1Z{nu}~`Ey-($Q?n*?IXJLH~$LWx-xWW -zzFBK|k>IP2N8_`VchY}l8P4!Id{0XuxL--jr_bT$7`wJQey^6N*a>af=^F#bbuUP< -zYm<1@`*ZAtM3ZY7&RV$=rGE|>6@)xmcJBTprfOwhtf$VhITsejWa+%We6eW9rEAmL -zdYk&PBzQ6v>puo0WsDTL^6+ao^HA^cpPNHp=B?Z8e@^xAy_qXDPtKgUbej2rpLuDC -zzYp%7o!Ym5zfRRC>Gq3_**CV0T5mhHUMa$JZNIvW;oNE8Gne}MUK`I8nfggf&a3_z -zbI-BzZ}MMrRF&>N+o{=;n#8Yhv74T-k$EMUb3f#=xXTx@(b{`_pB`_nVV?0dJG0I& -zz^#}a|1(a_bCdWD`&s)lYYk`ZUZwr8>xtytZmqRyYWA6hvIkFA2!yi1`G<>@{2F$y -zTjF9m^6K%7J#u;%?2o-yJ5=^3!$0#a<;blXCK4~-aLf71#*=M*6J&YeX-`#0gjm#S -zs()KE?Yrq}s(&tT_LT2$LNvTXy)HZYuIfvaKUJ^2ZK<8| -zjIvOPUtb?CpP$^)!Y$uydn5JP`ONjtMu(bwbe`Apd!!)kZJVt4u~p+$tCIeLMPd|j0J-)FsX!`JJ#FS@&9;=6j@ -zsjQ1{B|qwUZI<8pxadkMd*res_ixU7(Ea?SQ&w%|j@=XVEP~FC7I)_z+1fKXvvrnx -z=~07rt8X=K!>UfMzPC6|wpr*%yDyqSJ|$Newuf)BF -zg4~1CreFA*TJmti@aaF&Cf)OqdHdUGU8ss_)VY|0V>fJdj=X+XF<`--7kZ_5Tr^~9 -zzbPKw5P2d_N>Ew)$oBRv?mhF8+GKMDZ;}=*ZWh#sXw1?I -zihf&hU&Bf4ezS!m`=eVHf6_NXck@5+obeT -zJ>qz)n}vN^ep-0wuFhRkzP;Xi;b8lj+`je@x0;g@-Y*2Q*Is`3@<}drX?A3eNBEX` -z?=*sUA7hWZ(?7pEr{#dMXZUBMd(4Y316Rs?@|rlz{}$^-F?;-W&a67lNHykm|KRj^ -zvibj3jwQtw~x-9yERL6L+-xsCwv< -zl5yI*)WVL+I3G2Oc}d@+CtUnyQG0dC&hUGzro7b_&m6S!@_RCqd+w)%3p!>Q+i7Kf -zZ20*9adpk{c`RQ)wr$(CohE5)Cyi~}wr$&JY}-j=H%`;|ZGQLOxA*q^u{+;AXO3of -zKhI~L**X2;;l|R<-o+6D7Q2z9iR(=g!sk4AcQ(B3*9-ICUY+kH1GQ8jZ|`A2XzpDm -zRp;Y$GBwIHD99w&mOp(Xu`osZ{8phXhG)saPG1%0#fn9(bD>nqKCZCZF46`=)~{@I -z{?Kj_-E_E~Vvgtr#yCj}S_5pBwE@H5PDZ_B@wBX|^IqZnd>m{j?6O$?$%{;ibCMww -zt|;8ieA8%uvT{V^>1JzM$ZqJUB0U#e>en3ajU1)W3{+#ZoJOQibe3_THQeJ2qwVGi -z0p`WNr9ZIf@IpcquR==-b$ZDh3fX{c79#>?2|UbA_~T`no>r2uk*${>a1}LXwR -zy=9dF1@{d9!}gMahH$@@U1RL*p0VTICr@l9`jQYMGw!CxC1i3nbaO(HOh)?8@Veun -zAOSyIqW~93G9s;xMZD(}-Qs&DqyS#I?89Yn6DWM%RDvIOl|X -z7ps}8r~~_Y&U36|Hh^ER$SdN)W}lC(qHqs&GNcbO!Kme`**1(02+6-}y|J%}1gK(} -zcGyY7f729jI(}d?-bSsV+6$F&%ym}gYsT9fC}oi?86x3efv#+l1x0 -zY-)=uJpWF0$*-0k98N~r4f(~pRIjc7i83b_k1S`IVlD$6tXK0LL~oauPf<}}W- -z3D3+lnjl@;N{{5UuqcglS8w?|O(fF_E1z_cs86CZ+obg0T53{gAB}r?(I(ClX6tbl -zCi2V%?1eRiv1=ssn;R-=HW6-VQw1u#Fg699AL_qm=3h#xeM>*vz7il(cy?5 -zFr`HW^gb}Z>eEaVg;DoY>`a{{97$}t;AqO=ZfI$1chW!xSyX+JFZq}udq4zELANxl -z**|s0Xh+WMTUX^(sz^B*hkU;Marft3cey6_F51AUC3HE+F0-|9bd(F3>~a(G5V|%@ -z>)!X4F^bVo5B+zwPlPR4ZmEb&{t8HJoCBlW$PMu@}w7_R|Nd%(_Eu+#W*LZ -zjxZ*!*Qh=EwgC6VJhsio=sJ?{QOH6-f4G#T(~<-JN-3JJynVfRp%zF-D&?SIbjpB;`A@Dm@0@4tWI$ -zPKhTCpZC~%5-n!Tr79zO5G4I+Cm=~ -z0#G0Ms1{%101Kwc`8T}fTIW89UdZ1P$w;!LFCA$em+zDtANe#m%*w6ig -z5cra2R^`UzlCd2`Fw}VR@MJfnS5vN)2CnH38 -z6XkEjP$Ya|y+5V+2$~n*fLo&rK`awgC#k^IP}|j#KrI|ze(jQzp#wDUGWROIGO@vv -z1zd;{EKuL-^vWS8EV_8k>dJjvyh^~63ZjUxgGI)gnXS~XsA#v8zaiNtZ7mUzpl7%i -z)4DwYvgrE=th)tq=*;>!xGM$%v?l>!b{Kqf#yQF7!zeAP=-f=5y_R*~KxQs)_0xvm -z{E%jib6;JMfRZN6K0!^+s+^DpvILgM+tB%;xs9`2 -zhws@{({?pso@2p&k1oiRx7yrFr`6I)MZ*N{YN|_}YzP;8X~&!g+iK<*R@si!#Zs!IRPI -z*7Q0@RhcrIUt;n?X{R3B-Nh-&?Jh+9cOc>~uX?g1=DiaY6Y#`?ynCCwtVC)hzAw!- -zHfSzz;m6fCY?-=QHB;|+531paJ8AIraq`kpH2v_Ig7g)Uef!LeI80YmLxDaKYfTC* -z72jV>51Ch6DUfCYk`6R@&YufD@dAvLhKvAM&0%0X)HntHNO|r}7ant|s~6%?c+$?` -z>Hs-w?(}IZv0H6i&y7Z;5w;zdCjR+)D?kys=0;Yz>Uh7!xWA*|{XFY)KlvN*k5Eyo -zXo>3^K`6b(vPzFt|A;{Q&8$^Miix}z_AV`@kk2_F2Ku0 -zBq%kled(WSP8$O+W+v4Qam{q%;hcf^Y8(BC!&x|Ec*32eh)}&>2xUe?!#S04+Tc6; -zVxN%PI4_CwcxxK~6YE~U -zruOjlqfS(IK@)o|EAVg-#o?N7EL_W)n@DEC_%n)kPL-Y0>>+%6NS+QayEX}#sVRQa -z_>7vh6}zref43W)1rv$<_hwJv{0 -zu!?u~|I(YUdD0d)xbQP=b6d#+NEFld?4)l&1)4F2`~JE6MhwT?MHef?fACHEz|h)A -zslil>Ua`xF!z&9Dr{K-Q$)=>5w)9*-qz>w_K*O+Xx3!gbgG$hJN0hH{?vAkmREw+6 -zUQX^=I;F%ZKONVfRv?BYrgVVi(Ts2q)SsP0J0l4o=4b}@u6H$H%kju%Z%jbyp$vo{wC|QpP7h6sIZ9ly+iPeEN6-88qG`Rq=Y7M -z-w$P74!@dD=kCFd12Bd)pkr6hs -z%2jrgJM?bs!_~dH@~#WedY7HfK1>&>6E&1DgyV8DvqI@L5g|@Y+G_N5A2zc13l%EW -zc!h|7%$!QYDncYio&{L17Fp+5HbV)@!4}`#9)8tjx#0!I)y#Ya<-oRl!j0DBq4{zD -zV6wiw{Y+=tm?NMrU5uHOar?vzF#X*f;?s;ddCmKxrSw@dV^m@qzr{{LNjrP{7oVc0 -z%sq^)nr`U~MG5!R{OHF4Ri#o6bKeL!*-_4Ob5NYlG2#N6nzuxIp?Ktzqac@QjwKCR -zMKsc1Th^Y4svRUe0_jqEfaU50ggQ&wR)>yl^@o+{ -z(`Z1RkXm=5<8>pC_I4VmiE093E|I!>H@vPa$tEFs-Z11TbD -zXL$q`#TEUFfPlIY%JY}WYm-A5W!l5Buv@c_I8r9wvKVOzfS&Z|2@H%6c)A{A;=FfHHWxFA5xoe~D5y2Q-}HK=GDx~+#CG+7u1>iFS3t(F-Jw*Mq!{hHOS -z|4HA51v+9YVn$S1w451S4Gek^<{<6ydAA5LR>(9G!@Du7F3(o5a-5J(^JMEsff#&+ -zSOZ`6I7eMaY;lN#g_jQ;sh&0J( -zBd5JYvmT~XENAh8fTp~LL9=u-+%?%wG#!4A#u^LCA~jj-I|+n)#_9_4xVnXM6T?X@(H#`OQN)i%N7+3~`(l$}*tm`QohhDagjUU%$62>Ih{5SS}e! -z-dU~VuFxHnrde{oe~*u(zA7lI+3=BmxIEF;;O1S@GHvGw$mS2*EGSW80 -zQS4ey#7_U|S9APj+Fvb^GL?GaF#FV(N>1ypGT}RffL+b#%?Pfe+toVgJ2zL8AMN$H -zcRDiCefVYt|MzWAcOp@Chu(NR^~k?X9y{aiWML+K|aZxXvrt@*9ehNMNApHMW?U1pg#1K#F@Q -zB##AuTD=3cT)BTG(N_S$0a7`e{4G0(6Q=&6&f-uK0oO(U^V_BtkI>5Sd(8 -z*mh#WkI4kt!D&GfM{;~pVM>5kP`2N6mlpnYd#tW*9NHM#9NAC4c+|J<$gOhCne`?X -zk$ylk=+W4=a3e?k{`3yqtwoE`wfOA&{jiW2H^1fCvMq2ntEOT@S-B~uWe>NDV8YL- -z(&qdWih~Y(CXAj>xvshV8pcDG`6U!qUu>07rw^*umDk$iFY3_h_;I;ne>A&j5*GW{ -zl*eGWm4HK|VNkrVWZ6vpSZ0*<0whs{Z0cp$XTrF+Xn|oT+eY^<^o8xoEso2c2KJUf -zl$e>|X{sNYDlSvEQQjm1tNJPq$xLs8nPwAtd3Fw3Exw_Eu-}xbiwhHb9dm9O7Pyfz -zH}AhxMsVrggAMa`HRu#v$v}$Pf};$EmMhJ>VL9c}=L6d;kH1b1%?alFxvvlZIN{KL%R^;?-?>I7oXhrgS#9T04-}OG#aML+tApCD -zS9yv$AjtmP7QaJdTRm8kH1VMqvnlzvRa)rL;BURGe@=X~`BidLr_p_tR>SsuS%9HQTUbmW6i&FdVX_2jK*kWbfkbYjlosnR$6yo(W>c`@gBv}LR0XU&HX-R5Fnr!(hg`j4T6xA#={m{zvLGX*V3UL9z; -z5DBy`x%;_X)alY3)MCp?waha5Bz2CUV}?!nPy=)s)tGbm6P_`v#SQ*+xRrjF6z&6D=99$-VKt71I&nY^^55$_aTx -zqDz@tmjW?-4zR+mu~e@UDIUXs!)I;T1Xdw%Pc?yvy%bSBU#UQAwMQAyvme9L1zJHD -zP;*C#;ZqTT=e+riKm<8bBkCzUmp(L}pomRenz__IwmqYi8bQSupTwX;1sN-)DjbNg -zX0msH7UxBAq~^m2sX3>M#Fhdq{B4F4oylelfg|-kB>9Nez)rGNX{)E@mF4F?)RgE39lCippzj`Z)39ySYTKVap`|FJR -zB}o&#d65tSQJQPjw6vR+bGFm2@0aOnqx(GTKdD0<)^4z{K`Q1A@B>-TJf>x(sKUmo4|oOKB{G)uPH2*-E)yCeqpm`dgt(&nSuvs(Hk{R-a60 -zw|qEiNcn848f)KbsHAr{ScZ!o=Jexv%W)O#?m=Tf3>jvR3ULbUr|w-#4^2EdiMrQ* -zl<$Gw7!1^i_|8_tZTwpjwq!U9w#rs(Rp+zX{1MTI@kHkRo;v_WVdF*GH4I?XoQY8 -zdJ$iea)$boV(dMw^f}C<;wuI1U4o3rVPb7YM%^IRi5Ip7WxkGZ{{x2}JLqRZ{Ags| -z@p)z4NZ){1Sd}_9=BWt^b14d!<(6lV7tjdcu7xu38({UK}*78 -z+N6gns!~=*!|{OcPcRT<`-96yZbhI& -zml~Rrj*14lH-HIjpsL!$0_Iq4#0AHiG_)_w?Rg#Cw@i{`L+?u!e3Kg|`wwH3CDd3n -zV@xfe3ZubD`2)MrxFpvPjg|b2lCWLW8cE1Hqt)cEXm^AOQX~js71aD^WsdGG*lmw` -zRQUG6z-wTx4^AMxk0nNz;L1eF@&~;Yvq8)6RHL+Md;E<#pS@@|V`vRi#l8xc#fDa2 -zOyBr2Gbf-t={>5biYqLX1&q>(uSJ}8a!lj_uA0&YxTn1G3=J>ab(Q;s$p36ep&coO -zQxg@6<94n-s)}?%?B}-V<%N3LXj7XxPe5wHS%A%qT7@k(8(0v7_D<`{dy&>OfH(=1 -z5(&-TboLmtciDBiL3yV_W^!s(Mk6iM8@GgL)k4R0=4XhHcIC`TCSmx?*XSq7M{jVkOV@Hj@${Yt!i!9 -zy_UWZtXA&Lz{mtOzc<&~@~7Kv9|*J-U)i-beZl_;N_{lJ>^=`3t^$2}+#z)X)27?)aeTQfp=j?e6IfR{;FEH}3vjO*+25X>QVezt->oqv*h_sj9EN=2MG?YNe64(Y6Fi_+x!0g(9IYotq -zs84{*M+|(Qv+ki#Qdue#Zk!lW-q;l3l7n2^s!EoJ__xrgCbM`t5#i3h1i`iMsb?KroTm2kH9}; -zqqFeC-Mxdt5Sq3r>3$`trvnD@&_mE2ZnO_Xk#~uJZ044R>1R5tauZP(+9B6N5n&5- -z5SH?uFvEZbNv8ET8hFmWR^DgV`?X@yspn`>5O7!W^Ne7uLs`L63lKkjo@hFe)d+`( -z6w4ttO*aW{S~Vf9VNn`AlEzuCK`0zbPUbf;K_25=M(Mg6f%}fN_6F#V&A5q63HRlq -zbFRItq$kDrXwd^>i!N5LCcV0ywctIWK-ldRa3GQJzNgAldk&IsGa-DwQ%CIz=N)jN -zpEhrUcsN#{J;p6^qlxJe)D&>!eF%oe?XYJ6r;&X<1tcPV6g@K~1*f -zA93@=Ge(_v$z>76W~gZkn{>}6M=6SW7bg9b8 -zG3K;3uYI;jKulh``TLBzlDW^+BynX8(zkh`=8Uk-{Q7hKE)!TE!4OsX30{1r_sji& -zK)Q%zBjes>)~U=_v$2_$ejNW)j9xm5BVoX*UlVV%j6?5+RkXM?Scvx>%?9U@TuyhdcJyoVVh8Uj9P~{feQO#y*5)!n-wXXvs?Limd*0$DS~R9eG4F` -zTm~jq{0f93!gdr>#=)-26y4;(hN*tpiHdVBEn<(%#g$^)4`jx8m-<%1#VQK?kpi;* -zEih^fy^Jwq37aIS7Q8PHPKj9c$oDtKUE2$T^EPU28*V50+tP~oTVdr71w?MnX;Y^1TNxGCmJg8 -zQ|{k9mNo>njkL2|2^i}KlFKw!)qNU-9tb88m$m9ZlY8PEjH1w-t+e6Ky_1H(n@PeW -zV*X*dl<0%UQDK`CSM0KTX8z)Hzu$13UDZvlse6bY=^557w((larX2wrR#U60z=WHh -zTTwA^!Nd6yG-ymc;!L1zj&bP>8F8`fa@R!{=m_!LfI1y_U!OoQ1$-m?lBSeiPvk0} -z*B4aoJx!kG&>=yI9-pE`-y}6`vvIYC?RiqQtQ@Wm~<=&`ObgC@w5zoxmo#Jf-#ofz8#W%u@;`ta27;>o7l?ibH(g -z4lA+lar^q$ZZKM3&JfGF$9DLslbtxhb3GuJ@BV{&B(1C7+~<%Qb>-SERzbSW6c2FZWN -zc!AH4Y=iO_d2smg%R$0;N!1EeAVq)Wglx_NRvNMaVEXY59oSIO#I=q)3qz<+~oSG;agZs -zls#B+VU0ccVr9o^RRxZM+=Mi^?UQO&QGmpHqjPLwUG6&Z8p+q~jO{yKha>Uf>kw|V -zOVP{eR~*j9J8molGhNLM4PzMxR)jr-+|vg31O^Dpef7Sf&<6nCP3koNZ&UPjAuzG> -zI_@f0T@iVj;QC35h~@863pzWi*Xg+&RH!bT2T7!K=|ny1&R{7L$E{)e>J&#QU(!DH -z<@1|($nK^^!n20Y0wkspm;GALWVN0b;iBb+6J^Z}3kH_GJ_6^(DV*VHUbqA0A9vHD -zx^=SmnI+H5A|;;&_PXS)(BW9r7lyhj&az+9NBFxT(?-N?y(ygEw4gtM`B*(&mArUe -zjv%{sGhf2IL|tkLYj?_KRz|=|cLLy;%%^}CC_xsTGPrqz2sKp^+4@*Lk`b&0W>=HK -zQ#{f8;J0ZNnL6?AGs1O7dH&f8)XNgd@!GJ -zI2rrSBSBo`jO?xnh;7FIEG&(w-1_Ol?P&J5K7k!V*%d2&JhUE -z=>jveGDXodhf{OBiy=eLjcLs9a=2s;TXgWEkx*ij_4#&C%{JV|O9KpM8|M=X>QigO -zf|3V>;8$dY_QDtK!CIE#&*jL99AwTOM-KzR7wh9ixvp~U^h8?1UkREM?P*fy9bQfeKwc_Ozc-{PJOapJ1owG-Y+qwmcH -zV@WYSISe~Fg_z~xQ8M~VS@kovOR~tqskE#rL?WpwWH$U%KkbcUB8y3BttnOC%W=Yx -zB>&JtWru@PS@J~Ed#ufAo8G?Dmz_Zo%^CZ+#I(=+9Ce#eMykrYNg?!%D?&8tcB9XZ -zZ~15QvXyt(O*s98$!UpnW+0FmGo#?PNyB{26;X~3nGyDs$O*6%1vHVl3qlv;O@!>d -zkN4PG1ksIxq>$nuC!#U~yh5ACkBZXs!aibTZ(i`G5(wY;=^aXCxf;!k6Jb?h4Iu!P -zM69i&1>a0u%S6R1fZ?W8D*YdXm>G{4%U%`WSi94rFa^y*QQFb;xuSa2p$$C;g@qan -zn7Qm&^k1!pV5dW}{UW;ClqofL!YvEXx{gYAv+IdRAJO;Qzo;7{GZB;+!_UFCVbADo -zB4Cg7YueIF_nU{4{Pbz!3s2X0Ig1bRM?Uc8R6i6_7;2*rY>mqQ+M(Dd>CN9%@hq-J=YY -zU~j=INzeX$Rupk>v(XM`janOE+2+LI3;T2}5?O%!_46oxEg(S|+%w&D0cjDEU-)Fs -zBnBo9X;Fw=>BwCyF(LHBnakJ0hM$!l2o?pABqVXNB;=SRNKO^?y7&9wf{`9YOG*rH -zujjCy$Ti#^2c-PVh97vKf=cqczY{qZ8~w26FJvX;APzw3Zimz31K?>o0(^M@WRvsS -z$y{5I$MGFSaJgj%3Bx;7-Fu!&4dQ2*%B1em1m%FAV%H2B^&smjYZO!ku^=8H(X@#l -zA3S3QsQ`fQ+L+FruUf7M^|s}h$C)b+q{nCC;Wa=sobVYAhvPY}*9zKTB6LCUNw{q|)mG!u -zB=>gf1r_sqtw$y9>uHWURg6rS1>c;z{Osdva9`G}NTVY%>-*Nn?bcuaGvdcC01sS; -znIdu7D_6IJIz>80dX#I4a*kLmo!|}94zp+C$v`Mb9YA!qS_K!{i5`7c`MlH>65^=}zt?g+)UVs3AL@L@i{K0^%V4w -zO4-tS=k;H&y;*)h{2-5@(}`p8UsA-@L5 -zP2o$~m}Nd`{kk%~=^efH*+AB0Q05nWPcZyAKT7^bOIe{h>8YbX8Q&T0_2sX< -z24xu|JUMJ|L1A_Odh`zudYP>^+~pu}GUw*M66e(P3CHRZkC!44`g6xECoChSmuBIn -z74qvdpzcw60M5|%YT0@@6YaHj)2j|;jwfF@0^*Wcx;Mo -zCP#maB^RZ}+|7{29k?Oj&0u)y!c1)P_pi!nn@Y?Lm; -z?|)bbjtz-nukAVG*~#G8+x@MkuiD<}E}?Zeo-XL85QjByUeWGVzh -zIUTh^4u!XN%U+ieNhYC@pxLScfP)$7WFS6{Od3gX_pDA(%CmC#93Q4qgSS#ifFVJ* -z1FjaH7MIWvs8l>awwRY5ciIv0*_$L332$Rw>G4;@PG;GKnvK!St4nu- -zg<0`E$8AUEb&hoCEf(bkK{U0_`r{|*%NHYwi#bXXVT`t3W~u(d5Hh*eOg6 -z2LnGoegYr6u<_|Fg`=`aY-g5c{Gyb@OVS=ZEXZLD-xLeabCVJdpoWsZGY*C-2W)%$p;v&9Eof&k+sJXDAvjZ$jCWwF6}@{M@Kn;cv;(_PSX_ -zg($ItFB?UBlw_IqtH -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 -zs=$HKLgw=v!B*=^OYU#jdWVWc -z>jxmuDT5%-8M0=48o_E;H}!VN<3vr?G33kRL5q=A!r99;%Y`}~_{OW|Uq3-LwsLf7 -z@h#hJc5#>`(h=sukQ{onWI;!P>n~?Ra<=5!nK=FO^TrtHjvBys;ESvJLTyEnsMTUd -zKRwtYy3lC0v6Vh7=o{Oo3geIvd{eV*y-n39#vwQ8#qmLR$U=`R_#SU{f^o0}YqT64 -zCYj;qVZEp_>evc#94E#ORHzAAE)P@+LRcc-xBw~B3Eohp9-)M*cRqtT4@7bKndYp) -zRyrHvPRbh_4vtiiE%Yhm(CHwt4q#^%WrrTpqI;m#2#xd<;tspTjHbf?BF$+8Wl7n= -zh`k5Us~w!aZcX1|w>IJ9k!WF#x-CU7dHSGvhF_lwf5N4a<*2|1fm-oK5A%Wbc($-3 -zPa4~t`1NmS-9P)d+E*9d|=D%UebuEsP(Lx`5^ -zej#1shZzAr>{`P#9@10QSTP8~<<7gKoK)CJ^d54yvR6LAh!b%E -z$Y73>`n7vwX0G!5go`nl0s8(TsBw$c+I2_U^8@ -z1@Jg~3$C)5z}=U^_Ji&a%$Dfs&G9IOrLPV2c?QHbt!IP~c -zC{7jGDdd`krmEN+dr4wC`%of?<*hBOyB%V4 -z0^{??gnq-OLkg&nF$3xyLZ}0T=g|xbt#+Q}E?5qu7@#(*m_vjdX5IR-ii_1LpC$EzxT7PGKoE!0O};JQQFEs@~>n&%RiS1?S)MYe57Fz4#}6UMxg3o0H1-fz%U -z#U+p^A&%{WzFGF#e11yRWpZF#F_o3FYJ09@k%()ntxEy^$%#Q;^po+AvGEG$6ZjV1 -zx6~U~@;-P3^DA_#lSiX>UxQg+wFPH}R{}^li9psYP=P+@mrzN6(UI#gg;JIESq1vy -zt(~YFPUp*(_G&HB0L9aj4937AGL(Z3_X&$7HXk^hmYBe|MdfgtAB?^wQ!@<5`1gGzSiCenP`AqQ -z3bg6^R62gSa-=vVCnq6(O9M-o&(A|O9BNE47cd_hL|f3&%Pj`QbI!-y3DNCHaE5=p -z9wan9vLlIt6?>mC>93tye;*lr0RJC+Y)jvB@L%lz_rCQXLLbe5kH+8hQI^5#pV|z+ -z+8=yi;J=xFV?f{E_@ksr&dY!CX8M0|^dI&B3qbx~;DfdNFaJJFbA$aq`+xR7>YV&T -zAM(GW`Bm597uNiT`Rn|FKWaYzLm%=VH3t5nk0#R6f9)&$U5oTX=7WEY_0jr^KCt4y -z;`zYoX@4_+ojz~^>~D`g@L=43`Lp@|wU?dooBxqNz<NuR^2O?Z;}89tssF_h -z+5g44AH~f7CZbGa`hd!1+^kb9!m(TPY{;xmcKl{`Fy8hvBZpm-^A2{`oe5!mH`I|nP -zL;o7j5BbGE#xwL^4u8n+lm6ZL*XaYZ{4qW)iNE3`V2+x+eC2g`N% -zxBLf|`&a%y`XB$j7xS;?|Lprlezg9g4||}0;aKCG(W_@k@ZzwXZu{o#MyzuSN4v-u<5TC4x&NBLiG -zybpb-qZN -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
+)27^ZcRcAz -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 -zRq^Svu&-YR@O`X{L7d -z84pJOkxz2HhMuUa=7!OQab^!25~-e{S4rzZg~^L1bEDobl_tMe2kp`a>07~ -zit$SS}r^`#cCTl5MYROPo- -zoq+tlhMeEKYa#MC?%L?3cz%3U=#S^TA9t0<_f%q=+ -zailyhnhgGIEc*+eP>=E<)E9s4tjBo!y94l?{-T3?g+A-GO-FB#Z=BWjd>^VAttSr; -z_LsB0#XOI}egy7w`ZqlTOjPCtuUF6gh;OU(!5ri_UwCPwws@ZN_uIkm?!V06b0@?? -z`o%o{2go -z(UYn}teo~^Kqc^}uxC;ql}7$q)Ix*;&6lN@Jn$tKKd?!MT37b1F2wmBTH+N!5VovECT2Yrgga -zpASyrc-ogNIx32Ipxht-1XyUgD!wv$jgD5R@cygk@V`%UJSD-;LiG@Ty(gaUk=>w) -zpPjOqX$AaI$;WgFM*fe=pG*(?vQ~w!9YLr^0DfsKo|o%3QEXrKU(RBoGD6+~n_b_N -zrXa@OpYdGx9u}&;o#Vwpz#Dd~PYLn+ys!t8!|e1(TxSA5y!8t6|H??@Pr$#85cm7d -z($hEx+mGcVP4p4~ -z6|VVySl&cYs``t<;G2R5v;Xz{B<4@$Z`>_yqBL(DlunF41bnqd-~WN%+fKmy5$}=T -zv+b%DucxtFD0K|)pN_3CzTeFEon51+f5EqO6yx>UZy*Qal@jl!funHy3HuMtKbWYX -zALlD|NLJ_@;_Gt$%Ep>$S*VxWU)5bkevY5rEzb+E{|NifiPxR`Z(Stv>nrfzZ=9r1 -zQVipTl}&VHI>7wjD*(^Ih|kLPXbAgpS7krumeIy%&ehf0yTyJ6+Gu9|x-1#-t=k+A -z4FLY{l$O_XS10IcRXk#575D>{*}lG*sH5T6SU>c;pwQcW?0+={Fn{%)>yI8M80qQ` -zj`#LC0={P(+tbRJ$f-9y-SL|j9TiF_&+{{+mO`Vt@$Y{hKz>FVmj7WR!C$vv`TF(S -zL{89UiR8YtBy=9YDA4GLV{91+29xuZ6Dc-LI -zeZYUAzN@Bqe%$|bq`=-GjNsaTxv<`4fQPP&>(lGt5F;KW?M*fq@(;*Qm;UM==$BV9 -zHg|qQzTzXZ0H~5L&&=(TFbZcj#%L?1myy?N;?{T>O -z@vaK;d0X**IrIbeb+V0u1b&zpt)nFym~Y83%tAepKOyBKS1|aC@%+6z%2+82_))q4 -z5>Fx@y1b1Vi1BxUJ|BqvD*f?1m5elUhTWZydbJ|rm75qJb(#f#cda*JT3z~Jd}b3R -ztKzo}iYipLJ?GQZst^7g{O=6$K4%_Pj=%r&Po4Im!$TeEKk)jSzFFwd177d_OTe!n -zf4Yl!pZS`B9wMJAuXx^Hf8f_2pj+k~XZiTBQ%|1|UkDYy4~2g80RJlW<>cvC<$kL4 -z)I|G%pQU}-YY -z=Dnz4F3$Sn9rpW$tvo;8`*gHT<ZOqh95Pw=18|X|Dnbn(0$f9^c3)g%WGC -z{t6zA`1?1$Uf4!QbrH{z`{~zp6Xo$`{`mm-o;uzRcYe>&y+-nx!})D9{x(rc4)!nC -z*etZSE!X?xNHNg7Zp;sliz70@f0XN02Khy={2cE3$}H@M)(bl^j&Z?Yl3 -zZ1Zx)gSl1`H30u=6Z3ly8}8sXwwFEcARpbA@qg8LJq3Y(lKNpKGBw9=s3IkdL`nKYjW~_Ecgc=JiOFMu{*t8`GQV)xM(*~x!Wu+ -zU0)%;1b9#4@iDb9f5@lAuwCzaRoFr^7nK8fhR9tFj6P1-&FDU7blvj -z3*swM-{k0~qYVpe?)_|vM?HBw@7F2VuZ6K+rTo3#uBYA5U(()Ljv-!Ij`?+4d*A^h -z>zfU5{ObY#NqOoE;=Tj$zqCJvW}rSiJX(|`M^K+7SCH_M7<;Mk_WDx@wM%!2YHBkkWJ!#E6m3aU!ITFsF&{x|L>i+KXQVO -zu3u&Sas52__kXwVy&Lhrzz$?*(CzIXKBc6Yv6&94}5VIJ=Y_&Yt}@5u4SB0n|| -z@gq5&y>$(At^wPJU#HB}NL63j=81_+D*bW4CF&3F@%%5rLO!|g>E@Hy0l&_Kzb?mj -z;1=>_g4mvpXb!#s`3Q16v!5dVP?zVUa1iVP>RY6Ij4h4&)~T!?NZZ -z!-V|2n#fm_&&z}QaL0W9p1wLfzdy&5VpqXFgz?}1UZ|&=-W=~+J5opSYx#ToA%8%P -zAB~5wK8VlB_x~°Swmt(cF%nrBqCsg@i5r%K<~iAO#M@Ie>dfBI+rGt}di -zLb -z2fnPDxIZJEk=l*qe8dymjnrj2(7=oj5IyQP6fo@*FZkn0mRd!zr3`r75!s4zWM?A -zRcXN&goxh{L%)&V(6@5GyxC0jMulfzhXsR-xqoael)ye4jdg-!>lcS>*3Z{T@F~%a11=Hqq#`jDH?Z0sn=3qgi6U -z@~_tNnMG32uLt{6^4FPrB0n;%jR0F*c&+#lEuJitK~H;9S$;CD*Hedlyxs*b5{;|K -z`s5by-)P`JiI-jn>M0la<(lI8OHnWUtRu%u|0#id*Ak2;p48D%_--2^4DTAx;6L&k -zz6@0;do<(CYxThgUE%rL(8@v?)_75pcwY|0U$Q>te5}A+=xB@hlAO;zCKHWR<%@KQ -zL_Vs8zo%DGE1mkx{6weqX6g-pGL3lth07KSzQfm_TUe=`k?RX9Z$y6RTITmc6H#w+ -zi}A+R#tLok$#{C4ua%N-ded1v->F}RW&YSVRQRW`+=7uftRKJT#?2|N01*N=g;rB -zo~~m*%KIB)P><7;`4|7(;J;t9ejIpG%NN(&p`);4tbcV~wftqP0Mz?e;P?IA7Wwc^ -z*nTIWKhuS-jHkN7J|)9Gr5E#eVXK~=<>&l_KHXt|RQoUPZ`2Q}@LLMs=H1 -z>Q!>FKImQ3Kvn9qy|a!*edTD>Gl=m#$Zw|ch&M%u>x`Ey^y4<;h2P^$6bF7luE%fi -zw`zNk@gCA4(XU71FHgkde!w4*>scHhTG+wsz15C-NW=@IzPhms_N@*3gxdD -zsbBE#3X0#CsDS(swo5*jdBJRJ42fnSq`zL0!fwCh1OMXu(>XZEg7+*IE -zw9-Qz^S2vNzxWIMwUc*q@@++XV?Sd(28rj-I;o?#=%*p=p}rFMDezq+^nK2}E)fj{MZc~3D=LL;7!mguK8bqGJN9pbU3 -z7MxFW{}c4@1Ll_|6|~UC$z0!>h(e&`e*C^EdCgR{4D*RcKOw#kzFNM2H}t!)IrFFK -zz@P3^?cYjhh!_Zcv_-7nn?0z<2dI$tU|=KQq3S%|9_WWq0QOUUZ|*3CR)9Z~`)`In -z`d38rdXy`vqd7zQ_r*#fo|KmR1>KyEo`1j_dByt!{#M9OHNN6KA)mw9-=FY5g_Z(8 -z$nU$+kf=NGi;NfaL%*N6-aOt+Z-6(!ze)Khb-_e_-kcwK75x(?V!s87_oqj~?ho(} -zG9I_YW}-L$u>QFKzN-5YFZce~55CAB`Mj;f-;b;YzH%&ouj3B-grkKcfS;Fo&_bS9IX|j#BW-?=AxI(5NY0O%e9}N6;Vi$)`Vhs`X@b$=lu#3On -zu@&a3jg4A}YYz|fS5VahEbamQsLI#a6>p~7UAdm}E&4-5rttnRUmf)&<2e5}V@800;Q{hRHm_c#y!GOZZzY4EA_ -zirQ(LxPA`DF7~sh+rR6M_)`P?JznF|$FcK~kAVDF`M%6U;156^dZ_%H=McUAhT2Kq@abeFk=#6w8{DO>!ct;>!gnZ1*Vm#H0n(1%U -z%gX)ZF(3O|#eetr)zeSCoyLmaZ$Ny$0pj!W_X_wHy(jPA0Ob2DILhnen1cM&*$#KT -zOMHZmy1>7c>rn&u6LDXDUrqz^T~VJc_3iQO@Fz;My&QDIOb>gqJh!^4t(UhZnrV@W -zZ``ccpMT&cmxA6&%o -z(Uu3a_0i^B+Ia1Xk63T$cd1X!k;sRx&d+~(3-Poh_GeBYo_7K9y!2xJ?;@Y;=tK4| -zmYGoRq4IaCA-}R7@+&1DlLP(rhCzNhiogE^f5StuQ;@hWkskGL^Hur~@zai1S)Y|g -zf3#0u7(Z6rtnJU0073eem+f^ZHntD=7Ww{5olu_$K1Qx@f7I&-s_ONtAwE3=@oC9- -zRGfqLM*fpr|I^3eeJp3KdmM(ph{W#(g9oas5BL632PUah075uZPk!2H1Q -z2rFGs)uZ$WKe_;Xhs3k#YXI-Vo=Cnp9QE3bFSGp$)NAwm^SwkqTz3BZf4wcVGlKE< -zR^(f%{k5hgO|%L5a}~w+eC}?fGAHcr{Gaf~W~x%r%iS+hHx>DOs(zzyR_kf6%HP>@ -z#7J`%+1-3}X4E4VMLnWikJhokuZX8*7w=2XXd)Z(MdW(xp+C#z=D+WVv$Q*`WqGXm -zKjhmda=ypM=fDG{82`tWv(g>J=jD85g1z_0`|^tSKb1f7b*Gu0wf1u7+h*BsrgQDQ-2R3Y_~(KO|IDljenn*u -zi=uw*6ZizF-!ep6sM9va7f-EP|KK`w -z*~iI8ZMD)`s!v5;HFgp8bzwzS{Unmt7`G&dU8HeHxl0$NJ(q9EmUJcP{aCb+ev)ezE=jJ`nL82gm>V18=DN_5L+QM}aqO -z?tJfOPmwQ!c%^(_@z01~Ok#ajAfL7$@0sn|_{=xNZ-aMne86zmLSe~_hpzQNekJB} -zs`$QtR%-k4Hb8#2y5DZ%cWr;%*%s)Vn>?Rqa-jc8FXr2jYDB4LRQ}HKKlQwwo*D8 -ziFjC9@x9&PkE{FVp1%qG)rs-WYvjkO`{&-tjePIE{QP_92h%r>`T4+C+IUa92}X*2 -z#QOoIP85s$eaUyuKwu#c`e8_UY=(TF{%e`9x{vxZbwAzrh)0Ay%CJz<<_d$L`2=W`G -z{{4x3nlsOBv_w2_Wgg`FPvrdd-K!y=8QCA`hW?~++qpmK8Q>#zzusIc(BGjT?5pX& -zeC+q|XBy3MfU*B?|EIBlD|yfl@DS@axO+4{j_X0r%+U5rIso}v -z2l$Mj8buaWQXakpin1FcNMEC;|A9&={ -z_V;}}5PbM6))xiL&;N#eylCX(brAUM-^)6RMZCi* -zuCu^UwLyNM)ISv)>L_U+>$kgGbrc2rAn`}>Nbos_5gz~ya@wU4_hdwMK1(=6Bz`S-WOAYWDZ -z`fL{i{X)D(;;DQu&>vBi-%+pv>R*5_WxtCW_z-n};VC`_x>$|%_3=XrHHE&H^4jm)ZR^V63UnCSVQ-q2yXn=S@Jn{*AFdk=q&aF+Tzd7gSUax#k -zJ_Pkwpmkm2-B;H_w-+25eZ&GoCp286CmG;(}(@5FDFUkF|)NZ9ks{Eo~uc-{t&zH^cYU;PF<#dh{;I -z_3b}5qu)$swod`)6{-mTNAmyPdA0q6>79`-sN&6IJ{hTSMdphWeromO8RX+EYQcD` -ztr7XBi2uv|9)kLVSn!>7T=S1QLfBh%z4m^bFY+vg`IfGQwEcx0fAklAw-xa#RXn>( -zOQL|Eo&*})wSJi{As@3F -zA5ta){!IlkO>_Dy|pUR@qEtOSAvfrXcEbupd0d`#a3k(_=rLk0%$k{ZrFs)Y1C| -zHg`VF@E{|_sPMp(*Em1s39tV@;P=%2!MY9x(yQ_hW(?4gV>!>qfd|_9|5H%>Y0hyy -zP#5&GeT95zY456K)Al=lXEf2yYs@EX-;e!*e6`Zz`_O)p#z7w7hPmYTSR>@Ssr-le -zxF3uAX~ccoZ6i&*#PtplgS7pSSLW89fAb3c>OO#vlJd|2`S7vGhp&t0IrYby-QbrI -z|1K_`zX|n$GdHmQ98?N?JN!-Q-|T6Feo1}UpU4PB`3U*?O~v1@L437nU57jVGcOtW -zEhD%-Ve3LDv~AwBQoR5BWz;`Ize@Q)YdbO`pQ)yJUQyIr<;uza&#tEBA@UB@)smt -z>G>A@##Q!nVHg0M!OP7@W-JGLh3Coj_57+(lLUu5{&c_-`NIyjw+G%?s5tb8Q(rsr -z%MpV@6;$mT@d -zY#*XdK&rJ{rLIigV3L6EbIH9FLl)LKI^yMvlS|^nDO_H{Cdh~;r!npYtZim -z@>WocKb>8Be%|O?$d~QI{WoTHG}62Ec7mJc(q~uDfBP!<4f*$}yG=AU8~ev*$R9!e -zB;FsqU)!H*R%`S}G;)32yNwn)3wtj4ek=N~IdZanSn(G9Fp!@o^;P{zW-12zDBs@) -z_0vmN+2|tV*ohY&wFW!)o-iQRCxPlP#3(Z|2{>BcI#xmif`-?FxBpX1sCWkAB4|jj{gT%$JPHsi#yk -z*L#)EgM8Z7jQ8i~2j5uMi?FR-<7xNJp8ZDh+mnx{;AUhZGYqDHHoq! -zo?(;gQQAUjrn9_cj6i4Unne-b{_nO?{K!l`Hz^+vx) -zy^yzP*tcIN+5gON4t&^4=DSAEu+V$tQoA8q|FgFj&I?iHA6rJq?;M={$ -zwRM$|W~lmIwgo^Lxr_OXs+rAHv;dFaoJHHuu*hl)EkZt)+>a*_$a)6;LtbB)tD~zs -zdH+@h-?tukeTR6zM_S0^Gwx@RYEdW_`Eyd&Tb; -zlEC>tKd)P8_C3~rL%Se;vDZ%5#P>C-VIk90KJRF9Y1ChTVtf<)Kb&8H{3rRni>v6V -zIqaXb$3Gt{H0C77TfeVGy)g32r2YQwt?dVY_==7;A)f>=!X?jT6VNX;ofl!7xUOHH -zGgG9BU%XyiM`l$#Cm-f7B#Gy*N-Fqg^dFbwTlroa&qywee7q_AeJ=;0UThrK6Tlp5 -z`j-U_)Y_wwTcE$zF&{l(v4sq$84v8(q&Uo$0xAFIvd -zZG#U9D#3W6&pzz86q~z0XKH>EU47(mvH2s< -zC;uhUpHAI>IkW`MBbdg&AA)|#EzWU&n3faa-(BPQ5%z -zLwpbQd=fwTJlFOEE{6EOx?gZaeyzW1!+hq$e9HC6TNw3T$S;ugs3kULIpqI^i1F=) -z{Hgl|j~isBbjaV9d`*uqoX?1UHEG1}cVT@(H}U!}*r3p(HH?3AB46Y39M-ojQ2(v& -zCwvP2WFGjFGJo-R6!3=1zq?%n=e@!IlKO9FcO#`iK8n;I-TuJSHIN^gg#6IFVtiXW -zSSiYr>ysMp&{JFBe>oo`pdi)#-Xk1Vy84pidF?W2>nk0o7b=K)AvvBY_#SnCV(%oJ -z2i=AHgN~{KerF5U=cfRFtggWL{9+^YGXp;??M+f?ZNHY?)p7m>^t;rDV~T*Y8IMGu5cgeACtP=$Aa(i%yF7{Z&QV54jNp`(O@!eqs1;N#Ivx{HO)+ -zi*G)D-{?xv7azGkVCoz*?QX#5ecq^Np-RB7a=gQ{L!Rz)JF)W>^Tp??eF)l$BnAb+{SJ?1MyHiI8l;p{>A%J_LU! -z75+{>Ax{m4X!|P{+ijp2@Ea1p4T9oJ27ltf@16G0kc@oMKCCaE_CP+$BDPmS_Z8ZE -zjPu!NpGJS{)jWS&kiVA%e0x~DzrM3SK^@NDKKuyrQt%^kz5WHCsqUYA7W{h`@F{Y9 -z_G#!x|C7&md$3CDzf~ED^NUse`fH^_Jh3y6x5*j!|2eoH!V{c7p06=KZ)7#}GX@_3 -zE#tCpp`8u15`3?;5AALs-#pOf_RnVbG*KnUv(&doidbnU^6jL&mPb4=Gva~Lf1eSG -z^W%^|vPC?9%SLT{rD9XWzYnndtjU7>j|BENcZBGv(GTAL|E^bP4eU{%c;1Lt+I}_G -z=fKmYczn&SYWp{=T!Mb6={+eB_TJeqZ7TGYx}S4IH4_~?&-?YSCpce5^}KZOAO1PP -z{{4+T$Zu`O{gkSdM?U}+zkY42w%>EhNx)avdHuuYYxC90{!#z9`GB4l7vg?yS017N -zE%F&>ito=h#z=F&aJ@)Q2l|Vu@OM`D(_dBobXT1J5g5hzZ1!C6jk$P!_nC2?-3|W! -zhx4@k<=&y*rBQX}|MKk6_J=$M|FB98j_>I+LZ4>j^>A!MKhnc2FYVhK=x0rqw+Yz4 -z$=JUzOaIAZVbp6r=KlQ4cWU|8*U0Z}m4(kkvc`h1YR>tc6YE*2|1W-DaBK84Q1SDb -zp~%`i@O0Nd&U^|!cnp94i$BiuE`$8P+x~378x7O;Q||Ohi(k(VLA@99GoWT%-}4sw -zLf!w^2abrkKeDYd^f~aC{C(CN=pT#v!CB((t9v1TcLe+UuLI09y#m{lLN#=>YzO1F -z9D8w|#}X=^Ti-!h -zfcu?ze>Ccuv#RuC1(THuKjrvuO(>GhW7*zBw?qD>k@r*GK^EG!m;IAhqfme5#r+Ff -z*>qHR4%d71TyCV;-QF($z&ZY%&0tRs+T8K&{Ff2GL_7#E-!;BcFOi=LdlD|LcVfS( -z`wcI?hI+Ld%pawh2>E$zr+(u1Z*JneBE&x$itC9PwCAPVK>nnC4~W{ul5L_D4POye^SC@@5`)wJ}KYDXG^D_t6XwR#D)I>*( -zU@xS-Y5op)5%Vwe32GPCQOGKex9xn3^V8rj$@%&p;!O$gM|_39R{{C7*Qap3?bMQ5 -zJY6M+w%>3e4{bhjr@P3XD#qteuPJMxdB7_e=6~yBSLhAwZ7v~CL#i4mQpHa$EDOE_ -z@hQ1~DjG0T=e%9@InMPj@mNnifo~Uy`CRu|Pv>C|(_Z9kbjl^Ij+<8 -zAAVC++g~^X>hpe`<-b1-$88?!DWttNK~U8FhFcCrz8vbeXe&m4_g8w0{){U9xgGuIR~%(~+;9@k^NZpBZ4pzocvr#xJr~dYquYZIoeVy-v3P#| -z5=J@-|5^Gor+*k}Totx=rnK7n^Lb~{526d_4}Cg<`c3%v1;z7z9|ymDlgHPj8u-8$ -zod2C?f{7NX;@>^GYx|RiH3hy@osTqV8uUO`)>oOlP+y;)pMUBj<{NlZe$S2Z;8Qd5 -z?{{}nC_VTEDK8z7AGKA*r|<5o?SCBI2>ri$u>Q<+M%&+GOf}?}%wqpAS2GJ$T*3RJ -zKy7V*V*}#XWq$GeWN2umu-`oX2M)vwcEWoS`tJE69a)g?-CN9Oqb~3_Fn%eY-D{aB -z^CiCiT+>V;fhzoR9{u1@|2kFtefED9O@HBXP)wgx{^c3G=#vM}*VhxMr&Yy2k^q$R -zHnq9W%V}5`{Q>TJ(k(IGnUIf6s4oc+@9Q;48{c-E#(8$xnZJ(jYNRFyQU4|M`FG^& -zbwR#fuz22e;M-K-TPaT)`yiiSDf_>D>Kp0BTt2_!RuhvZ{^uEr_-v&pZ6ZkMWp9<)1?>LS> -zd;tDZ#}~&Bw9p#h&ottB?K>hL)696Z(M>I1ZR=!0|7gx9IE?xI*N?yV;1<|}mi#?B -z3YE3ivPdmjEnr?VlS9u>Q+TEiNTxWu -zJAUX3zQ-H!QYl}z(T`N!kGMR}qkHp|{oM@fwf%+{XR}gN64$TZLSXU}&cl@W<~q)Y -z_0G=vIr{|E>t|y9SPcEfCaUVy20^~#?VPVYdLPgiri;ACwJ)luPtU+IyLb)Nn04{L}@w%~k#W5EiQ@5cPf -z`V-pzK`%F=o?S=ngel4;cc)TOaN5(fq -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 -zAUEP~4-qdZr_Hy_NEy$|4OXZ2yva{c1y -zB-rmuy;c6E?l<(CO3&Qb3+??J4Pg%;p2g4qfn!e0grrpdyA#&eN04v1&Le-nt~>ip -z`~DK@v&DR+%@gH(&!=x>d!p9YMs^DH%=HsC#Rz{t@z=Nts7D`3^1MN3BOBG2@Ri$y -z>sazM%9kqI4Enf$pFJD(UZW8&@X*HB^9SgQyFG0D<=6{sL8#jRb!~+LcPrDdkNpU<}b) -zlWQh+>mtp+N_(7tP-+MLq#|`igkfF*y-n0NeuSWW7dBjg$Z<768 -zb|vmh2VMf#w~zdR`)jY$dif&2*z+G+?-Ey$k9mpeBPLcdvB`oz<>OrPeZI5yz+VRY -z0&aG7{*OWUBHnje4*C9vuMDtf?~(o2>!LF&gZnr6_l1B5R1f)N3V&4i+e-ZR67DbJ -z@@-cM;3q+zVA|^Q$U49~1ifC<_VX(z*h8R4K3^6f<9)CD3I0YQKgZn#lz7Tp^>-`h -zdwnzczKL1zZ$BGK_+>qEGjznJuCeY>Gv~sVgJG?zvT@E)&rB65UbF94Cfw1$avgoxF4#Mpl^jmxU$_s -zKIWIM&g_so#p`R~zOExb)A~(&U|^L~sD647?8*GE>AcN&2mQ4y)t{f)FXMUNM?J3z -z^-G+eZEa#=>t}h{@}Z*6z<(#`hbe>M4;Jk8Al&CD;`5C~U}-u0FFgMI+csH0FFzIQ -z4ZK$F51P?gC*5y*eIxE0D@gL)^tXwXxkdVMvnzTD58R~&^ph17zxoLAkm-nrbkz1g -zt|;m!gn0Qr)RW8_MC+HsE`Mexl6DJ};CVJlf -z8StMcQhnX10y3WJ%-!%0hm*ZN=?~=Vy(0cx_+vTWy4N)s|8|BQ-uClPUD)ND6rU;b -zG4KellmG8RI~hOh#Ua!iZ1QAJwe@~k5B_7|8&=SM`_`59@8s6lUqPSx{2A~>PmsJX -zdji%+Fi+IpE2_-@)Zk -zP2`{aiu_!DepW7)>rv}XmgV90G#9oD`BeNo?R+QWWq$-b`UCrj-iN@xC<=cGw+}2q -z$S0Xf`SCqb-<6K~u96tPBCpKTWW4OiNLj!84)tGy;orovs`EXE`cP93I#=XGjF-K=nG-8Fjr7e}#LqIrF2jafaHCq2g5ntMZ -z_!6Y9I-U{Fp-+w=ykui(+;6^{)<5_h@~KLAGK6i__k-#&mWq6fVg~E)(sp>-9qjP2 -zXB|TR^kVV{6ud9vY2SE(k-(q9^}hu-aX(u$`Agjathi85_uqKKUI}-i_JX`kY~Nto -zzdo>Uj>EozTCI+^Mozti53(btGn*~se~(&=iFBs+wjuxQPvoC9)xJNRANKrE(svKO -z0zC=!TD|q47vS~z<9&r5T0wsKk0<`)5exl$9qr%BGkSId@i#7S&t8@F=dqt4K8E;9 -zwATNlbo76i=2vSW>Zjme7@|EtvDw6;K)>7`Ib^5bhOc#D_dlWhIQ+haz^-s)CpZI-;vUJLRy|~V@ZxrOK5L7)u;V*DZSnWgsDE80)W7C> -z4*rVqb=WoCT>l)o!Nj~zQ@q3HhKvWgXrZisUUHG~xTCKcSrp_a -z=jY>k8Q7}!ls^=@OvdBR^$_*BRmndv(L>fZH;gs0Pgaq?BM$je;{CNI_*-Yd-^%$_ -z(WkO~RTKATE?(-vT0<>X^y!gMJaP;1k8}{`KHw3hYU{Hp5A;*yH}}SG<-8_`B0kcP -z?*Dq4hWNS{=}QHi_3RheOA*@lRgq6I_6fzieg=NG5Bv|@zWk*i9;ySys9>`zd^SgLX&wTtmZ1=tVqIY5GX9<6;?Kd)h -z_fz2MUMfcXdRSRkwgvT?Q?>s0BHwx}@~ydkzi9*F8>sg=sm-r@P1H}1Cw*%H@GfFU -z6TO_p`V;{kZyl|@lJ#L92zcD*l636QQFj}?@0}{gU*`^!@wAh^)G@zh6hFu_4(nEs -z_>V2eLp9*LgdmQ(T!{5oDyEN5H -z_cyNT277oZ#WPBcbz%#Je6){|e=Op0|CxaLOc(N>{Lom&=YHJ<^dR^jY9OC@;FGOzZ-~pQvST?8X3;-+k1LQHc5BATI?;q~ES10lFn_Zz#PbL1abf<~6Kj&rRCkM=~tX58{|E!0N -zyN-B0=O-b+>p6^gEB6PP7Giu`y&+qy^5tv^13M8&^1uoDl!&igW2b@b68zyS?g77X -zAnwc2&cjnEmeY~X!OzR)Tkv;)-oiC{IE;KQ59pJ8Ja4AT_{|S};NJ@+e`)k?7d8;~ -zGN;$QZOps#QT2^|8Dv3L!JUqpQFd^eofRp4Fl@x%k~IO+l6RqTzB?Wtaqk+1hD`S&L$8QC9#es>>& -zM8xMFgZR78uauAD2}hmJbCNfnc6cMcOXPS-)m1WHcbDQimLKu7Tl<)o!@{kb>rJjDCd -z_u)J@6Y^I(bd~WJF8nFSe?A>LP1|98ME -zDnj;5Ef8im7uxTmMO;`j_#-%fTJZ(&-H>0+?FHwbU@r*##NvkhWB42EYU`WO4*CV+ -zM_|J${|v!Dl29)_Li>FP{;u{TBcJdI7{&uX?Ncy`ryc4tw%P(gz>e>DN!zIkT3i*W&G;fZ}=-_FrjjeCM$-A|7|w6E5rs>KFO? -z4S{}n1^Oko7heMZJ00}1Q2X8m{`IGq=)7HZabXL8r2f9W%2;8@VLp|0)vr_PGh4d!Dxo8;^VeuFqe_dR#5xWy^Pd(H;H;Scm9FozFr${Ok#Z -zfL}3;>QR691O9ao@vr4y7}*r$`*8kuwwx<_{)F~#(k|TJb(rYE|GYD+3I7bI|8Z*} -z&u)`F8x|{{=ar}zI^CG!_eY<~c--Af%J;1;$9*3n-gcuUxNjEmY;NB)xQu*)M2eUH -z@d)4f2bh&x5yh5@dwhM4`RR4l88R`6?b8NyQuwj -zT@0)i@~1fc6+VD^0`S}F+WH*+%EY!DBLC6XlVm*Zi-S-f)WyTb501PrusaEq|B$$c -zvCR=A@9F@rZ~*cv`Ti7I1>DfC?rgBuU!Gi`kB*e@-|i0l?Lz%s!(geJ*QqJ=X~ci{ -z`j;Ds_Yp7T>+gCC`HVt*u=OnH+v~j970gfJ-(&3ZRk}Slute00a{FyuN#L0dBYS7l -z4aB?C$-fg(3-#>KS2_QTXoz~S!L;AugY+yJ`F(tR6Y}fXVd&SKf1QLQWVR>Kk11Wp -z4&0}F(#h=+Pg+3sif(nN3A}g8LuzMG=2!;>nI{;~6r*z{l~k^ayxG{S-jD-!L{D_@- -z49pMu8(+_@$fqe5O!9E@8Tf-^$iKX%u#BIbHWlYk -z^DpMdeQY&_{Gh>Ab!=dN()XTS)3diFh@KifgT7Ofe$O~-V0~hVAKz(*`iDuxZ=OX1 -zZx;2;aO0@szy1#KvGHWDJ-&zhoZFZJHpWpC8Oe+PQj>}MbNOUgYb -ze@)AC$Y1<}hO7Obt$Dcm2@raJjkoPjT}<1pnOZqHA?^6C$H~8yPV2^Nl`^~SwuPRLRUI+LD`KJ>;&ngq*MGuI6nn93>_}^8h -zJG0!V$K(5RcrM~|&1k(xB7P|1cW<8O#2Dh2p_s37UT(a?c@Xr+LUmE^{lHE2k1PK4 -zS}rnv_sp`WM@@ETCA9TIc%L;A>cieVXRHwP6V6X^x03HWn}Gas->szoy~cj}VLzdk -ztMt4b__CrsllmRlFh0%~ps9w$t8US`7D_3;yJa@K@&bA%Eg%C%L}Kb-Iz= -zZB6wpcc-EKO>`dI7C^rP|9PghKL`Hr&*5L^{I5)B=*O@RIK3ZEbYYWnQvK3lJP`4{ -z&z~@|oY55TIRby9h`*gH6#fnu(r5O={t@rTUYI854|c}*=ORCd=WBVmxvQDE$oX -z(n -z#0PJ)6Zr>4$iCQi4f$!vkLL2TFY=3@Lm%h**R60mQWIXRDyCI)Y -zAH(T)WLsDE8u?yt13M*e}IZ^wnXFn=TYEB<+g`aI+-w$;Ah`v>g9HgtZgqP{l}=Z&A| -z>2`RgO)&lzf6{(53PwF;Bk~utZ*F4SP@l->o7)WhN%%{_rq%uaY7YFRxDTNyek=TF -z>v;J-nL5zFMf~rFsQ>gqypgxJqcQyd0=~?srm&Cjn?Emjl(C2?cUwNVJMh7~g;M>2 -z8|0UW|GjC26U!;&D}4ul&o8qmf5ZQG*`DiP8TgY+Y5mI70{#~KKb)U+u)81AWhd?< -zLI0m=^Dnm#`6uTI-)zby)bCs*`QQe;@Z)W%es_35%&(F=8=!qZZj*dI%XdIN4eG0* -z2C3`Y|6BQfhf%0^ulI)-|MPWZefIv4;#}fbTbzb(5uLb^$h`(7D_J6sbsD8CjxQRVjN%~DL -z;1euIeizrD!(rb%eM9>Eu-AxJp`LE6HlCfI!hdld_c&_5$DTqx*g6{D*zKT4$7G3xh?W}(%~=aslERr -z6yFZ;e{+7+V;Asjksq5wd;ZDys6R#iJwHE_qh-8s^8>^a4$*ySK6T}Ki7VlVU!;1n -zNUgoU205{M;GaeDTgmVKxwSLf-;4B>yNIWY_(#3$@WzkKm+{0~JivX(f<9fYJLG#4 -z;x~_h2m5q8>GwTa>Y2Y6&8KS};4A;-X{+~5#d;lSNAk2U>Y0z0p#8g;0{MB2^r^2+ -za(vbMkbzB%CVyUFIPh$cZ_fRrVW?LW@y8SM0`GYX$pbgUFKPyQvGdw`o%I6!^dtTq -z*~q{O0Z*ca_PkRl?jJ-vdaCw&0_L9&^XL0D{UPF?&&fa6aI%qog!xs}-ft0!`?3%( -zT%ohl&wS*|iT^AH(Q9t?``K=*{XTz*i>9NQ$+;;$f -zG}lkIedf&mLVaW-?fH%az!wwr*&VoV;|nwS??1mK`D6Wm#nHlHI2sHggl@`0K(23`a3J-9yJcchVpHYfft(@x(u6-GYF&t#vP(t)pR -zq(XD7V>#H7-Q>NF!ixxL8Quw4Y{V -zkzs2;aiIp2c{xb{ootJ{Xv)bE<-TR#Ii$AaI!p;czuGgN)c;T0if!_)EDZ%?- -zf3Bx|yM&?8KXVfQF9AdDH~0sQ+IkP2Hxc>BZnT+2(Fc$gnU(xx0a6{G)&sK6~eav(} -zP-oa{<3ZmhZM-eP&qCoZ;_~dq68PJ0PZ_0z; -zpk9j0i`&bg-%TQZypSO*`OA+O1Y!4ZKdq4zZ>4;Br{iow9;JKh) -zoa>Kapyx)&f8gy^S|a0V|5XY4!6>3v9pX7ppdX-Fl^!m`A0IxM#(xa@)kWx6e0~!K -znpmwJWbem<-%R|6-uHn2b-CbwJv3j=uN=8l##fot4e{GLRKIuF$gPG{X1+(hblUn1Tp;%7fN;KJ4j_WC>ION)5fU4DXp75<-E2J81fdKp-&`V=2L -zI2-jf@NaT@JhRlu8pGen?P-0SE6d$JFM3BDjy-wzHSje;fv*vY--`VgFc0=)N2=Fr -zwG;l3^3>ke3XF|HyxI@%EBgMl3%Jh~{!rduMFaGo&ZN)Ajdf-lk#EKQrQ?xba|Q8~ -z-rD!AFyCavlR1C>X|s&CedsOnX`#>a{&oNlO~mV7UJ>=(u>ZWY_U=uDy}!g;wa=9K -z6m$iC6wWi>k5xe~?CZZhZS;`8B;x-U318H=jw>7Xj^YU;zJYzzo$SR`4RPNh@XNqP -z)cKczKK&*1X|7+Lyor2B@YkZ+^VcKg`}9KL&!0Pu;zuo)A>NPm8mztl0Qb+7K|an{ -z?ROc(6GXi2erUfH+UM(iW2}+oYC-uU=3;u*2>#WY+V}a&qW;U3^7n^%BcB-YJwD!X -zYau@>kp9#)1o`RkA8`HoODK~4^i+@c7Z`6-!QLMMdt1cgUbq+d%J6?p)cXI?0{^{< -z{2gufqaGacnV~fR3x7y>%HtLyKOXsPTtE2zQyHIo;{f2l3;MTHB@=TQ -zOZk*fm%=~0g!~7!5HHAiljP4_JA16s3fzYz)Q86*zwi0So(!;9>VD^gV?o5*FwAm6 -zE|?dK(dIi5`n8C^{iPk=_Lm9Bzkt6EZUVKv-zvi106*jWev3txkLh~&mp~uh+WX(X -zL%i$^$;0A7h>v4GIDLn#Lq13sx*wzV8~FDj|M_|^iPo`?XS%bIT6^L1oms&}v_4;M -zf_xY9(|a3`@9+`zw+i>Id=7i2nfCn^#3QyL9+9T~-Z2UGFyeolKCd8NF5+=7s0aQ$ -ziRSw*(wQanq4?rkPZ^*4NHqKvuI>zKzq(!<>Y7-uF=THRv7r9JNax{g8t^@aQ9Sc8 -z;)6M^Q2z9F)K`l5+@%oj%`fC*|KzEc?#n0*LBIA-H(Px4=5o{r-K6ylJ_LS@`&IK} -z{)&F<4LnBCKG_ZY0nz>_@E77S?TCNgUyk}x@LSIR^f+Gu!uh&`dgRHMXnuRYk@2~w -zyhS}sFH9_B;KLrk57WLssdr)dkB~kRiTIs}?;VGH -zjL(ut9~cOGPQ(YFk9wgu>xf>Ge2wh)%H&V?z98dyKS8~qh}WIZE*`aIA?zXGpMq_u -z^7St2wPwDhc*@O2M&^$AKHq;`A=tm2DL&KGPJbVt5Bbgc$)BEx^*eI{brjnC+bx&% -z_u@xnJnlzpaKD$pA13rLvd-Y2oPXTwi260;qwwFcKg#(430Hw1*_Y%&m0zK6!{5Qr -zd%|iR`{owa7vr&n-#rNT>s*GsAEk{qza4(}7~DT1;(J%B3V$o|Z+ZJwE;}kqZgII}uCNFKkv274Ix66e=( -zhZzg4>2A{pmZLsh)aPPj5&z!rVe?1pj{_eK@rfMT{PzN1K*ZlZ1^kHspfL9bn=j~_%S2jfNZM*N%=c0)vT_<~Ou&*P -z0AH#l@t-Np^lYLh#qaA51U?k(p)l=zpViK6!BUb(^S0qWIiWs755>71_yfvbRDKZ= -zWMZX+_(om?L_>x6K`~$O$6qL)dHWjN?*M-Wr;o5FxL+6cQckp|@b4m{VZQ^fnd?7S -z)1BFQ_(#fX{p~#k{ihz`E%%3FeHHl_JbpbN@zztb={&tEBj1-*4EyDY{Ti&b=QKmk -zSDI*-uT$VL;@=n_moIZi$oSkx$C#Kq>JK|=?RmqYQt1qx$5T%YtS<7wIDcI}RK7ob -zbRgu*F!IN=IfHbK7mi*R8dY -z9fm*7tbM=YQ~2kq()*!b$oKVBLjHBf6I8#lsjG~S-To_CpX-l${(o?qjHjJg -zN46h)JK=sK#GAOjZ-Kq^4E7SYpNGuFdT#Po^>IbsS8nFa+QyQ6`LO`_^Y@gm(fcLv -zt%Q68Px$Xd{OjRkkgrsL;!#cP@UFw&0e?-P*Aw|qy7f@pqQpg -zFMjzE4;n!0ooAhal|X$k_s?%h#{E;kd*k!lf_#CO(4RQJ>r={=E&js`7&g}Sf(s%3 -zbDHvJ22GIhv7M&_FBtiP{QEpGG`Ar?najUr16^2AZ?e~Z3xoay|2%&`V2h5WBc96X -zu~uo+%T@ET#fNG@AKUUN?dJ^C+sw}6Ve?;iL;l0815{6(bB?SJmj6e`s@$dd=EMEA -z;{BVwM$34(|1<=@drkWE^pOVUiTai*+WLl%l<~SNHbec$2;!$n4V_t6l51VF@K|8;BOkwl2{q9dqfA^$FPI!$&;I%*id*H`1$w~hUZGy&w<)_iVm0YF`7&< -zuqfysd_8|(;LJwDKH=xT$1Nw;MaW0Z+Y|We+dR;Nb-$Y=0>9`4;lJdXDdTyUFX6&E -z?4t2heh0iB#P2<{?_0qh5%Ig1BObRF@imIxt`fV8DXI5YA#6}7C8{Dg=m+-pdf>94A;0fIxh7v%!p7xKN@X!EVM -zO~yAJj(XZN8_56g1pG_H^ImYp#1{Wd{QgW|Ju8}n?3G4|$d7J8`GI~l^ehbea)j33 -ziuQU|_8pz4BS(RUn49=TsYSqRf&U|1d%r{_9h(4u7e61~u-6B|Ugz`Oy3v_c$NDJr -zqv$jJR-<07JiR{{_RHG(M4uZ_&(ZuD(VNpI+}|Xe*I5BB5?=OQJN>ltJDr5zS+kX% -zjfMX+L>q5&XE~m_#MQ_qlq7p~o1U>8`-tDVA9i8=V9z$tz8{5uti^o--2c}E^#`%Y -zSK{-X)7Ob@e&%8GCw>XR+!^|N4(Tu>Dx{NtIzQqi4~(S$&Do%1GrpyI`6VUfcvKSduWAeVSF`Qx -zr6tde>;~-pzcC+0A2`#>$fiMm;_F*1S@z%iKz^9ee?j&A+-&rACgE2f3v^}Y4OV>jfJyiT@Wxa-7V(d^N$)7!M^{hi}n*W?HabI2@@`n^hebcXZh(F9Z0r?+B -z?^i+oaT}q2@H*-hE={HTglE9N5DNbS#IP#AIzLB!Sy4KVM{^mOn;+F1)P_H0Bf;IDZv9XhkNi$$S61vV -z8qZhocjdlA`q|f~ommyw%lv$oXovU}Fc;?+hQO|gg@_Ch;_}#!_Q%QfC1N*@r_5-Jf-0&xz$NrVk`oED3csNh8zg{HD -z_4PxsKM!uvdd!DBTq*GDAN-uy;4x%Rebp2G9>iB7wDzYqgM51ed~xtig??Pqo!NLH -ze&47A?q?I^XLl@=h;LpM{@QT(YdL-Yg8ZB=;MaVg|Ml!8wEA56nyJ^LRb(dj~(OtF;%=1@^h%@0f3g -zm)87N9DBVk6X(6^2IW^e-!!V -zSXOmCp8&r$^)AUnPj}=84x;ni*c164estbS+;w7lA>O?!1?LI*n0)<`A#ajjyD^jz -zs_p;N9C!p+Kd$e6i~Dt3yrOthVLSWl=t}=Y#)5JwrL-XUBg+ -z{+y8i?}hp!vA(}u4%jR3m-6u~bC>bdSG`8O{d*e!J2(RV?nLW%>hwh!^} -zS=#!oM1o{R;HT$>|6asf -zFR~Ny4aAH2e4Z6Hu%dxvKYZR@w$Em~g8ci|o882C75W%H4gQ@uBp;l6!(V}XA#N|d -z1^*om{>$y5j}VVd1%4H`|NB9a7x79rF9UrG`F1PI8rTHXfAaA)>@MS_2k(^e)IY6- -z{MMDEpKYH2`@@~SFN*u8Ha?{Mxnihq_R|wytN8~VEAb=gx23Dec;{7z$@bRoH4N-a -z;3*3EHhY=@uTt=@xgkHVqMN7fe%i@_xPR>{qTkZBUD!qFlhw8Mf@@%Z -zP_N9--^M?Hzt)%PIV_j;65e?1`1h9C=_|kN -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 -zXbbow>=;_z^8!! -ziLdwT`_RXl6TJ+nFW*<()J4ZaCsMuSuvmlyRrcIHKDYAzEzO#bc^C$J>XC21iU!DUS0FZ -z`1HrqfdB60Zi~-PKdA6KvInk1AL$JKAEu2jh3-zt@wDybsWMoU@ -z$^S5WIPA+?l%Kl{2_0)Xl0R`!FFD`z2>5MH=#N~UmRJY-82;b7TKkn! -zH=gt@_rdc0coh-f5b@SmZ$&(+2jx$F3VqAiwQG1?adO=z9L@=#me~axlifXo`>#g -zy}F`*6t)0=5_lo#My1D&>k;2AK=u2-L4VJG)s5j8sLz)|e;$l_Ah>l@{d*nccfFe= -zzvCA`9zY-F=YRGxJ@bTrp7Ylgi{92btCd2M+^4A>WW4-8}%l<|4rj${PSOtUtD;)7kk3jzmcrZjX#BO2JC14 -zedVU`|Daxp>qj3S1YW@f;tw^(o7l2%iJxDqjeHIG_j73NPpEHVDKja4m|PzB-GU!+ -zeljx`@`*ZF+Nd -z!(KZ|~ug9{g<0}sSBIKvUt`CZ7HcJL35)#fu6_n(URcCH}IbEq#Kr9Ic#>2nLt7+81&^*0>(-nEhM -z&E;_<^l1^V{Ka>$FIP~$)#Oi1?9fn>2gN}TB7V6!1^xpeA8BrH#9M^@uDu!deK+zS -z-RSAc{=j_;e7&ZGqrNzZ>RCeXBi@xv@1MMj^{+xo-sJoG_1!B4?2Ilnj;D&s%oU5@ihdPr!Fc1CL -zLw;Wgb-uaTA^7J+eDl$Jk)I2Fmgn2Guj|TgA+k3@8(;K~I=1o;vX?tf)Ui>Q-EH^1 -zIN9NwKVJy_81W=N{s`D#E0OQQf4|s)dhAeln}6C5^)(MMzZIJNx{i9YAv?&Q`C_$^ -zt?EScSq(e_5&wKC@@Mu5`dOn`84rDJC7EC7_n>|ujN*@ZXCNLkm*o3R+;0;Kylg(+ -zsH<{5Wu<<&ZwmG7{P|n>dvC!0;lB^o*0Yjsr2p3iev}jRGlZGc{q70B?rY%5cxt~l -zBL92!&lEo!5B%s~XVLwk@jKxU2qS-#UnR!M|LkVV=L-mv_1_X@b<8Q5?4hHuhx7Zn -zDc9Vq@!B__r|{yQ?55U#Z;Pz&o=FhVqB2VPEqJ_`z$-%XsT=cNy9BP{Q||@C^I~{!)G(M*x3uB=XhjY2!6T0`Ca? -zrKLtM={M#0$XvwhS0i4}{Xw`p>H`wt#0RC_+_2G&E6 -zKW$O}AmX7f?g@WH6L$tOR@*za9rdNiAA#DZ{;vAe2!}oSpT4f`%%&iJq>J|a2JEqP -z*kgUQ-=E_?py4gZei{Ea>@oPWxW1J#PR2VN@hS8#p`QDx7w{OMe{lX&3F{Xt`14D& -zM!cg2@u%c4@QWElzlCP%*%!shzw@ZDjAy>^Z^*}k-mDJRThT{1l|}yQ9+Fq>f{e_+ -zKH=?jf_xkg`N-wHEBL{!Bg8*9z+WQbmme-F-&ggh0q~&*d)VTQ$6>ELgT2D}W4D9O -ztk(v@&;6x8;?F~{GNUV!MMvk&aw -zP+H%&cKCB=qGdeu(K&T&+7vpkhH%_}TAlbyy<)&qc}(&!XEof+`8jh=En_g|m{ -z5r2FK{Il-qgikW)uz^hpC4J=<>Ki(FdD!T&tD9cBpC|qs;2j`7;ib`E)KLR#3Hyxe -zv%y!K*|xnzugliy*vx%&-phRkd?@fY&hOs5bdv0!hcGNe{P0N#3@w~T-{+_g{RH?5 -z5JT#DN%;}^K4m@GKJ9m;AM9aY+MkfdGM;$tf_k>fiSTC2qn;~y2idnSW8hB~_U|v$ -ze~I|xY15G}P#pWK@sDBP{}JH-^|by=ZZ@%-r%9eJEeZLTMDdv3$lrOPCw}MsCGhEy -zU%>6_+)eb%&x7=(#^vSv(}olSz9;fy`T0H${CM$xz-Dn+7sM0yYvbAV4esYGMCYsE -z1t&JRoF{vsJwJkyUR;cz%WL?sMpwqGwxy#~GpZ_w76x&wST?5gwGa~ -ztY;Olz74eYdbV+5Ck6j`%LC9y9?<&UF5<*y3HNu8s^Q9p|3m(#GpP58*h=w8ms>JE -zcn{PUL<|0EzZ4ydK1TSF(-4ml?SrL0;1AD8-~G}~U-!|O*p2T!x!ouS$)@P2Nm?QdyDGh|h#SFlU&C<;6v=$o1g{7oeQkc0*tKifc -zmVObIq|}(igob{BY4}@62l0;?Uh-96!iT<9&1T!T=A_hQ-zw5iG}kD>`uTfb^|ifP -zBRnk992OUs7$FYF_D5|vw%-k{!%65H+eR6CWL%rHV60o0R?RVq)c#2pb4)^1qNR6W -zyXN?NN@{XMe3I6NZLsJ_eQLiPzQUh^MMPLqQmoIEL1g+6E9h@-+$SMIS$lJMSc*lPv9h-IPiWQco-|T7&D^tJ -zKXZ~LIVDlq?$rL~G#~3M?Hg*OHH4AbKdO$wTjG;a`}2AE`YFrY*AmuC*Zr`%;wbS!nP- -zeL~-ugh(8hls@q|Im#*V^-sXRlVc*xaWU}<38V&Ai4W_iE>&=9SOVUtVh&17F}F^# -zB*Z61T2v|wPEAa9{G^p{KyX-;B`6^^P&j_Re*BNg$%)BI&kkPm4b1SGpY1!|SbZGu -zf=t -z)};!Fz}L)P3~$%GRj`?c8Db9c!Jn1CVk<*@%^}KL%A9amw1$0sQe)yR -zpr4q8)F6Ca#oWQq*Ds|%_;S2CLZu(6%`B%5>I+btONmK{z!^wNjEJ_I2#qd7OZIDL -zj*Ll*jHx2+fpYrzHkc#AQc}$^@kw#Yz_V^R5DVmBv--6N$Nq);1O^7+{GvIma#gHR -zu)kSZHD9cnbq%FK_*RjIkd5Az{c+HJU?2`+4NHO|_{=d;L7h^PF%z6Sb4-eDnixW0 -zVAZs+xIUJ^;Ogc;e?BEI_0I@X7c- -zsg{2JTo82;1*pblEQ)A=Qm9BJ>+1o15^NvX{^(mJ0o*suVvbgMyOpn04Npu=aisCJ -zvVWrTJ?kHR18kZSw9wSBm^fcQNK2LPDvALPw2#@(M;(`{Z9)Df;I#xxvP$Br5VCJy -z)7vuiYgK2uXn+5oy4KVNMI}^L%YFo06Uy*+A91Z5jKBwcKEa|Y7usk;I%Gax;q9!~ -zRCrMy+IxoZp5glWL?kBlH>(>@YF1zya8An%t083FYI*Qg -zwZSJQM8;^wV2mQvea!araxmZwANvMo`(t%TYCra^1WMb^XQVNj2i^KQqsL8KNq$Mh>Ph6_mZleNKSzy;e5iY%}<_>yH#xzb<+{8Y)x@~O6bIGjrfunJNmqP4$RU_*<)BVg{E`y^QUC0Qb1o(n8l;pi6l -z2W%`|Ioa9}tPtoTJ44)VKDggRi+|AUB{86@BgNXym@amS;9xvLoc?t>y(f -z&>UTU@s@b#H|E4-IHh5szyKHjVut%GCMw3F_^g%V>^19y%>L%9z89S8AD@_J32KM7 -zd{W@zh1*cIY5bFt;`;g4NQsEHMD~Gi4CIjt_g7ei1wQnkU}&ZajEX;q20i% -zSxxp7sDNqE{!|B`%KX$b;#(cIx>eyfr-dcQC^ixAT5a6n=i1mZeW6MUHvpAIQbk_R -zK4Hm`aNt{6o9g+3X`$`4gF*QEBqXNBMDI>t`-(Kl -za^WP7GP+E<1ihn@Hwu`1&X#wkjf4{wBYxX+uzBBA~ZG5>7bES7j`rQaZ5nE>e-ivAiZJL?_{Y^#mC%GJ=}3>WHKbNmnFfP -z6k$6OO0)Jm{l3pKF5COQ06)k${`Y+(od&)^@BK(TBH8}P5xKpur)uV)gfy(EgT1Ss -zgawD>i1)4D#FE;uPcro7)DYEF4~lf~zF!qhsaIXPuox8cAuOS%qTpvFS`eY}5OZ)fRZaZgw^nq3{qL>SNa~Xk4WknoBZ#H=nBR9g -z0$IG8?PAqfD9cIX{Yr8R{qeuqXw5*)?)bPIe=l(&u#FaH -zk~ToJO*oTttb;n1ls;tIID8?~acQUBp5JHsenv*0>8qN?XQvcr`noc1)j-J}F{xIJ -z79PP$W$=Q)gR97w59_^sTy{H04qE$GJUk<9W#$uhwXP(oWDBcli3m$5e-WUM5=B`_E!YF%4$1hb2UDQ2RD+`*!P}KUu3$Z -zSVf=3DqXWn2h}u*`EP0Q-}ICHHU1Y=M-%#QSgIY7Q1gM=pT-B0if=V&-PX+ChL9j1 -zB5|_K(S2)}8`<)U|JPo8t7^*I`;<1@mQ?Yzn%q{c+?=YY<#4MileX&RTqvlA>%DIW -zm>a@MQ6p0tLB97BiH*GXZHNsee}W&x_lthM5$|sqCiTB+84er4u(2+oKT;b+G41Fb -z*)idu5zG}aKdY@{1tdi?8PWSYv}T38XH*&Kz)^n^Z8>~F -zHpdTAj?_ -z%3fQJJQ*2=jz6^Plh80aG1<}}IVKVrIo6y(Ntr`vseYf-#71y|Arh!&J!WV~O?YhM -z$QzNpuelt8PXAv8vaAf;pT}B0I1B}%wkqQoQ?`SF*25qw@fiYw@?r6{dv1T2?4C;` -zV*kt`VboBmx?y5m9Fk9zss!*~EDeOM-RBO-*x|QI^3T8g7V;ukiz_QfO%Ve~v$H>U -z*5smU>bQdv;*g$@(6goD7O^o++u3k5K+;XK_dcu!oPqiYksXz28HungJE>~^khg1? -z8zMzhIX)tn%CZBiXyvOV>U3Ft22XXL1nb&1PHU5+fzBgHp;DdU0+#*zcc0^D>s^-}^VTNX5 -z*EbD=D@Z+4k=hbDa_RbqW9iE(Kb>r~&{lRwrwE-om6caq`sDC_#ZR>bsliDWY4 -zQ`XaKT?|LODuW)v*DBKnv)G70Te+n5=qa2-Nd$XO9kluuDr7QY@Txd}e=F9R*ivTR -z)2HJj6=1fXf->9xXbRGP`DW-!J-4WyPO*Rx5bJ;n9go`dREq;mBjd*oIeCWH{FDH& -znzq><1tGS%ssxV}u9j?lNI9L^nYxW1_*G3+vqQjWViNkOQd+Ha0@pz{O^OA@QEGy| -zz-hAhL}E2rz2}J6WJXIOZ*X)Rtj`6tTsRKAI@qkvGEqeYNP(S?TrM*r`r3SL!q}Sq -zpV>e%>Zo|rVGmrtk;o_0mmSeTW-mLG6q&v(w(RRCu7NZ{yGPt~M;};#4@G{&ZGb=}A+|+g&z_cK$SeGVo0-bmIo9yhC&Fj`%4ZE#BC|fSNejNQXxZ)~WW?hm -z^^g555q%VE4{0gMsEBc}fDS%ahbn!}t?KMGfPj+L|A&1CJ}5dW)J$SE>pml)WE?f9 -zBfB3%<|wo4n3&uv2(Sw6>IVg3yx1fR07nU)k_=0laRiw+0`{6kBbk`_!fx8s3ai-^ -zn04AdKNbIVyZr3@=k02z80}_s_GPgOf))OuA3EY2FkBQGkll5B&XTI&_)UjxS{-ae -zx169e4`w*_@Y!=w&2vW$XC%iAukiEmp?%BART-LfyhQdBcgRLFw&jp@+P9Ut2hjda -z@EsVV88!1v%Qmtgx2zAHLkC-i`DIL#c+cX(C6Bxc&4X#>wKyi#BCP3*WL0DogBkh; -z_=Z(#bc{)jwsDkf8ejkzhVG5I`O`LAur+I!jR -zsHzerRgbm3lT#IZ=*c%etd~VAZVIy7jSSXaU{LmKS0$SVYQN)-fnp+05H(zll3D{O -zMp`JIC#J_*{zeZH7cN-^5DPR7tSw~{>(PO -zv-b`$YbK;1Mcw|hF$n~S^~?5nxV-qF{kG2E3f%EwAF8we -z7a!8>K7cH>x&3!%L@lz?hVoyxnk}_P^@3&NIA;(eHc22duijZ+^Q`vW>zMq8+mf`&XwBH8s28dE= -zf>s^Xd-+mE8J0BPYp$~+RNnZEEH-sQtBtc_*5!_>i0$Yb9VZxVGg#W -z)=%l55Rpx}kJlZG-w*X7W{_R~c_=-@+6JhpA%bVcYRG2kb;yPR;8)d_17PpA$z})k -z+1(k|=6~!$6!+r4NuXsYZ2z~4k)5o}!t%7=9yJIKVX2CX|JxOj82x)W{r|Sz;`#@+ -zvi7VgcmMZ2W4Bt9V)LP!)%yRpy@K@7#{GY|X4cbUmzjWq^8b}q{mof(Ac5QbxjW%4(e3#= -z6XN|lvW%X;-%gFc3&o%&ZXsXHze7DBCn@-7{{3lsN_fe-H^lrm9O&S`JxwQX@sBg* -zE;O^&U$Dmr|IQEx3^!?nlUC3R;g87M+gEX1b6roN|Lv -zmTG7n1toj^$I-&uXL0HIW7$X$^-kF5F=Kex|fsV#g34XOX5WyoU)}li1fONEL=6@QR8j -z(W*;vQ?1dU5BhENK@-js%g`#-H6`0iAyr0~x-uV>1#0Njr>Tnh^B?W%CF}RjKbePN -zHWN~;=CJ?+-u``yCSPy~fFT!+{t4Wt%lREY>|mU@|G{r@Jm`8Aj>Zz@qv$f$5Aq;2 -zGQd@Jk6RnIC@ug2)ti_ZPr70)pn|Vba_@;D4!u0{?{nWtYTW2tVnQM;Tli`WH#t3ME4yJ+$fYyS^67qMo;soLuJllb>ct;h -zs%(&MaR|s5r#IRh1aG>U7&jfVC7*V4ejx;(ZTZ8$7gtAr;DKRi-+^w-=FdycR!l(!^Ze<;V7fBxwF{bbIl;nGJPJiE%{!vRyxa&U?s -zW=nMIIy2KA{sKWcv-~df#umSZ(oU1)!LL9L<|5HysDzVhatWrb4K;`Fe#%{1yuu -z+WHj<9~@Ka4xZp)D^y=h`^-$a?vWNDnFvCidv-EG22oU@&7V(!nX;JOZ3J$CR}%6!*sdW84ShAyzl6t#EYM*$1!nVsEdEB@s$i? -zeCs~SrCw)`dJiy|g0R3J35LU=dsxGqQM~M|%{h?rcj!mx{?ZvTa3Y;wsfeer(@6;Q -z0e5~0P)0!MKBBdc5J@=dkg@ZC6JW_w3r)yWHpe^TYQ>q{ZO^B!I+R>jL`$w?WV>8F -zy$9#E3r`l9c5u_-72`UG=y9w4+YsEH73@^uV -z88T>lCamiqI%H5QB)*b!@vlVW#<9%wAH^?Gj-z+N-Nz%q1#D(>v}o@(C?A$ctIrJR -z%TGY*FZCYURu}>Y?hpw56i)fa9cGm3wb!RD`?L3yT=BU08T!8Fs4cCTqT&P%Y=a{# -zE8?@Ru;A}%WrhgRU*&HLq=lk-%#+`LWVa(W^2kMYel(WYvJJhF43{W~yy=ODnXQ{~n18T;)Ne9ae -ziYNCCehE`ndD7`)DQknHYQO*FA$|!9ONq&l@y&x9itooOow(7N%Kr3cSuw9KFJPt{Mv?rr~DH9O#vVeSX -zO#-$e6*F^W4SCw!pqa=Hs~Pb?>p1K!i8AlTUyc8`ubTEOc~WLVnO^_ -zTM~1&Tk8-FE%+2bU3bgfGyLxL3Tcro%C5I~k#pTV?rz@7U=H?;g%1Dch^u`?V0;Tz -z^;!IjUvIv-dfw5)he*&*4)8G2N~P;r{JHbKlhKyVe96_uRkbV&pn8Dk7=@kbh4u|q -zmDnMxmi48?M5Ii5ClAYq1+dWDI&ZmAY7Y-XgbW{``n^0=?FY-yb&T>uvKHf4E2LjdgLy -z(`(h(v~2=Iy%WG^cKG6Acef?8$fXL8!K%s`Wx~y|UMyEU6wKdwmV-JvtjY7Wc($1< -ztS_#p)(%7A4QCQLP=mU^Y7n*GS;k6 -z<_!=|RV04?1*wuy86fKajA}vjCZQ$}HP_Rrx{t;f`axt&+o1u7)Qd>Gq|Ml%o<$4Z -zPcQz(1)rIMc09jZtLJ?)KT(zhHu!H>rv9dCyuZzgxCtJ)q;fQpFQh-@5vl(njyMUk -zdsbM2J+noG_e2Z75ZKbM>4Xv~?YeQx`&c!VLXFpKQJcyK8{d`j>ktfO*}B*r|81Uj -z57lC8!e@>8BHUAJDDQ*GS8@M*xcK~utAYh03@dB*IuQD!bwPaB3|ka*KWQUVkAg7E -z?sk2>J^a`7QYa7InIXnB6<(y70(@FHqi$HRypLMobZ@#c|XfW4`=9;_0^w<*HQIDr&Js*+=O;V7XdB@K8RgG{PG72B2ISEN|mxSSbAc! -z^d9f4;{g;3a9C_@nQMG|Xn%_xUb0_e?gu`kE$J@d=jm@k%NXVZylvey-cwf!co#!a -zoQM~*bdk^-di1sV_DFqIP*eAhc(;QK;UuMyR_{;LAv(TVdtf(F%;o#{r6vIg9vjaI1>PW%W{TI5rTZdI^pyWtp*8*x4 -z#zaJSo=FeBg5pUtG1&%c+6u(ro)%A~uG!#-CJlY1L{4(4-Y@s?sKzv=got}FpfcpG -zDgJeco-hX*tQ_pY%*Avs@X$WnW7Jgx_ShVm!O5t1_TBMK4)_ne^M&{Hz4$42h@=2n -z)uU~XU++BI=*-|tTYzo)UF19y7<( -zgz_siL^bL|YC6V4PXdXgiI0aN#i;cDEX^bTKr>Fi|916e`r8%$6QVFQC`b~&YN?sR -zM56%j1kss>;xnvL5OWZ#nH*YFk)f7LkY_IJld>I`H|PIh3>HLCk&4udC+l%4TKcC5 -z4rxnLPzYo(dL=*xfN~fv`9UWMtH&zMy+GuR)($Lh-`X=5ia1{3z<`+X$%Z1eGa6le -zluB9O-$N{Ss9Qd_H$qbX2}Z>^7<5T3;#18!uo3pgPcld^H?{%|A1q<$M+1g9Z2oD2j8@`?S}xcED}b-bk%Lp~qhD)#w5VPZ~2gm?=Z?cL*U -zEdtUM6Vp#xeA%q$;<-dN>r}|J$JfT%%4|0g1k|mD#rE4V>^Dd)Y`7cPeGkv-kgEiR -z@os!uR(sI=o8yDxtoVM?{oGh#=yNon|IRJwmk)&Tww@DM8xuqrEI(7N)B5@R3+97T -zd%C1V+gBu9=qSr`85+5r{BY9zK6}1eKvm87P&Ze2P#FJ7!*M^M;TBw#-N_lh|4{gQ -z8ejVjnd9r<8?fQ@jJ?=?t;U>xRWE^{J{3#zw6;` -z`_$GdkW0dQ3LqVB(89)j!2*zDyufS0grL*F5@HdAX(I&M$g{OVX4c4&|KukM#Q%wL -z1ZTutDjwh+74^Gayry>2;}&uX%!Jbh7Y8V>%h?^^Ij@=QW_E6_*Hc{am8J5n9=A0f+->z|s7cS5v9*^4=DfRCs*zi1vd>xbDlJYb_(+03@vO -z3{3-U>1N?I1QlH_HODM%=-%9%YVHS9sL=nzeRXtbvnaf!&=(Hp1J24d%Zp?J`&z5T6~ -zIE?QMYFH(O-%0C%E^(_}&)%@kgz;6JF1|mYe@)(+&aR}_!lhE|j2rJkVl(-;N*A|u -z&+GOTnc_AQu-C< -z8Onb>vORkJ2`~fGZY;r-_N+$FJT#v=nCj| -zxK5W!l^r$w)&wOuD0l_qn%3Cd&sMWY0)8K4S^EqDZHnwrocv?)na_{slhy3$UBwCTMhB -z|Fz)S)RtOF>FW~^&KpVrwHXW_4{`b(UOo6-$Zvz_p$J5pra@Ba4%83)L_~&85Rp!= -zPDt25bsxtA$5OjIjGm+x5F87he7HpvLC8M&d!aUY*fjuL=&MixDw!>w7@S*ero}q*!ooL=B>M>f?MF8=?*(v?Y`SZ(FAH#Q!Z%A=ZM2tB=NviJDg=o!an)Rk5Gv4 -z2zYmhzDwL({3c}^H0!srqwU|b2V5!YnjXd{Bkubt)h}2`ZyN}PgM)1$1v$Nzu&Akh -z!C~Xqytt&K+BVR8;C$%p{j%pec-#DflnDjC->t6kMwV%2Z>PM8MyS~rZmhwn2iXoe -zR9@O}ZA&!8yKB&x-Dqj?J9Xw@c>X%u{sEw69ca|5(pOHV!&KeKWIV!ijD7+5pt>U84p+q@N<}O{@x?D418r2+mP9xA{M5P!{~A7NbNVCOk8U@mH~74 -z07X2Zxbk6~9qxeEiSxzm0kEq=eyJtUeI{OTBc04HSa3&eU8?KeWELq-rTeYA%#F@P -zaIW*ltYu3@6@)WETsy#`!fe_=t~f9U!1Tb@*|4|Gp;uHJ~TRf+*zkk**A6w&|2{VjZM{n`C+3z!iVDK~{ -znn;6hY@*T-@2byl7uSyn8Bv^{$wdf(gX7$VYRv&nt!+IH@R9kBYmr(f+J7Mz1VO=$ -z>J%vz3r6(T`zCStI+VT>L?e>#OIa<`1dhG6>-U7d -zyCU6MuJ33%a8v0!W~LsH{w}l5{yqq8xSC>~e4elGy_6of*S*9n;Hy&W{LC9oGS7D} -z@pj-J1p8dJ>VF`)Xnv&*WG-s`?awz*P8!reu~$9MN38|ZQ-qS~tu%Ph!jPa--&{UE -z+~LtQ>R+Hi@cL?S6#U-%$e%f~^3A&=f2c7sNWis9Z`sIq%MuGG3*1jLd=GeqGLOmS -zFR~5R<;s7cX3tS2^Yer1W+)}%LmeVMI7ARIL;pRq*H50<;f_TCw=988oYT6|6T^Qz -zKga4(+@snQRJX##dr=ppN$Iu8Wu$zFkwWVj_+n)noE$dLWI|#p9>d&7ztJNI;o~-) -z1FlS$CbYq>5OS3Pcp|TL;)Y$Phx)DnK8*M4qDk9I+&+_rOHHi`;rIfML`mC;S<=>% -z32HSkev7zZ)Uc+aiWoYy8(4@jFZ_8K+?^7bT>HLK|0_T_laP?wcYw05d_(ur5ADSz -zhi0*^bqiqqd=1R0P~N-<$nCLsGxAMPMo9JBz@DB?O^*xVW3?NhjGVxwAj$beTRBXd -zYZRnUbQFWr@@<38lf%{GZ&jQO?3M8MIQRPd^h7Exm7+-Lvc43l?~@d%P_QwP -zFG%X$V_#Dm -zu@us;CQ3rjHOerrc2Db!$#jY_y>uxo&KCPxa8tJ4p$(t~%TtYm?!%Q73!(ff7}0G6 -zNPkY66&AQRkmjl5PYl)wNYxSa-^t?lU7}I`1E0+m_-q9ML1#Lt?B5UMvL_kIu0mJS%P-`k)>z-aa7;Z*o -zyTi!9uMtHTf#2>gjR3J<^PT{2Ky;utSC2P0sI#SK5JdZLgTXjgXQl?`vgQr#~R;-T?;)y?4C0^m{)sj=|9Pgrc(OV2ZcZ0lX8TOq4jb -ze!|5`gjm`}gtfEr^k8Ikzqw;r8oIR;N+Hq@iompi;_WrpJkRbFSZmJL%2=bj%F&~^ -z9<$6fXTIgIWaF3y)9{6uIbdi;;#%`?H&^Pg35Ot4XB)y}PLn+=;&-xbat+vNv2 -z(r+6=D)_AB%^r6|I8dsq%JqPU?MuQ`XKzo>Yv&W}~E -zYd~HUHFV-3|g`=MO0Kj|s!?0lp3)IpZGl;oq~3 -z4Mid%a6uxAM^&EX?Fw))VQ!X>D=*oKlnM{>vO1;GGYwK&1EO5q0(`GrKD}w;%&sw^ -z%sZvHRdK4Y@Kl*Z?*4w5mnUi!*A-@7=;YZ@+Csj1DhGS0ff~UXtgjkyhRNHIJYM}= -z?ZDeaDivM(l)JOkKH7ot!y=h2_nnceAL7sqiA!SW3Mht923<)NJF;0*Cei%X^Tdmz -z9yiIXU|IoSZ7wn`#dOZ*PXJ$??H;#9*s~OW?E>tg%3C!9A-d~e(H5b;N_&W15kEF! -zTX{#>e-$!7zzQIL`oFnFfi1wD^SK#1$e9mY!%ks@z>J^B6K|FMfqa1qDpKmoWiTiw -zY!6PxgTW0UJ`(VtOu(N=Xg0k3WkXaRo|^cSDic8nc))#JA#dNp8Q79i^G94%B3KJMEpkJm0sVHK5{%~eSV#zK{xC{)R}z~WygfF(gax{P*#I^R%Lx-(-Yu%rMxf -zz@Be@Z^xp9?V)=4R=n;g5H2w*lsd~gCG?xw!8!4x|J|4Boy%eOkxR+kpS3jnVFb;`Q&RM9DvdBCv@OF^d*To9ITPWL{36<_2 -zGNBp+tPh7iy_5nF5Gn-)QFWj$Dd_?rp$EWV{RNP8yrd1B-rejQLD1;L2Y%Bn#IXXv -z9#SQlW1(5vsUahfR>;uo;F^qvWkd6UB?6}V5g=pM%O^1kJxz=U0{s}bhtc~8Riu@z -z+P0jY$b>y;%!P=V07Il7-aGj$;3rb+Z8 -zU`nUZ8_L?f3NXKlbt!M-g -zTvE9J^=P%(2*VdS??Y6zx0Xfc586F5PdPv1Su5fyOUJ30UFCgiT7WaD;8lvz* -zqLn`Yn)G3Dk->*IS@2%gf{{!Jux4^-{a4u6sE5(bNikG13>GbrDP11}5b@%y$3qvQjyFnNINkJ2$BpT@Bi_M>e){v}oDSzj8&E>}Y -z;#IwIS*mzktTR&73?-+LnFxRB{3{TF06ibXe)`If$2sUvzWQJtp~9Ay;6fdg;zH3z -z8sQMB4xh_o=u?+D}nafjg%jrrq~z!A1MimMT5 -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 -zc4&u;VJMx5@$Q=(_MrIg?vkZtG* -zjU}72(_rl)WF$~JlQ?fi3;EOpTwn=&iP>2;B*Km^6>c{s17%j;r5t2Li;3|q*C$JK -zYdQ9pU#@_r-~NW}Y{({X-exOcns1sl+RC|@HRt&#X*Y?vi^gW!gd-o8MCVp66ozcf -zJt=(RzB7G+xK1`Bl~iv+cN?LL*{++;h~QtND&8H=EQQg|AbW{r;{?cROLpoHuIgDp -zXpO-u4+neO>BKt@cH+hEWOu_9qotK+y`50DWfJ)g3K5|-f_N*5_mU`1+vA0q;e)et -zuK?rN3M-REW5ASyQMObg-ezLVv7^Z`0nGtN8FYka)(%zi -zQ(WB=7`U1`ONVvnPLQf*PR13X3(&ps9EWI!&#siSelsxCEQmEQ@yv(_ -zu{nW&fOfz;0xr31&e4iZkuDVtdeX5VpspcQ0nS}aRZVRb!fjkQSk0`iE8xQ62Gcnq -zTLKcyR4M~%5(vw;3q(2Z7AuOtsdB0s`V;XF`}quhN^=;+M_Z)eIB#>YJA^%K2eP%n?pJB97=om05X=RYf9@A%2ezqV|bGY3K{t35hCsP5|!>R54xFWn~QGxpkIMIU)qk=0o~Z<(cG0H1kJ{s`~UW)KVkQ -z56&P4gYF;t&`fexIit7o)H!@cK>=6fQ#0s9HiM#-dcir!#nS@MTd^@7E+4QrI}RFk -zo0`UI^47Iaxt-HYDR^DbIepuwbDHPL=$y9tUT=|bWC%F07npb8gkE14`K~?=9JC~o -zMxsl+011w(X^Pu~55o=yA+aH+EpWPAXgQpchO%5hMcbgS0}rjOH_rtybEln;MMnpF -zp%h1~2VIBU=g9`m1M7SFGE7T2o{%E*%dD-nHvg&W=92?JK1c%M?g!X^5xmL-0!Txp -zX*=?hj9i<*AC}g#ET81S-a@7;AQJXR7)Z{kYQv%2TyH9bN@Ugz>2C3Z=V^Jg8NAgBJPW#6Z-iS5hY`O%{}bv3H3>+Y>pCFKY8mFtnAqdn_T8IK1x&tY -z8zWR;TD3(OcsK=*S_nrLGr%_HC-gclvr@<8ImgErX>Qijh)p@JI9C?1`yC&I#8Y_M -zsKq!DuWld@Ps%vPP^xLW!i%np1tTRP#x16KAw(-cxroQ}J`seKE>?6aXeUnkAF3g- -z4kuFZMRj}c1sjWn{NZtz1fvS?l&JiqJ|S&6b>N~@oPF3Rp(2NF3rLp$Q6NB$bEe_% -zx%SfYBw{GNh_G_^X%bMwr+gfE99cdNEwy+S?MY?NVqNY=tJ^c+g@4Cep9B{;u3F7W7!adf5eSzsu^Qo;~K_$k}o8f?1M#5bTJ(o5eqN0Fl_U3_h~Hw -zaHq%&1l>D~UA{Qj5Pk4%F;_}(F|LM;HP>oK20GlvxmN@k>_Bz0QV8~6p^a+chM8tQ -z=5x$Id)hipd&Zb3C3c{{vG>2iEdjdn^TifUh(5H^BFXfcEwzSS1Hmdp(rVF(X3#$4*@&=EU$VbqR%aNA{mSyU4AKodIAk!hppl$7MQ}>7=6dMWK_?V -ze-M03qO+~T{8ePUEok-MA_m|QVCiIOw6zGhmrBw5NhX)8SpKqZCf|HN%NxlP2rnig -zVK>u*6si~6^7Ya42S}Fk>DV=3n7}XG($`%>0v9hxQ7JK;tDevUO*kroB3vmwb`p?W -zF|@R>(7=xnTH{nG+GsH?SKvz -z%F8f-hkyx)uLtppUUbBK$&?66_I|#E&1O^)R*fr;z%OBNIU;HG3LS?GcFEs>YZM -zNqB+_g-0cI2#%3+&g0zwf=|LRW7?H3sKy~PEc(L?>Ok1Y4IGsJ-rU6F*QNaV)UwzggEwj-_J_E$=Ze2BgPl8#Y2ozojzf0qa#cRT;~h{ -zDtvy?`SlVIq(=-L#Su?BHG!(+WWyr82+#caLx7 -z9aB7I3xZMnsmuy#G|9;^$3XdE74fVJPJ9Gnl8z^SaoGI(U~;g1-tHFn&HN5Hm-s7s -zw!R}Gd;Z(^$rS(Zjrt$@rUSJ|P4f2L&go`ow@cFf3FqXTpy=p@;+A7vr=-<`WY$muK2#t8LwE(sSXqoo -zq7e#wgi6($Ned@S+U6Fu3Xr_CLgYvpnShk+`vl24N0ArHoK!dhe-#Yd8@(SY&`Uin -z>VWYHSAeqF+%?WLB$9wW8SL`}_!#sK(|5i*!F=Kx&Xe!(Ob#s)Y^ja!tr*^ONyfB? -zfzc|7k{fSr<=t-hR#LE5A&^`8N~jRx$tffWCE7|)Q8-}&;0Z+88q%CdD;?iI?iSyt -z^8c_!7>?Wltx|i63O!b&$)n%6y-tKOEP9=;X4k^Z&zP8#LkgU$2ga)jH~IyFC7XAC -zqH`y&LleT&j6M1QRKr-NETRrRE9rxh(Sz`;&fq#VH!&bl84#6z7;hUz^|*vlC5&XM -zRYS}R0H+{b;|rF>%&6wVc8|KCLn=B$;+X~zqWdHQA4K-LFEWd@*pVL2p!$AEJ6|4U -z5;UuEl1#x>-wcvZLck&cs7G7yX8_ykjSy_R7*cm<5RSI%mMl!qM( -zhF+jhbuIIkq$15&LKhhc)4R1lZp}}ut_`6ujgw^7%YC$|4c}#%HFHF!dU!xql;_>K -zta5X%TwzOx38g#NJk{`=?YkELZdb9{$G&S4P`O%~`#tDt6DHNpu^FX0Y0h!)lNHX{ -zx^_0KCJ?8yIA@E76-s7(NWiELaG=IR1IOIZT@X0%LpE?Ate7^qRYI$}3T#u~w4u8V -zjfO(Y$0w`JpdR7FgfJBAidYBxr0BpGPWvSLBs~eI;UN<=;NE3VoPswwW -z#$+9VLMTgPWbobXmm@gXGXANu>_&Xd#+~GtFO;)DT}|vG2f1a(ty|I7k$+`KgwJkb -zHZ=eknfRqL6namk27n+Gh_!*+)e}c9cM2a;pU;pMxfN -za?UK5w2+|i`ACvu)+&+z;dlNm*(VkZnz1cg%AL{3r~>dU*fD=w7n$oe)lCnWG@SDM -zHu^)m1DPGZ->4+%Cl0qZahx`M9q2jEWY1Gw_RwXA%P-_(OhhFA)p6)bJH-au@JE@4 -zv;J7SJzo`88ki+8*8yItRC -zl&4O`0B0~LTnPbXFZXRD;{l0ps6H@m8b*@S(`jp{gDE21YZjt(to6`fNAP~yvFPH& -z(%;(P)*P(Q1mzNTuvnOwQvhSN2A1{LHXj{_qiR1-;8v--I&4p1eet=bPOPWJtn1h> -zajOT>^ltgCivdNZ8lDA=m;{|*xW_C=&y#BkWaB1*k4}JmFcJE$j&P%69gIdqE+U<2cwT@BFY&;|@zZi!T*8oMr#SB}t+U@Rw!aUU(@C -z=w4!CPTBYRyv_KV7TW7WA(PPwYfJWnLT1a;QS;@?Z=_=+CfmgpszpKdg&ol`pxXd= -z7;rXG8kKx>P6&=|s?%qdXtSEYX#hY9v*BeHs#SMzy>ws=0y`c+QuB7d*pnjePAr`= -zRdrHwyTh18w9eW=&-h_A9n&B#EL)NK34Gi``E=Gpr6v1BlJhE}{UFK3HBpB%nTqL% -zt8)&jf${A_Es;k|c3Xj7>ab_ef}_k#%bND0Z79PqhS`@uH85Q9{miFh1ctimzc>x~ -zhaNCaU_9(LDd3j~z~NLi5W*=Bx0@z#Rifi7!+x~!HGfkD6e?=joB0@kqc0Aw;ApH< -z!5~ap9J=|E*s};)A@m2w_OcpzhfL#d^Nl-@@xEw=#*2!h>Y4^m9j_}c7BPOsDW)td -zDdjd`S~9T@;Vhxys02NWKnnBA))4`R2vo<|^04P7J@vE_<*FV40fvMnn?3}U*)5j~klv3O9E -z3%}+RMNo38L^Fjs6Blg#q!8wt+^xSs4*0Pd(Uh!!$jpC{_aGP1n|~+Q*2}6hjp&RA -z-Hb5MryRUAs;h7NlS{ecRU&bQD15n&m+l4aQs+1G*U~zQ94E_liq}90N5M;$M$|BK -zN=_Qj4)+b1$}o(~8>`y*veX3yaRV|rmG~N$oqm*#%(UFh(~#nrgeWp#1NJYUlxUG& -zVm5|v^lEZT2t3gz|5+kMPQur-Di4&HJACO@NPoik_F2iMOu37syEBu9G2Ydy@YB`L -zx=V+vp29h@=8{OO8Iw;sTmC@vXNHB%jHjFR$#fHErD -zqJ&pLMHw$F=^eNqgr+1A&Zb`w7UyEDj`X1xNj0arIx@#zX)%r9%IM5WP2v|Nr&lUli -z85myFtRn{{ge%Q!{A-Neo{QfeUOVI%M$aIh`;2U3a@+vfZ7_HI$y7Xeq?L_4JZ`<; -z(IulAE1=Wf8cm(`$-M=$XR=K}Nb_7v2KtQJ9ZBHI(suMSD~S -zEY63|Fl;48ADju>#tBvd7s2W(gqw!e*s^yKxeS=XDSQ^Jr-CfK=sDJY<1b|zQAv=t -zQEdy+z7J~6$oX_VWBC5bo=?V=R4qc8F7z`^7Ch-83;ALx?lCu@WTF9lx274yZf7K> -zNpLxA?La3*-UT=NZ~-|*?H$k#@G7()N=GTsG#MHgu7VFOPlB~!K)2;Kh?W;_xvhkj -zhht)Naw6zVkW(J=GCMg1RiuEz8$#$m!aM+HVYu@{+1xKXJ7CBe^IM-v4nyV$JRZP? -zG1Qs_@e!*01= -z{kp!p1|Ce#GiiJP46K0Mf#Er`Y;P9K{LSKKv01F<3qAxIgn)k1@vh7r@^o3cL8azF-0*BAx=Qork*_7Vg|wezF085ZB3&?sLM0qN@?D*Qw6y -zf#g8fB*>YzP48a~+cKcj#wW*Axd0ZUlHy!3pkz2(MEnjij>&sihIs1};Enj79w47@ -z8=>kieigC3y~u}=^?0#OuzHI~EWV)o=TB)lj&|O&VUFscb@k9)h>hBYvR?_{ulrt0 -z_(FvS&9s9lF|VUptPIP(OeP@fz$_FE_}MT+lfhPL30auO_kPjd9Wtb`AEyHPc0czhAtBo6@m~j6xPf>t}08#%b1@ -zrVpY#A3&qgm6t+V*EBGlYW|&a!CSk -zlg!9du5*hn2$+Lkl93clxu4E;;!dD~i{bSq1~80?h~DZ<+rCWHGdG>3rAYd+gC95> -zaZ9#M#Pv<6XA|9vm3@=oqfn*Og`-ndXf3)HRy;)mp&&bDcxSqGHzw!I6~z3ql=wjy -zN|4^|{nR<7kE$jpn?t-oA`t$Az}*ab$M9PH@zzcojswo{x!I*5PVB{72b&>uyX6buEs -zJ1V(&-Dc_G0dTc5c!2jRU`S-}AdHj5ZBm)y{<`3cemIF|_EnI0+Vd3b(`yv^S0z3q -z_b>=^>kWam)Ys0#ET#pA7_61f$u>zrLfjIl2~rZrmZBxqD*^Pp(`rm_^T(<53nje} -zSP&KZhq6pE_CwCxsUP-BuOZ6<+}7{ScKN>x1d+*ghr8iVUEz21Gu590c~Fn^{HY#N -z(XYy&0l)F!PW^U;$81omA^(lDR_75gD$qlhrSxl&{C_I~R7Xbkr&|c;qB7;=f8@ZY -zxVQhFZLYx!RJ>&k9nJtj-3`nDr3vU|*Czt>d9$W-CX~XVEbibGP98zXyTrRoi;cj^3v$uP!+;k?imuSJhEmVl -zUFfBVTSnpZj|j)nm8swIEF=X^{z#;_)x1`n4?$hEwFQaVQ1?sHM>zBKYz~);Nz#pU -zNM=t47Th$r#6h4a92KKzeMrNl*k8E-@F|Kr+N}=^=v2@)**!fcx3sWZ^bzA=s -zAh$MR_Rm|J*g!|&g+S^YLHfsRuxfL$vNZo3`BlEgKXrNHO=c+S+}NI{E90f_UJpqb -zSF!3uFfhFAP3|=3LfH?5FeEd&q7_?4j(uU87j^Rb>2O#lt>Rd$uM52|<1YGVEHv+8 -zLg-4sOWR`a-c0`tmgHSi|B$uHV$c5*`zkIlQmlo6u7mRm0DUy?vD1_=Xx#Y4g@Y}; -zV|uZ89I!~R@ppk&Av*QbKz5=wj{_%VTOeIk`(8>x(;;%>1)S3E#jyZ3Yw@S%P;=yI -z(d+OoG@U(n>Bu?7G{Q|6bDt2hfkKdr)D1=#7zX`P0n|tdW_*Q_p_Ls>28@AF*n2!# -z5r{iz0CF3hzLFgbuP<@zM9t-JVk@)G4>Q-VD6zlHG0+ouGlUvXST#ye4~#bx^sY=# -z5t^rUm&OCK!iezq7gMI{4LXUiMB;%BV&e;#8qGS=2?x%(_w!sOW -zYD)8Y8qGb$NYU*=k(D)M8|sd{->M;Jev(RR2H@NWWGoXC4qwIkzPq&wo@rmSYRE$m -zjHUQJF=o+FKYBbhL%fkMQ8naQL3)P`2c|~RkcWnhT^+q<$U_#D3>BWa;#i8eXs8w~ -zljirw-QqhVLZ8RajY4LIdMWv;g*-!#zyk_IA6L7@b>W1?pSH8Yyw83K9c2XmP)qHX -z(8cxH!R@K|GP-XD&8z>tUUt&0AkL#C@E<$M4IY_8X%VIqPvr%T*i-!`*5 -zTw*K0>#TO?SKR+Vv33^L&@;8&;m>h2Bw~On?yTzsf -z9x3TDP~=k{#d%$qt}N|=YprkECq#Ie)^h|oL9{rcAi8e}@rx2YDyQwdk)`e8;V)Jn -zX_wU7dtN-vm>H!qV$`uMI)No#Uy|!YLE5aW)}LO^o{R)V>#z*#RUd^o(;(kx-+K9C -z(qf>(Yq%`}=0dK6lO>lKTW^{7wEM&Q*~^)>m)`c#$x8N8{G$NBGFmGBQR~g>te_iM -z$6Iw>vfEejkK&7pvRTKg(*^j?T5?vG#XoDwqS>O7iu-X8-m0DEA7{yXS9CuPYijDc -zA86GT)!h%YYSmsAEp!F|p9){Yo-Zlm#h21;>>B~Wgl7Eq(yi7_yfjUuOJ4*daHF1;FXMTb1_n^?z#6&V95@gP$M61;fNuj;IO1}_2^M5CF@IkU~1Sl2l;Q# -z{{^2{e&{c$AH7k>0F`>LxhapVGR(<)2s$MkbJkAiYk3(q$YEw+rn)O1dL9o};6ebi4B1gv5GmV@9SZSc8} -zVB4;z7g74fRH$R3Fw)>RiVh{zxVSb=2PQ4PK-eB+aacaQhrXOsL#2KfZMzoHHU!cq -zK{v{t7?}3*-*ltwZ(_RDEn!JMNi)#K(&ukf5Jc0!d*Idx+_>4`J4Md%p<>;nEep}cX36_sRg>3;+` -zAx-Q6&T6}iaRn?lC0-FCl&v40CI@|h4SmDesXTw!6GHW;!2%swXz%t2n3u*D?}at;kSR|0Jlk9#VNf;31X$Qf)@nexi;WYB25d -z;{AK&YRg#RYm%sam9wQ}KSPSFu;AAVa1{?o{n^hJsIF5Yt=C>dpil=^2Qn+7w^u+l -zw&N=48UsAE4!g(e2wa4QKxYQ>;)J&N13f+MkbP)HT*;hu%&mUwkE>#78V-mXWUr?QT6P^X&=WMVyWQ*{$q9_W~K>Xf8%w5+j*qA`-jo@vqx -zS5AIdzebz9v)CVA?90yH%^1H77c8ryO*Zy1s5yk!s|Jnr3!=y;*Fx>zkoulXr!lC(akY -zZ6pBE&_Ol2%*w5v0CuhV3ieCPfn)0;!)0C`y{Wvlio1Ggz -zDxO@qXdh#uHrniO)eF|*1;rPk!MySq%;gyGzmgAl+%yY?P(*#{lSAvj;`%>~0$|us -zOBirqXfUw1Y17t&SyK^+#Z$x=#H{&Hf>|>#EE8ZC``bC&OF{tXf`jIAw*Bkwpx1CM9SR3M1u~Hm(3IrYPL*{?$=KX -zs)mbJzwuD%;7l3;!m{?nsNwV+G(pYuoI5ueB8cvDq0+dpEMx*_n+;~|FE~V0rf;=z -zFd%#!%kZ1q2uelBhn}>U292z>r*Qc}yg(V%MBM`AA#VS8pA5Ux}DmjO4RtJhGwNY!av8p*(T*VqIqcmC6SKKNqi-1pT^d_6y}YF`b-Z6t4V|_Mfur2h|avk -zcn39AeXonGON>}qLY2N+N2MyO{EE1g4&e@k0O#t_kfll*%FoM=44akp4a;XTb| -zy>Z{ii>%S{)R}lwhG40=l6f%2M+7G>>;+at{hnB|sHDcMZ;M@X`JjkhZ)BwW5aF7~ -z)pE7mEoXO__`0DuceA`{R%?;CY-S~~be)cO*;6yHIF8Wd)Ahsy=Q{{m5GDJj$nR-np`<@Xr>Wk(z`EW!U9URyS -zeeXZ#zU}42F^5_&u16oa5`kX(+VK#f&DDT$neu%(NW@|TI-HJ(x^EN-0|OW2H3^`H -zQj$kd`I7SJp-Kc9M2md9sWsBgjAuUPckAt8wW2cPRrXlByqMDa+_KGPw -z=nbz~Fmi`v5(b=u+`X6gQ5i3 -zfW6VH*~8xSi=xLC$Duk>NerAC2(R~wb;oDLloSMiX9mG9cJ(KcvkVNe$JZkK`YE2f -zcVh2vh3gqp)w$94CNDRB4jge@pY2F$@$m^^*}WWCAJev?dmDg -zF8J%d7jv;&{I{ewlVJo>I0yR9%)c>9;0b6{tA!``UZhDra7nM@jF;H7Rv7%nyL5fj -zM505g)N%X;*Ua*jE%N1NZXLvW9k#x;_X_c#!UgzJJ>eK|k5qau@gp0Kzg0>g_T-Lv -zRm$L3U(WQn8@2f??#3#{o!L($l~Py@Sl+2_%&kF3JerpzY+#e4Wx)?5Ma3BUhO%qY -zQYWrmlOp>7RcwSTC$g6^e1%PsqAy(35QmRqq(+AW? -zrHR%j_w}ge0;0#|boiRgzyGipJ9Ku!p>h8?3dHtu;}1MnC;M(RJA2%$V25@XqrvUa -z9^6h`V1E{|qT?@L><)2s?q`4D#Yne>7(G#&8G&$@cKmiAL0L(1S1}5ckj%uCcKh;t -z{qT&IWeAaj;hQzf!MSUgEYm -zewy7qqTNjPWpPij0xa!S5ynz3daSANtJ)!Tyw;OcnN`G8mJPfEjBOsF+}aisze01H -z2+O@bN56?OEnA0~2HkDZ?)yKv3!OeT7Z9uDG -zI>bi782qY6^WFeDv4;bj^#)9yX41gK)BxJTjCqYTb=(3v;Q>oIQdTj5UmS2TZbDC! -zJ0h7EjZtwCZ6WvA<3E-6-%)?`2Tq@T?4Ldxmn&vG>WpfJ#%roKwx^^wc)6Ic?6`aO?K2Sk(tH5z5JUq{-3kqee$}y~s+X7nCV= -z4fZmEE!A9mi!8IJa+gaHt<*NM543@rdDPf_A$8?m)^yOw=Te*51Jrors^_j8(Ma%JGII(k9 -zzYy^(q+fZ^WwP&TZEqKj{rnxtMn*9Y>xJk0F>Rp -zvbAeqI`ub25dPkI0pSm;f;6EhhDpN9MhLXjCflF!+Q|LGoiZc}!Z2OR -zNmg>_lfmrq=R=;eetY-jzsDzBKyYP8#RhE$DnC#|EkVD$_g`9Ut#0N6D#;`bF|?H8OL27DSBALx>o3Mvc{C6SOD02f8QY(A^{Ro1@B-MgCnYt8P<0cGzvHJS)!$ -zqtE`La!aNE>}T-HH0BsE;uQf95O_=fVqR(-pB`P!wy2X$)wE{o2eYYSubq)rXf-*r -z3O`rL!j?@vLTQ7r!CkdC=Yo -z-Ua=sA>xxRLFzOg4D5dPD6yco8P2$pw`nOc_t~d-sD@6bK>1NtM=leS<7S7BK|+PV -zv2}4}5myvN29X^xteMh4YacNTk)hYs8dlItI(nsQc2RJeXkB9ddMcRTxlM$hvY7+ -z_>AA#5m6^9p+hulH(TCq0nSMO70-@sAAtI`0GCW#<**^X_3(C&l((xMrH$OAm6$;O -zuD!`HD)ulf+*Nzp+(IwzZ%bF@za>>*JYSzE9}}a7%eLT^4SYDwGA=AT7<2FM-iCn? -z+ukIVX-AZbu<$D@D_yyGMsh5};BGUQ6nd@%8tmJ>3|dST!R}0dK&T$N#eqE{i5poE -zlBI_9kSdQY9WUi3{$;^R{49%@a$-X#2Al3NWLH -zu&l;eSO+7!pLMBzg`R!}uQk=9^SY*Vds6%)?E7h5C=eSDomsLEr8D||WCyv*7a@cS -zi+DXjuK|k~cPC=zPQ=3=r9~2V_K?)sC^RYmAZqIDn^BIn^qTh2w0gPU`IHdm54%rh -zcd`uLDv+rAH(^c3cbREH~gP2uL2QeSs$@0i74ZjSaowiQcCkr`&+`#wDuMRO+w -zZmQ}IYlvA9X<@d!LXz5uWW8RBB5q}L4g`8A`Zj=iGM(%a5ZWIH5tID@j=119X3-0m|W<+i!2({qxou~=#M*t2ZdY*MY>^I34t2C=H+k=4dQ7Y3^>956_o -zG%O3p*tqCEQl`kR(Bz^m^k>2esf&~DopcKC%fL;i_E5iEX5yw(75kJO!|-`dH@@LY -z#3@nrfVrA*SidH`1nDC{D7-Fhn(oeVuhz8Z*_5O5Mk)01UHr_>yV#=vD>W~-11kOi -zg|DDBF)VfYA>n`=acx<~Bf;X0!5nrF(+Xb+_6p|Ur6pZaUmqaMfoi>N9`O$L0ftSA -zP9LC~U9dt;{X1sdVe;G{dK4RdQ+V(?);IO0@$^j@?s4=fiEK@2)}AGs-^`=Vtx~|V -zt|0(KvHOFXt=1QjEeI;M8S;S&jB3-G%4fKhj~lZuLXw0N%$0V> -zaRU@?<>7XIySRS5TWp$#-G($8m;~Ue2k|Q1_I9>eTsOPfw=Ymh9}%!1gq4X(2iL4a -z-6!c`*Rf4?hFcFs$Rfjp>}HnSHpZ-5QkoD5TBtBdAZU@Euj||i)4}7E9hb)(kZ?j+ -z3lf6(maOsjIUJNlXDCDuRn -zORN$uy_2XZeTJ6e`?@&zjf?cjEpv?fJ~>qXhL^4C^wCki(Lnp;qNu)QSIlLyyHxXE -zpXw?eL>5uycKmZGMaHA`g|4j}_GNrqn*0ZFZWWmshQ|0^|B9FlMcdwpW4X5l#MoN@ -zhxKpOiqo<%l7p)V$k>1DrWw=2RW$vGF77^Q&(-zbQh_wuORv|v?1GHx=kQH{Yjia9 -z7tf06V%Sf^Yi|cMKy|uFWN%M&S-UH*+IYv*bZTB3?=@0Lz&h=f@(l1Tqbkn4Mfmx^ -zmuxN|e)dC;2{0fnI3ryu0eUhv#JOXrs_-W*GlikZD7s95#2@$7to}=M+(rx%f96>{k_jKzA5YA^eS)Ro25odNRmsMwo^AYOJ -z<+2Uoeur6O7udy%K{BRePZY7Mh@ceYj$;#&;3ReDIE5ay$f{fcGMFq?8qzjSCmMtH -zxs^3*Mh0`LEhbTTm4Qr9B@WqDCMSJSHcu7Grb-LFl4GjMPg=oyJt_ou594(jw1u^4 -zzT&g$8B_8YZu73$$W)0WWv=!GH?fXPC7KEvDsqoRCCWO^%~`EN&$_9el!)fI4F^b5 -z%z+xb+dR&9=kOW0yJ;W2_2K$ux3@lgwp$M9iUg-cQX0#>3KE>5$ht{}8wb=QIMaE{ -z5hzOL%OmZ#AfZF4d14M5(QaC$BB9(Aw%oZ9!Emg3vJ7AHn6P^&Asp%+S?V~)Kj;t} -zzP-$?3_;(74`hCtR2*H4Fx#Sni{|f990H~4o0T??8ov0=zHf_NbNSHB?(Wv}*>1fN -zKxN_LxZJF;Z(@Y_REC&JVgx>C^okxdTRYis=vD7>VEBkdfL+z0SiLh+VA^ODB!6Ty -z*=(U&DUYq7H^S4|s>{<%SsfHQ)H81M^wE7Jkmu= -z;vil!7RJxBq4o#+lI&b8Zq;*xXO@ZH_8cWqX{;+RFi3`x7afLJmTBOr^17bRrR+7! -zovb)0?#f@r^nS1HSO>@?M+~HrUxRT>$o%d{4)l!x -zqD{XCE-VNha_VFV8W&1-+Qrfy+3h32ry?h!4+q22t2xq39?e)(B!rjw -zf>V!fsH)ZX(prO>T}rgpi#2~1u*bfp1}XGcXsRkkgindzR;9p6Kabs$pQ6E%<&gV) -z%frgH5_RD;@bD)2-V7N{e+4KCGvW16GP+_7@TOM@5%g^Tb`X!AeXY-PbdFO7w@kG= -zu-K}H+C^p6B}LmWeoJ7})>VSx6Xs}P)v_|AIf6^Fe>hPa^CbCjxZ-o}eDO>R9P2 -z>8HlbvYy0~36wl+oZC!^7jCUcf^}5#D5seuFQN$x5@o_j2=z8`D)Ut~8xiKozM4W@ -z%puVj;<0MpmSc#aR|IhQbbtRG#}KQvr&fs?-nK`Otj9@qTU??wK^Zcp;cE^Fi*LSu -zTPU< -zwS_8f*Y06IsbsH1lHY})yq(14g)QLdThC2t@dtCbkbP9<@3{?-tIUM#`$ZXP{j-0* -zi-2wd*(?IDV_y({UP@q%DoDRynhFmdnO8n8GS&pFrXLv$F?gxMBBQGo?@y)Tn|qGO&cQqSX`Cdw`YS2lj|(k?AeHV`*nm!xb?M# -zC}NP?WScHi|3YO;>*f}d%PTw$=^dxoW8wEM!1r7OL8l;`{H2PpDZB6bX2?0w?p9b% -zIcdqB&S;PGt6$9(=QmfH;?53WbZn -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 -zlvF({rJ3_F&dfM8l%JiE=qNrzlV_c# -zQ3=R7Mq?6Ccz(twCHvrvO3Kg^V+YvH@HP5L#`Y(2r^u52;VT(vZso3~P?CqQOH7z8 -zuN5Y&DwR2R%>W}msn;!jj7&_qq>oKdj^5uVhlZSN2u#eRVc?bC(Rb! -zN|RXYpK&uKXDfF7BJyDSonM!NQ -za-%EFJ0v)yvNy2M|9ovp6#7Uxe-C}M21-F?vf&+TIM -z?(Xg!T}kIpT-AI2godrR&6maIX1%#b2^u{Fa6ltB>jxTcJH0q*@W0bP?k@29)|&?R -z$>|b?)3?p+jtrvhZnoN;U;TD9p@%sRn*)SFQNwnDqBa8d`m}zxeO}Em3wf-}q92TK -zb((%i+ND+Y(UwghsC@a&5R_Z&dgiXYfp~P}2yY-~$kAy7C<>AzNK;CV@K!}gj`$&q -z(}2wXG$XLRljZ7Z{g-@W@Bi4^aW(yGv7^nUW6u1brh!ZMG1h;&43NH2i%!e-ZCzD) -zI}Pi}H}&-7>!G?(NxmY&YidYdRs{{26rb0o9)FO9kEHsrIY`7&Dk -z|KF#NF!PQ)NyEv(;`?qho9`O>`Sb~Q{c}nYYV$OB-#d2Wt0vZ?246S5dD^cd1KM7U -zuI}OpCjUox#kGWGe`@cavEsh^?w_&xLPdA6g|O<#ngifHIZ~<(4P(pIx0g_EFF|0b -zLVFP!^OV@dHdAZWmxKN3tsi!geO1*DyI@m0=@6Y+LMW85$ILQgX{BFU=ehV}dC=@& -zQYOs@C(ZlWYQDI8x4QoNxH3bQ+v(NS6?MN(-fVAY8<~@(I1i*^`hC9ONThgUf#Znq -z>*IByv3xDrlON-sAL_>^8iY4@i{^f|ntemQcRqbPpRMq$!|Yo04EG=Cj0XC9v)rjL -zRh*>AikPJBV)0iNNwI-$XWM4G{NFr^B1}42ZkxsWW+*+AiAb{xnjjv4C|_@z&ku{$ -z{rY-A8`+y_ljAK~ug&rQ^iGi2;21ZTt7i5zTi#`{A;Qg5aC40{i*e#Bjtp}=zoTAz -z?<%VgD$>r)LLFYJvX~rN|CJPAV*etmIeK{9&8PFhW2~lMKFY;O?Ak -zYm9OPJb|H<9B*q3vVy%ll#-LjRRvOrC)nkoo4lQ`AD-1P{k6ggr~&4M{}}ck_NZ0c -z@v|IJSf_M{2-=Qr@PE%Ilcu@95;x$^Pw}wH);BlP?@&m{A3?8QVEXIjrmliI;_M^C -zCdFxu=$hl%-Q9XV9i}Bt=Ii_W-NYfr%k?cj|{_n$<*$VVZa$vy~j00WSrwBSKUMgIcc)>O=Of)6lZ9KlXRFOryF)! -zGygur(cCPWr{!k%IJ+ZzslUExFDsRx^?ITJV4!)z-sbZ(?atyiNv{<_?7Gfrm}Eem -z#Mg9{u_pW`xu&cAt%-`DzN-hgO+S^`rqTs1zc0Wk3+Vf443Egih^TezF -zCa_>U@RXc9@ZBbu?_3@eS;YGAcLY6)=+PA!V=aO -z8Sw|}_r-yRtgi<}6s#Fip@Ytk6UL(^;l*82Hr -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 -zLc^~LJ(GP?T<(o`f3a;ZoTT1es**?A@1$tdW -zGvAQPO2!HgyuLIb7?0^lF$`g|sZ5`r|%E?>Anhf`!XHo3gm5n*xbyWG}iv -zyrSS?x3{V0Pgi2DU{ifIEWe8@09&8yB0k~XIulPp0PKg$kcLkdYG_8bA~J7S83Qvn -zt&CAJ^;*2C~o(3jIA49cNR7{@{zVC`CPaPSj==SldgYCSlK#-eoTd?Zp?<=#nB#hH3oc -z@EFAYfGp;IV0+JBuNddI6Wc3#St%9@&s%KM5pU|@@|?F~`_Td}>Oz26x*2imWG-IMUc=_&uRUai8ie4F^Tz4oJ$ -zq@Febnl&CjaRqQ6XD8XK>k{?SDk@3v55#J>dH416+NJo_GTTxvo=#<#)znAqF$FmE -zlojYf2QtD!l>$B8jw@m`j$WApp#n$GqRz7I8#Gv4{LG6oGpw-|%>U2c+W<>eeD`6! -z%d+3gF1yQLD8dm@AsJcZ@AtJ|W$du*4(#l{-F^Rk544eyFZ1Tj?whx>Gf(qoAG->1 -zutZ#xf>T7s5|)UKEL(AebhLzLY0&T6B2Nf!?y_HyFoD~I0=wGiUc-)|pz5z?GO`Uok+ -zI$voZR3?ti`pl9F!qH?=?}yS*)bfg_E*(!aLc%FQKLl?R->~-r$b1?Md+#Y -zV0b|KdobYCjdrc89IWO%&FEK?N%}U(qMXFptlgS#cwz{|IL|l3gUwTtTYor%2hQ3) -zz-O>QiO(P&2n3Azdqn7auJ^c*9V$?p*ZhTfwtYg=z1!yNkSkPLDm=~w0~!AsOA -z=9w$;BXS7Y^s{0xjKqeY9K;RrCJCME%dG}w?|Y3^qzNF`&L>UQ&-!aCk%BmA;9Ez1 -zR#E0mJW4B=sR*G3(t=GDd}kttOW}Cw?@i1qm|(`c6Qi2`lrv6ol}Vp{a;4D|5$SyH -z@o||>%admjN1gs8*g+6yjeiNEdXDofZOYMp1f8vBYTep((o13Ypg<@DbsSAk+m7=1 -zC9MRYZ-d=zz|bin)lLG~KEP+NLFp{b5Im5SQUru~#!*V1&b0sSc$9YYTH4XK!MrB4 -z!Z#*&W0W+AP*qt2OxE_X9*UcTU=m{Kn@h(V0;*fjg}=vDv+cx3;e9V -zw*0anlY)Yk2C|^cncPSnBD6rdu+-s0ajXoa4p-$NpbbO`e#%ER{i%V}X;!$@q0DS? -z9Wa(Uv`F_-C;vVH2O0q9$eyKty7KBjn8O9<;KP`3jv#qR?0_`RfuHr)R^oed#yK+I -zl{ifSk1F!M9B~eMX96n&&cT%mGtR*^42z!{aE^JwIh6cAQ+<^d>6mk>gBSJIP{12abf5``)V -z85^=f8I@EG4W3n3NWl3q=U;U*&5ioFMol5D@VZm2(G;y_WsP=(P^LXO;CV^*WV{hq -zZv#h>4BH77VXkptI}hp|Ap$bps7qC-QjEF@=B?Z>DYt@B+KhdH9uj`}=Sx*wiVP{R -zEU+ibt4zidp)bIWLI!7^Gw#RcU`Iuir2Hh%E4D$3Cl?*QgJ2S=ra|hb;&~)~E6d{z -zaBmC!$gg5ID9Q*`Dwx&P9v6#AuF{?VB}>JR4?CiJ{jpYms|Pu*xmR4~sSIHnaJh*| -znKLRYw(|;ky~XBAHGfS_1T7wo4(B_{BF9d>y{j5)vvRDt;w_+|hTu?jb;++F9`~E;riOI|~ie4TdG7g0B=iG@8JL+H%AAENh8k -zkY-#t7I~r?MR;i>6=Ai?p@A;!=i{iGgd4ew>cT1>gHwmqSu3d;F@?_$P9qNCl&KU4 -zk-~{e@lsKxID|~9Ud$_jm97_uaM7y9bnH`9;}V4w&Vd@8Ko?oV%2R!X3}b{8GKH%y -zRZ_JhJO%BjV0G9m##&@~QnK;Yl`n&xVH(KbD7#ZE+Nw-kN|%W|#vw3fg&!(iCK5qP -zmx)U$GSP*}CS2;(Ku-B=QGIcRZ8l*n1|y}ybEeCv!C7r07-dSR63sRdR8r+r`F5KK -zCR*vFG2FN~E1|-@!#XMi@}_e -z@SLM?P$C!&^Q1&j8RAiiU^2|J5~=t-tiuvPV=$*BGU+HBmncfZJTFmPhInA2s0{PO -zkeq|L0_EptVT)Y12U_H=}^f$F@g7`1glyE -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 -zXg|sEtl -zod{!F?hy(#@+|2Dh2|L00SeDKvgap^=7=7jXa~ztmqBgVI+WvH?g0uDr=$}Uo@78r -zC^G5Do}mbyBYKEpT`foa6vgl@_ZUT{E9o3XW*N{yiq1N+Cn<{Ph#n;pnz+OUO<6PT -z!^jIBs(m<$Z@EV)LY|V2Qe>6^9i`~3=|_pTIUS;*CHl^bSc*$@w1it=j<`%xJL=&c -zSMo7ZNmJG#Qs)@d5em(jet?E-S%|#r+{Z^XQ_ibq$|9{Dvm79BJ&&B3vJ^t7Z;2w~ -z;bHc}d!xk#;Gvo8)|$PQDx5b+rHT1&9`@khKH=QIjSpFhh`f3un -zxenHM{Ib^!Tnmw -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 -zuH6sm8J}!7p6Zu2ibN^tW -zE~6{VHNRY#*Q;Hnf^k7LE!xkrJe2<%TT03q6H}?9CB+=owhHCj2DHPs^LuF(z% -z!mIFDFrsC#5*mjHK$qVBAXF5???zh6;4m8a9%vVsJ01>^(&XLs_f=&Ej* -z{m)&mpW)yW#uWE)c4p>1^B=$7g$bsAgNX9_-M>Uil%ZBThZmuD2idaMvxQe9%66!c#FV(@i(2+&3DwnXL -zG=Yq{L)B;#IG2Dtj2D{ -zFCVWI@ym&pTl_W$C4LD_m*N-WnTcPN46_x#7@NeerPQFrO}8RU9We(oZbcX&LryE5bBr6&GRYgFBEp>fnxtD?@~-=oS-UG*TfECI)aP -z!uWWlh%inxGZ7{N6L9OW<>{CsaxYu6WvBS9I(+NAfOMhI?G!P~Zpu#ai>z;BhL>|@ -zW}5EqvOL#f5Gyj0)PzAHwR#sk+V~n}q7w^`JzPWKFcRmn3qCy-BQ>_x+~ew{eJrumP;|Fpgye>SfM|rSN~`>3lxx>I8o_(GJ-!Fiqy4NWOldk&T)P4&5P8q?rSfes0K -zvl`x;q;=1Ji>l8(Vp2c^Pp1?RQK*gj`|($>q^aSzv{d3NfT?V>UjYzw{t8evBei1U -zJe;z*k89S3hZG%cYI9Y>@rKt@dvuBmCCaKn6c;j85k`WJkomCUCsk+SJG(T6U?djb -z7b|Hr;C2t_miD!fAh-JUp@O1H<4OT0UVdqMejGmIiKAWAckNvFYV~?!WhJO%L9S!u -zC80~z@-6RrwO*;r%y~2C;A}>CHxgG8(3`18>M)6v=UM`9bpa22f7E!R|s9Ebh -zN=t&elpNT{wIbAMP1(1}$`I;ts2)3x5h+aA4>igqT`9qX?`K|1sJqjzkTE0#ap2B- -zO&l)o%8fR4s0ydFUzFkPbb|UA2F;CQZw_a9ED#6daWaZDve3(?TMkZ7n0Qn`B)v(j -zNNF^RfDLOAafHYLAJid%N}Y`wrGZepwDSl~YS*qdA{4_?9wml@NKNsz*I90KYZQV< -zVkVSYpzF!$CM%eNd#HjF?KBy6qp}ssRp$zxD9{*5EXB7uSO?{`Cs7d>)<;%}O~?%Q -zRAzyn_{_o=%?i#uzkXtv`StNll(uB0wh~Y3PiF_GT(bjXlrkBBUoj||0W6~ZbJiI% -z#)Zy9v%T86*5F2ne)>GGb%8^bnGWF$73~4%8pUWFaFO<(e7ZFnnLPH%`a^2gZ7zPG -z!y=JUge3uIw-<@mAMG|seet@DD~)cWU2jy;G%{cnA|5O}pl)h(5Xj!SmRZkz329Q1 -zDb7c9_=Z;|g{G2#EAu1MSY2=aG$@$9+$2#IChOpI5zWCfef?U# -zbw;C@D3=C7RVCjp#4SRYgf1rW=Yorh?Cxs$Y!2;%^iSI~q;*&(U%!?3z%Sp^9Ok6JhQuQLJ_tJJ%STpKh -zgp!t%tkQ>3<@-R(f6k`!pTIWZE;~C#X@KbTkFXFfTF$p=x`NfT-D|dQ@GC6;(74%y -zRXf#mrM}9{%*Vk}P22IVX)E$u^us&;}* -z&@-LZ0<2barOL_&{q0CY0(l1EG46*_-hKLIr`BF?nYFy?9!8s -z^qCtJ1wgIv>=GyG%|{|}_?rq|w6?T6=FD!2XOEB@5}XA=u)56LQ6fR18G~43n;G-Q -z+0tuH4*&H}8hxuXUPw$dIquRAh$bPPnZN} -zL08bTRB6v=9H_LX868S{8ZJ1aE<`LJFqgC!Ps%V~XQ-4f?K$4Xq&*)Z+fLz3+Dnv0 -zo(|54BWaIehb`@af}SI}l=hem0ZB3W2vtSeUCWjB%Jg}qJ#PPbr9Ecn%S=D1HmsWr -zA8y4ejp#tEa>NEKRxzi36AxCbhDk68vC3y0s92>L9g0;N&Z$`C1LhK|;z@^Ml@D0H -zSmo0c6RUiP0g6?LvXNL7%rVU>iwjX+zD!6!{P?MXzS(Z0rBU{8q8pV0$?@sQiKJms -zz0vlH&sRgY?F~l+HNkSDo|)5Q+&5KXHY3z#ao9v067C8W#K?pKY33<%kxUnnEMB;2 -z$+1ouz})$aiw7?+zZS6NiNm58zG5D1YH~`~ZxVH4(qySg)Tzh08Prl3?yEo#Lw*uY -zMNa~?*NC44gtJon-&D&5cf}8+5QDr0``VT`)WfCakZJ=MC|sMntsg7ZFK8mlen=gp -zL|zW}Oi{^09v%vN8i3?+hHbLs*_gE>Oe7DzV|V2{QYFt)AbE!SD%Pyzq4%WR^M&LY -zE-gn_@@($5VM-pDq>4%&vT6-T@;JjbS@LLOSJ!PF9TUkz?|1-`XFiZT!+jNNR`Sq$ -zib-IyZa}6N=N!W)?~d)w|;UJFs)CykE#kSMe-q -z%3Q_SP{Qt*U+rvYL{IP3%ge**;<1OiS4!GxZW(>2*7|!euoF -zu{SkpK(gEmSG_{XR+PESst)?dK#rM{r8qf()|kYLt;Wrn_Z45U)783o=G&v-sdqyU9Q>0G5560u -z($79G7gqk+ce9M#$3KU;OWA@(c8l^1Z%#4M+1r$fHqC6;tZT9f1EzudEzaXK74SB$ -zb!|OtM>48eF`uB8nw5Bkh5~85-aqW<#$r*pJ*+|0ZAs)-5wOV;9HHe -zd$eiF%OzUr2UcFrfO%w6HOmkmkW;h6R3p4mioj5e@R_9OcgYx;4c51^`&}CAog1ip -zn31VI9w`r{ui%29R?5Og{!^7}&xzGrX68^25r>BAL5bEBxOIdpAcQ4a=A0R82-5%0 -zrXxi?G>i*W6-6jWjn`0VI0zY2Nbzt-YA@ntrWXK$A|14Vs!|AakY%5v$eqKac#euJ -zH-QD91zBxjp^G+Soh!Dr_h@^=%>?-i2b3pE(%BBOic$EjvKBdiF#^h}8$kLP*xXdYjjyJL|q4T~L2GgAYY%uV*_3<^M#xH>a~stvpp* -zhAF@=hzFee9dg5LHRd+Ys#*eBfa`RW3h=e^5;|cH9;#S3+i!Vi#T@*K9w(M>tSq8q -zT%A|5Q_7;3D9Vr-IB-#hIrV$0UpU5?QD^Kfy(r5@XuzV(0wH4xxe#T*E2k(EPdXH3 -zd_aY@<`ZRnl%k@H4`L?D=%@Ka8J--jC?nJrdK-!|JT)q!45;YYPAQ@+bJhWiGT>8^ -zD8tA>ajId6GFWH^F3K>ceoqZrlw~6{U{Pj)&_G2Q@X9I5#FGw186Qw#t@%V5AEl@$ -zKbh6aatlYHsqGvbwWFUsbXn`BNWvl*}4 -zq@ad^hP<+0*g+E)zb-@S436l=C5{oFLt@b;5p{Pvwb7VCINC-#fo5EO;~qj;`dinI -zIc&Oen2~%=rX)wLV@Xrk3OS;J -zpr;Ktp6vpYCgil{6BgNq6sIIAs>V|uAcqqxLm-qLdDbUIo;9e93|S(#$f+_QccDZw -zA~+@G3W6ub(Z_diPzcd{kxFV~Fl9f8KGU!o6)%RF5^Fb=B!|kj?rBn@y1VXaXInKc -zezMo)^)jDwyZ(2JwOt}JGi9wM=~yw~b+`IbSnax_k}XqRe*|z`m=m7(SaJZu{`<8e -zM=h04UjBnbj&q2#3ddRKNAgWJwwA;AeS#5aT -z#+635(XKbDbOV^`-CAyNriY(Qc~%Jy6Siy46%~rKp&pcw*=6LZBZ087;4SyMUbDU2 -zs$mV5R3{9OgrpA@MPNAp6Id@O#>}}v{iF9~Iu((CO6#2UE~%EYsE! -zt-J}qR%p3M!Qng{3X`Z=7v=xathFHTG=1tYD@z>!Cn4jPzJ8K>Dt`cMe2dgt;+n;B -zJYgtH%-{~?CgV5xGEd#5zl1kAv;azitj=V-meosho}Z{2@H~hZDJCpylQ`n^T4_U&K&2{aInhd2U(7`&rVjFaFU0tNNXMd|!X3ud -zx%8PM=DQP*;N>^XZ^%6`SC}|3hwlR(HAqHm};nR(l)FqT`r7mg2j{O$~ -zA_3(Q@vD$?MYoHb`hK93Oe2g9zKH2g{hGJjX*KJ&DigH-r0PEmlK86p2#{ffQ0e=* -zmS)cRoncaJnoc)~f#wi)W~r_&sG=tt?b>{+;We*RFRyejAf$8rxYu`md5ewKa-$2! -zV)gX0DCT=)wbr`PKs_L#uL{r3Bi#MBQny;r+movC!BbCEKyS;ClVf%zV@XTES$A?ko)4=PR(S6Sx~@2opl8hnUH -zS9yUG%eudT!Z-n6T79trm8jKdS0HceGOT36dz=pp58DbNhOB&*!RX@{JqTLi;R=N@ -zo?2=CFa##I>P*6VeWTrMH+#)m3x8hlc%W1Bir4NmZq^&iJ+D@svBdqT=c5l14ae;X -z4+7y*zkqm(B4W3dk$1=&x(Q?1DwWYi422+l!8e-d9S!ze;2m{&1%Tm?Xf~=>0Eyl} -zuK>m*8JymoNrn+ZW$;%3Nu3RN1u$Q^D#wm{Yv~G*x%VAj0WepwD*z2(e+A&vj^Gsl -zc&)W7K$w)JD%*6MGQ0wCtVZYxK==&q3P7_V_A3-iOxjZr_cf|l0D-v5I){G+Ae?+H -z7bJCj1qhAq=n9~YS>_dh&r|Xhfaa)F++G1x`XmQPmU{(&7h;sJ01~}{UIC0rGB~|E -zlMEw-%HXd6k~$mk3Sho+RgSH#D?sMnPrd>`KPzbQ!NmAy4Qeg|arKQ4UvnXx%F|pz -zqdU@E)G^D{T=+aCYc4d0Yt2QakFn;G?pkvk)}YZC4Ej$v^-iaw;u{OjjR0AWU$5Qt -z0vr8>5x_`gU_9voi8YA#6=I3qp8r>QieOSAD -zd*hR0Fn<6lj#1&RU+!a`z?5MhbG@^C3w~vApU9Jzp5_X;BuysV%qPjydtJ$2tz8`q=DAVP!7@=9pbnOai^Yj_ -zql0B)GzvPHL~;amFc*>vs~ec4;&ZJLNkzDpD5*FpN|#i85yO#Ge1T<4Dn3bh)&ji$ -zaGsF92A9mELaM~1G|;=@lF~k%8LEzQDOK9FQyJAEl(m>NXv7gt#iAsDou~_3N(&ydNj*G -zcmQ8cX*__B?ve-a0ZZipe1?*E03X{458(Fv399`lZhGm`&Du-AM?EqWF9Fie(TBuO -znl!fvXZk*j_?n#E??hy5k9IRVDz{bX(DywgbB_<20^H;<;B^bC(~+K%doI~5YrBs_ -zVdj$_(Kd&9ddly$Q=uMq#`fL!o>lJ=HP9ZQpru+a&vVx=xX+ -zmTl4$*@g?B>7_Gr^B13lLHZ(xH*?<$=B_Yp(%KD7HPLip+07@fBP<~$AT_s4U%d7l -zub()rWsSvlh5>a{bysGo=cP;z9vl?76)wWTpOBC#C#Ywe?mx8hgH*=Hkx=4idBXil -zH;IJ(gVZFXl;C%i44RNqvJ})jKILzgq7Ib_=};k=GnSOLQ=Oh4gNd8mv6an -zw44A9#2x&UC(~n~!r7<*blnE~cB~-xM|G+3ocDf -z&0OU0W-eVpmTNaq0XL$8Y)+l^tsrNfkg^nHOpJdI>5p -zsPY#ylA?iQHWbmoXHF6g=_WH9lgbiFjBzrlxaI8_*MhebWgUBpqPnfP3@6y&j@b9W -zfddI|gnHnd^v!aKSqHW+BI4en8)y#GYQ(*jzE6som^BwjhZSd%O#kUK`vHR5h;~y~ -zo88orfQZ3UJ$zl^HfOTuPwG>CCX!NqT-W_eqGYb?DKGPv*GrLb_EY^g>7~KoxR_P_ -zHrd7nsjk0LwsS}p@}bk8C+}PizBVFph<5;#g}}w=|TkiiDxf4XW^MM -zmnXh5r!HH3Wg?*N9a({PB*m9p$fo#0P+t|qs8kjTiZ2?(x%lFkUo?pG^TjdCdA|6w136!$8LMw~iieDv -zU2kmEP?{%JXGm!no4N2 -zHj|^AOS`%^cnsW8&xz78+iU!g;|tSl@7R@2_o-TU!SZHUL1`Y8k%w`%+u&84yNxT2 -zZUg1!s}zM6KXimK%-TM}aslbLHFa+c^9b|(qZewqjxZm$>?2H*ly`(l-m9;vtRu|ziUA&B -zTP|;)_vG3leB83P2u+f-MW&XQTQ`yZ)~hvJD_IFL*`^g6(Gb_}h+Bt+5V&7>$Pjy^ -z5%R=Kqzq!~LW>S##HwXRn{~Kwk;$xsA977bu?`OONShS9TzJ~WL*$wwU-(0GsxaGy -z2Q)8ri+CaZ%!MKvd}gW@MMUIXoO%T*<`T_D6HyZ`&@5(EAg))Lny;-0!(Es^>REV` -zl+q0AxZQZ+Jvzm`1~x35RF}dmygx`G7LH*C$HFZqE5^c2CmS{kH^s963pbs@0Sm`e -z;p4FuS-2^^hRni^(HsdD&UZ#W7C!Hoh110#e7lQl;l<=MZaD|r>uq4N1> -zqQh9o1z>Cy3>Td$$r7Dg^Ruyir6)a;`MSab<{q&Kn2Rq=-Dfbb=T)VOtFsojUZ_k( -zwjiB!2V2mTy-BH6WD9cM6gR`H{Vm8BwidS_SbmW$NcRPG*|6Wy$;(qrJfhjBM2v@T -z5OFpT-(0y_fenAtyXRE?X6pI~EseIpI%5ulIhz(@I1_Hf1w+6GqDcM(Gq0wrf -zi8JN<^iGiH-)pw7bc*asaK5s4rRfv}cct+(#df9XG|qOV-GmNyrSXJLcctEN4I4rU -z+tkgR_WRb+yw)4p&Adf+wo451ZFNT&3~=w4qd4g4U^=Jky>C3PZ+Uy)4udlG -zzA**^-20}o$WCe2?|subUGIJ4c^&V4(|OC=`*s+VvGqe_Nwzx -zfL1S^qkP~K;&;ovZWZa6c!~mm>8mlXip)`1p&n}?mb>C1BKTOd-D_O!)>^0niNw@e -z8zW86k5f!65{t+9v$MEU)O(%og$|z%&(mSzx9hdL2LEiX^<~JTelBe6fInttTG>g9 -z*hhx%3Q_!K8*MCoqfICq4KXtr8x1zRw2j6Me8*DG$HO=SmCDg(d$n^-M!IZVGN8`v -zqm3TDa;nD9NkeYYxoC9c2HF|I7^gC-3zJVZ=BJicI_)E?wbl*no^<95{%65{@oW57 -zvf!iXCqreyNHNVg8AsDkMuY{gpOqyr=5@3<4ypBgvojb$?Lc=g3b{aRze>j~=*3@vmgz|{e@24{Q6uiR+Y -z>37vf=6O*_DzW8NJ1gGBAQvQCUj)bXeNAQ9;Ux09T_7tRQg$QY>3*VW0JvJ81(WAv`w0((=;yf -zmNXZjrKJ)@9vmqnBl0#R5fVh+#-xMU{c9-@dBdgBS{HenbWCT@c}3nPP19)_7kN#M -z$ZIxB6nTi785xncA&HP6@-`+N%tT%@5P8F;(pndJn{-TP&v`}OCQZ|68W(w5TNc6_ -zavL_MDDbSZ3S;DaWh~t_j7G!YC4r?hEzBnp%&<1FP7o?<1aUJdU>-9zkX9iJ*W}Uevn11wYYF4t> -zgx_SY2{(0@Ynm-NLmot#%R7f@DvsqG`kXI|{9>Dh=_fT!xO2KvEAmFGY#jB@*RD0@ -z<~oldDd`c!vQz_GQalJ1F(@JT{UZ7FQMurlSAAr4_BcLJunWZ=^935r#pC-EBbkzC -zLNzSRgctvr^1$=3Ge$C8|{;=7A3-0S5aP4 -zmOh}n)p2j8(M6xV>%1U_H$FjW7+!~`W~@+IZv0nsb8|5^-41#Gc3<+D6=oQSlg-Fg -z>*MXZ>+qz&=yY_ut-sLkKFzU&UQi$wfR=V8y{Cb38syZigEA!jb7s>uYOjY -zRx7zrc+;KwHE+4oYSwYkg=3C8m>O+9;L2jHi>%u#-OhEdx7b{%=8t_7F1?Z+WT%7v -zkK;#ctyZUALj^Vus&liqQbna(%{IV0u2dl4dHLz8EK3Bvc4m&a3>qRNk63I$P@DBH -zL`8{QJFAzF-yEO>JLl{&YS7(4Il2W8rRz|)dbw3Y4{OarO+8fwXo)FQ#L2M(#LJ?k -zT+o1MsrNmaIy~)&n>lB>)XtoqYDkX+`AuEFF3Ddy0ufKF&lR16i -z-M`kWX-c6hsvwxzWk%7dJ~`pdB0fI|ahmCNmTOm0ha`w!5?v|Q`a1j8Jl+CO*?kFj -z>eMp3(2z#B(xcDd)pxaiR+nd|uAkLs?cd}(*t*-u>uQ<#cl5dekvTO)8+*SeWa~_G(?&lj6$mh9qI0qqiXm -z6*+n^n1)h8!do!fEP=W?Bj|nHi{`c<`~b1-yl@?vVU^3uhK#kzKF}bG@qyluB+PT5 -zHzc7-IM6UwrXOgn!cru=*lF1X{{*U*g|&fso{hgYRuucPChf!^YAmdG%U7(6DS#g7EOg+)IUZM4Z~3j2m7>|JV9LoJTFg*qf4Gy)_xkCF(lXy7E)`&$uUQK^J694VS-VsGdz4li-UUc#vJ7X3>w -zkC+(gmoVzwNB&n8SmADwm)6o7y4qCx9uU7RXrIS(md2U&)t86% -zXQyJ)aIIR;)P+3^=6=eQxzF~du6I@&)k``{Q7&s5Jdz0o?1Txca*J%A*QnysO?kdcmVn9(9lk+V451;DnBX6G%?- -z+MS-)xW3%G-pTeYZ=u$!T?F>h -zNOr7G?8RDpp#{s@BiI0gCGrW5?P}*5Y(Jhe$xJMRdw_GehO>LcQ -zH=go>6wv6^BJ5>Sv*(aURaun@mM1*#YWs#)zj<>!GF-8&Pn4saMtv3Bej@3&O8zNN -z_RPd1a${1LMdm?x9%VXfsmqeKyt0<1HzblnpuBZv&Q0e0;Vhht@WWcTG@%b?;pOgZ -z{Tt7>)dSrG+LtaWQa!)i(UpC{@ZGVhH(ziCKM@bx#E&Kk-$UX*8&8N0Sd9NHNU~QZ -zP57A@Em(VWob0t7AuW2gcMO%Mo~m^hBopti>*AbuDftFQ>HFdeMk=ln4>XTjRSnC}4KrcQnrp;`y+6)M$*n?_K>3wvo*DdH901~f9& -ziU=9SvJ4>#rJ`m!NN?URy^8x$b)Kfagry9iDDvbubHes?0 -zZO0Hl(T|_a&NH6Rr0{dU0EYXaYL&%WG@@wSi -zxlG!&vy(rC*$tPf<}ye_EuC-zhl>d(%}|?MZh@-|s_f!i&Rn{$SI=>_Ac2AL5zjy& -zKn&!?*^7B)2VGwbLSp-o|p0{&ooz5yWEiO_cHdMxPzEo -zIF|4xxGFxDu3O5Qzx>i6Zai*X^jSH6eYb3|^DVS8vWOU*jP#R50~9-1d<6TG)y#9U -zXs+nVf-yF=(8ap#);{c$)x?_^!IMQ;1=+LxlLd>3s$b%Qo_wF6FA^^bX-_PsJ+X=} -zxN@4iuxdDi&(aJspKkjAV$l*x$jm3`x_oiGrz(5hHs;raIFULSZ+(|kXps^@p|bEXYS5(e0PQu -z#mE4L{ -zL~;ot^&@!5U0$o#8!Ic-nZd^DR4&bVyeuEy=}5gZMBTtZjtVi!K{=_yY$W#|1sF)* -zcz8MGo}>~&C9)&Y*4&Z`GKXA5E`vGbLPRSH95Dy?hz*Z9xL*s8KFY-$LW+q#j$l5} -zXDuE|>3Xf7X(^Zqj6j=j5pj9zvn^_~B(#sp>q6L#9$FH}*>6^kJ4i)5IhCNwY1$yu -zgIOJZeMxhpUF#~L#OjR$!>m?L1@5cysm$L7w+^Vb=WDm-8=iOsZ3X6=;fYpb0Sd}g -z29KYOV2aC3fT_Xb3A5WEpD??4Jg~$?6(OzW9XS5S)2)qTs<{!0*agH*SLscAX;wH2 -zwemyjxq&-k%t)Xh6v@HFWY{ZgW(1r_C*XLDfDiiwObx6*1BY6H!1^+A&b;ZI@!3sc -zSbg;6=Xvo{I%0=|aVn`XwYby!yr>`kZ<1?KDsgo|wP(}g>M!7Grq~PPabBn>BNm*G -zQ3z))^(U0&MtEa+erdO29jCpjXi1;WJP=dsGY=jopkW>{tVsSK!_Z<+6?U*YW+<^G -z%^m|Q;DokfF%=M+o&=XpWisbVWHKeJBa`t6!xP=4`Ukq7&!aM)7XlCpFT*cmbvUjKzBY8Q!MBLwo=%Dp63od5 -zczsCdq_q|2u0s^n|6V@rumhL4Beb|EU^kL$q2vS7#1+ -zDQ)ywKyNYn7S{@Ts@iU$s6hMb`OZSaSJjL+G@^aV*w7SYmUlzj#zplvG|ifGL)%X( -zH#DC!&xS5IW5R}R+HdFp38x#n>3BnjJp*xjKa9U&YZLO}$j>mrZ!nZ0k#d7Uj91@S -z9y9CHw>G*q8KL{b8Q9*>+CIQ%utAB>ARbWcY>tA_(#-9kzRqCA7Y(NC2n)pOn3sET -zG-tXA3t2yQc5+u3Wh%CTPLgPhnuoc`6)LF~?s@+h_RV3*_H9>~Xw^z&TcuTniCV9* -zWuYf=^pkkeW5`*Z>&#Jsq<;1+_GN@E&3On{16!H`TY~P19|(G6a|+c|h{vjSd?xbr -z*+Ng#+!h=tVQzQqNFR4;z@B`&oZ_j7APj1A`+e>msmBq+4}f{;aY$!oWUse!`jteb -zN+xp?*3cA7d+e1KV09U!Ol5tgbG{73w4CsSF(-_W68sE&aS@BNy35(d*Y-7hoR_>B -zzWt<9!{>A6(eMk-D7mb9WnHz`@B<_qYWT4Ctj1ORV@2+)p-A3g#?hj7AP=O?g^>HO -zGUy8up^)OC58gtUm<$23cqnL_BF^|RS&l?M6T-yAOwscnzoZ3e4N#^ciqWFHuaRQ3 -zO2Im?nZQUzx$XQqKgoSvVN+kI@Btr^ELl8+!Z|Jym9m!V4=)aUS=i%dnp{{^<>{P| -z(C@gGn!wfzzgD?cOp%C8JWeE5o*<3_-a0lE_Kv@g_%|E-H$BD}dEdTtnBJAw^;w5TMYQ|PH?TE=a -zbiL7x0PN`A!y_36w_a%Rv|RfOk$xqKPCS*){=C*VB{%c(E7T*BZ7DWmiOP8KfCbu!-?Xla~!}2zUFZ-n@Gj3x#RE)1_8G{6Om~1CZ`2MCF*UrHb -zzSub&H+1967}tglp{t61DLMa#;K9+GaDB%B~aVdgGHT^~J`*4KyF}P-9#~F;4J^!&BV`|M@9&%0LCG`ZaAhqUykEs>ExW -z6R(swwKYJzY#k9+xkRiotd -za&6vkxut6J7(uA%?$C7D3~OYt2M7xnCV*^4bV2yanUx?anUx?QOppmAzRzb9jX#8DwrLba@2__(HXi% -z`ktfNM9@o`v%t|L2&uEEedTJ>bd`yR6&5zRxxzEI&Xdgcaz{FHA+*Sa5QPgxtX--L -z8e9zjg-D_>4Ch!p)&de*=~Q5eVsM?HDmr+Y6F*KsA;EaPoN|cBg;_#JiU=wQ5lb-| -zsk8`O_LM<7bOK -z&S%e$JfA&yyhL%C6_=Q0Z8 -zhfENQ>Ma`m#ZA)}En`9bI=iS7B5wbY8u3aFWAat{Y*s|*K0xw=RZ -zqWI-9kilkQbXhq(*#z$1OPPft_^0Buo^E8pCII><>WQdT%^jYHDSXplGXj_P+N-OaSK3Xh!{ -z#AWRb;_sp#JjCAyZ#-c2HcCK*-jL{k;N}g*QFP#zI_HNoakiHonKBW?fM?dbOY+wA -zC8|ixiWr^Mt5mu(mj)>$YV|`Wik#zIG -z=E5{J4N(M&;Y4TO_|4TLM}*E;i_@T9A*tiGX-d{N<3?|Zk%&_}mue(K@gN?odiJ -z^Qrg+W$?B_Ey8oqAjf!;7 -z*-OwoXU`NIwN&1RmdEb5kRw}`+XI~g -zDJ5%CCQZ6J={b-|FbIPMoGgO{xWO)+HeVlk -z6eU)q*HZ+w>eDEKRah~Ez<6xS5O`7bybPh>tjP>vP1@5<7(yxb^zgkQogrjWHH#sb -zyz8~W5Hd+&$PfaGSk(J0!VsMJl3m*6Qy1g#zF>~8lZ!ywbV`mV_oNh4@zZ7r84ZwT -z2>%3Q$;tEoLP#l$xBug-3#yL> -z^mkyLUoyNQbe27+6XyOc;taxN5@kq9Q`q={5XH#NB!c_!u$I!M;H*YO&S(Nc%t`3R -z*h{n(wrGom=a^bC$rI5L+M#3ln)m8x?mpx9O;g7uf8Obn7$STV|V -zxBBFue!Rm3PmeL5Sa(#iWt8iW0G5n${SiPg$|6@JV>>G;?!pkAt+=NR3J!`~MQRaT -zfl?0ZwzvoJB7H7L<$9JV{bzagDQx@7x;us^u(5)IVhCQ(yg3%0pnq?)5WtxxhAaUb -z*cQwL@L)_XR#JF- -z!_tLEgoapg=2g&;6$f@BGnW{ub!oz9GD;ovwNb&j*5Vox81R~0hAr>STx1sS4K|wD -z{it+bMn1N??#NJ_>`#cYF(wx*fw -zx+6nzX1nf4!kO)Cvh6&-CD;$Rol6;6ts!7w>-WRuO@<57*NVm6^wV&yCQT0$3&rJg -z?TRi|vuc)E=AF_|%mt=!Gco5T%+6oR#=awl-e;y}X81k>)!poU7QQ1|yvocaW=YCm -zZ6hKn1wT|zWhTove2aljFnVt>bBS4RF<9G3y~Q86kh?FFzU~m`+yzDtHzkv!g{`pK -z#Oid>W?vVTN~ZVAbmzsTP^s{uC|K8tSIfjFu2>Bd0*gE9ovO9#jn>Kb!lfH+HN||T -zGCz-+hX~srTUo4i8w=EY6GcLCU=T5Uv))+lH9PGyoz_C5i=c(aTC2R=SX`%2XT))I -zKBLOf)~uf4J4n?YrE7LElM~+Tt#&=wSu@?va_wrZ*9f+a>XKOFzNX{eOrv|H)4eX% -zq__ezH3&oT8YmJ25U)x5a4oJQ&lX&Z>rCH$nVOH`?h6#4A??1kxQ;x#Z!NAfvisJB -z@H*ia+G$i~QDo~JwO$T2JzI-xLS0nV!@8o2T8q0caZ#a~%b|v8tCZ&$YXPdgjRfYV -zquvQoGoN%|w6(%hsJM@SRw}gFFY`pbtuW18jJ#`Cl^ge_J6FHI)4f*hHLl~9P~{;d -zkF7Mi)3xjK3$<#9;EU)SfMinozteN|)|F+i-Z}>5=&4$Ffs^UVGB1gBan8Fq`z=nU -z(DR`eMiqf7zCx1qGa0=U`dO&yN&09BKT8@dj+@nfn~AHHlVd(_s?pucyKZPGG`~Tp -zU%v1H($Yn>g4F&1==S7y1v!#&a)cb7i1Y_ALpsmygavELu6=+RF1Bq8Y2D>DAS)B+ -z%tiy+)?*>oL_`QT8ZbkADt)&`6|fSTi<;q>Z$t2kKxzF(d6i!jI!fp_8cFWdlxg6a -zPe=vu3)uHPw{#z%gA!>|ui93*PJtY&px|2OZv#OEUU<_^zS*vIZ*dKV -zRGI2(Bm@=Pq(7Cx<7Xq7T0WjIyAARQvx~>`@#sKPwB^zCrqg@4Snz1RWn$eRwZ|Yp -zdIWfMfQ#*s6a<{WcJpKU8{&Xw>!i`8;|@mm{)7~-cKubdl7CPT&--mIZf?^n@bAXXxstPBf!lATx<`oAmC8Ac|n{Va&sbr -z1vd{6A7O4D;FxbiX|P4QZ8~z_4!n2E`>B7y9$w)ke=- -z?ljvy#Gg={O24loz@{CLb30 -zsDhfjXyxeNQfZomKDE=yzN%%+T*D7tYCQnZ$A?xdItxP9dX9 -zSk;Vf$-=luRHUb-wBdygR@U&)PcI@`P@En`XO9z7l>Oknk4r;_8m1>86LJRdw;HqZ -z$KNJ*_r!WFAIDV|L3{LN-({I?0a{edGTJ)>u)}XH)b7QQ)-Dzo7@M;142vPH-Tv`} -z*=>+dm_2yhsrk9+O*X5({uyeXJV;fb=z?6U0s%gjssL>{$vzyY0s$7bf{LR-oiWN$ -z1q$LdLaIQ)l?*}^;Fk)wszCUjVj;iGaLKI-*bQ&33Rn$qqzdp6^Qi)M$e5@C5}AmB -zr%Y7JYjYlF!j401I1HfTK~KDo_xw5mE&TuEd!tU}m~7-Ha%TdSTYLQE{0zgqA)RMIRya -zGQ4IqussUGY)EFpKrPna@p`szH7iAeSJ$K^0((fNg{z$+3}yd%6I -zFjDRKHGK-#^wi)h{KyZ!IvTfNBp3~%!B=q%EsX|t#>V(`6h@sz5b8m;ismzdAP8pA -z1XJO=3X&H^Ahx|R-Wh_KmUmxHj34WhaIw~2Xd#;Sk=UCH`*Gq}inkVWIZNMgn0RFL -zDIrWMj!@3`s`b$D?rzC3QPKO1mYD<>KwE~&uh=;mYQahAG9Y?{ha4WcJq`gnwhYxb -zGZ-*bUjYa6&19(jw}lugA7OwDRj$tU)vM19=4&gB@kx&=R(di_Fy`CR9lUgcgn7cy -z7^)S54jC%VyM`I69ocjNOs*Jephnv=R9XsE@0YyIii;PV)HOp5(6MExoCdh8DGb%t -zSfJwq#IKX}%mglAaLC*{3EW|y!wir#d8R_zkGCU78d`T)-T9NI%%ubuZ^f(DEX%2} -zrQhbuYsTvU?c7)Q+#Rx$k+x&zS%y1J9c72T=leUw4tux9Gkxyzj%WIu3Cy&t<7tJ& -z=p0WgwDTWN45LZBF|V;u>(!X&&9AJ`cikTT -z)L!6^bg$Q2%|^Q?26^<cgkJ3FY6Wg1=3Eb0YZn@o!Fwf4_Vg&rN-E -ze2SgAeEHQ`M!GCU}kN9UR+lK$$j{ng=+vWEH?%<#J -z7i=g0_g(ULG|q0ehkp|PE`CMh(f@XH$QX^VhyQLj|2sWFzu3;dxeZYKdN)4Pzlr~d -zzlwj~jj?vHy?l(VY#+OgKS|%w6O7Naga3^w_|Uxc5B*B~b}!%^_{DC%UNN@#4P#q2 -z|FcPfO$uyMV3Puy6xgJ|CIvPrut|YU3T#qflLDI**rdQF1vV+LNr6oYY*Jv80-F@r -zq`)QxHYu=4flUf*Qecw;n-tijz$OJYDX>X_O$uyMV3Puy6xgJ|CIvPrut|X-Q(!Cm -zMi^^*v;-OJAVzyGbD13r7$6Y_JD -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 -z5`HBi`wlVRP6RLPoTFDWQW)T1pn@K_7K4q -zW1mRK=)L3fy%Iho;c5E*u`TQ}!T|k#b{O;S>y9CFfw-fyMF1C&4`-7eAK7xPl06R?(e((i?e+Bw5 -z!Mk^}n*{$1?9c=shuu!X&m{a(!eV>i|IuFdGQk%i&k6pG+t?cf@7>SdA~=1R -zy-RQ>^e2M9dMEps;4PdZg8yU(`-0&AvXgyH@He-yopc_K-_8yb{PC^qUV^`m`vk$i -z2!2QR9>53a^R+E(jNsqd!;TaD)*cxcUx&Yg;19#DLhvorF8c=H -z58?e0ymgT6BzPJ60>Pi!4mJ|A^430>|TPCxUUkd>|^&6d;$6&!GFuxaf1JJ -z4||Z{zq_41MDSnkVV5O5P4GY5&YqBPn&92wuf!JsXXx`kzm3fid83TGj -zWvtS}%3@g8D~?=0$LhSu=nt&F=z5hgR&OYbarz$X<@z1<34ORM8uah1yXa@k&-Gc> -zRdl1#F;gc~KhUkI7wA=$F;9OO5nVbrVxji(IdrHpmg0hX)=zplAq|BcKT{$AA -z=?6J6UGHW6Qvb~ONvD>?Y+aA}rS4xG^Yr1un6HHBYxzVG4Er})i -zKKG%n$%}zsU8?7n#)@BErnj@6>iZe{&DZlh)p2F9D*bi&F{C@?#%e9Ch+*wz-Pr#f -zt}$O*92I8F)su>&?N{^l`_WOPn{j{Ydn2M+cj3LM53&BHv&y3WSI6nr#WC?$$Lk-; -zqw`nm($9I`>bZF_Nhfjt>24!qsyPj`X8Utk9|Xu}a^lh}9{V#u`1fB61z~tgMJ4{a;=b -zSy$MD-$!jPhzfl@KdO|@x-seJ)FYJkh_SkVPShyJX^zvgN}^WpE06K|S!LAeJo+B= -z4*E`X8o!VFw}=L9VLY$fP}kL+=tI#%Dq@NjMNHMd7DtnQ!Jk_lQ4-U&gY}h^=||D4 -z7~kkO5wmpdk(Egjx$O1^1R5`SGnH0R!(GeR(@3I -z(IcZu2PXN-R}H#cgvn&*yg5mBdy(LbRTypObDR7}+UE22Ta -zEs9CHDfL~QP!yAOX>Lr>rlOdtXJY#F}A858vc);aVLuB(<;Mx%aG8IyGy>mGU@;|{%p -z>#5zWQ|TW^#&jJnix&O1JZ9)AIWbfBW`3j(jgD45yEJC&4LQ-K&zHv>-IMX8PKoHy -zd+2Y{1w5zqNUogL6&f(=X(8`Dy^T7u?o7Xm{*nJ*y+2||f1oc#Pv?5;4rQ@MAE4*h -zI`Jgd%k*^Cnf1)vDAErY*XW6(qe8DA6;=9fL5$H?^P^hN$cwRhGviFH%!zUOIO|)w -zeNl|pY@XX%R~{4e_oY#HhSw=}O*@n#=ly?#H^No=_C+x>rTa)h~H&>uotP -zPcJNrPQ8-(s$R_dR1e9D1$ym>=+;XZpJ_hhPQ8@*u$C1>kN%l;Wj&YmG;J!5rFwZp -zpSIH5u8);QzxJ_Cte1|80nK4tr&|=npw1W_1O9m%!Jh-|V4SVz2RG(gG4cY&dwLt| -zw^~ykMLJ9$qHfLeT5rgUD&2$i0$n#Rs&zqGjMdV@sL_iV-|DAaXML(P#_IuGXYDDA -z3HlP_9leUWfmW49gKon3QBTN@MtzBSp)MF1Q*<1CqIzI?H0k?XZym~s=44(>*UNIE -zMUO3u8M;nU%+%BKW0u~S7p?j(&u#spEZTHUZp_i6DxzIi=f+&UhIzeqRKz@ecVu+x -ziz8ybzEu=m`fN@t(6*xJ)^&ML>o?T@^eE<)n&EoudwH=$KjM1pecb0-#(P@-&bVEV -zER24AtT>kIgxna=@zi7Vw_IOcT@)Cqu -z$e5s~aGxuEv=enL=AF88WlU1)Cylx_>z7)QA5)ZN;Hml|<1_s{6VvpV!f4i`i(|U} -zi}$uxa=+^+#=rVpVa(E(8K)^bGiK`~p6|L1?`{2__jZzcu8uE`4!tKo=IH~)(WwvR -z#e8jJJysVn|I|G0cYS44EL8en7wM;2u~;ACJ+5;`#uEKyWc2EX<*`&B;eD?AGVj!H -z^P*qR&xz$JXT^Z-P2ESoq3)xz=sQ;02#56Pl31;OV7)J8>W%s>b)b##oSev2{y608 -zBaG8^L4IWPD(-)sIXbHJ=g~1nH?N3l-L)ddD*dK4`sb_|r`^2Q_2;q}ueWpkwYfMZ -z=x)5%wK6{@>W|scpcm1p7(lOSA#= -zFhAAhS<$8cD2W9+syw>2YeX#6d-7tD-p9O3x2CUIxeQBmTh?)vHk+loGj&aUd2}q( -z11qCn-{ku1nT+T3EZ+0F@8}rRomd~%>6sYP`pQ_XJJM&NCv*SndHey{7-!SRqeqR5 -ze0?yYNOLPAqrastsJm50l@3!6(EE#`T0hB(vHBa{^U8YbIBm;Bt$xGx*N+*m>knLi -z9mtP*-E(wI)Yn)q)|2Q{*JJ5}PBO03`*{BAJjQprspC+>gk -zrk_EZGci*i%#K;Qg7>|SDT~?q3H>qpKK&S)UmorHPu7)n9CbsjD~x&iX+d=Ae#J3g -zTPmYVFRY9O`pu~5)^eWzI*IX}wvUL#`croF=o6K(M01#@X2Y=>7CV>toa}^f~T-J#u8M)~$+SSm#y58oir!_OaN@daw@h{MTdi -zqe#yyiHz>XI8XOxex59hF*<%^RO@jiF;+(~uGhX%F;4rLpX;Z2FA4eapj0w7$ -z^$h(Z*I(x_U(*Y6VvuZ_|Z5|CI+|o6gROIr>}X>AGrU%+<@vqC@}1`(KaX`lp{)#C$C( -zkFNCVqho;{#CnD1as9PB6N|K*x|LE_>d`IpV~Ji=8NIp=^EuryFZ#5K_rIQz6aAV^ -z-9;xc-qUj#@9Fv_F{l;vP3g`hF{D>>{q=16EcJ_`Sfedm|4r~p#(#RysL0m`80YI+ -z<&n`x3!_4JX1=b6X2%$Pm_7$Rl5xJWf3il$<;FPubX3&p&Ak8h%F$7$M>DU}(~6^B -ztEeCAgN*<5pph|2_soh$UC8~f842{s+C4I*p!N7W4IO`qcH> -zhy^+>E4uYm_BH6|Jpc8?;#jOl(#NRmTwS7nDT!Vkrp}gfY4mABSuE3)MbWQsjE?2H -zKJz?nqW-2AFy7bSvA&>HjQ?~G_CYB7Rfn~Px}{EIzr&_Dl|CV@W&E%I;jh%W)aUfo -zOjPIs-v4^d$QYwHQm@hDscS2B^&0IgiE+9`PSolY#{YUX*I$pxi3$1`>pyx6^E{o% -zx|)7g7L&Az=f7^lJ{Ucg^-SHEJ|cZECz^CpQB2c|STE9#D`UD&%!?MiFF$5zHvM=y -zw&Mk|%dK=eYPi9?D&td$hGxB4;?!r7@-=i;5 -z-y9v?dg|y{sK+zk(`PfWSidZa9zC4-z3xT7mzL7Er)!r)pT1rh%XA#~zdk%NmMe9| -z0bM~|TQ8+fr?aT*==Aa!(lY8g`dMiVYc+KpEoc6>8D7NuUmq!rd_A1LApN#DGI|{M -zzaCT`ReCV>I-On|)w)0Le?6-*YV;uLb=pHerk=s|*HL9rr^hq@)7iZL^#|^M{jxY3 -zlFajUnDM{9!aQI9#`RbBOHEZCUrk!g_+MvaN3*g|WV$x7Z%sF%PODFH|LbnN|8?Ss -zXx00e?`wHUwCUv|Vvb(J`jYNi5_9#{qUg}e82{@K>q%M>F<;lF-&ud8-$U2Uj&6M{ -zCl=~~qua@?x3Z#6CBDB@@f_k2x`**YW(< -z&ioiuZtGRbdg_q=Wpu38m%0A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 -z0rh_!qEA#upN|LSFo|MhPAboGj&7*O^Bt -z8ODDaIWa|#D~PF@Vf>$DznPv)|A!vU`j5WO_)kCJ{jV!3Vy3>rc?`NS^?$vO`k$^x -z{ZCg>|Is_R|8bh(Wjfy@2B^1|LaeT|MW!azq%cL+WIK+wq5h+{bNzLg`j5WM{7+YnjurYBuD|ZU{9nK0`LCZa|JTj9 -z|MgMke|i@Sh&$kxJpYyR0rFGk`LEY9{?iwD|LarPQKjp04y6u9RO{^Q7^|<8MUCFd -z{jV?a{@1N?W4ul&iaNcV^*@dBsMqHsChG3o|GGK-AG#ImKYA(qi1aDOf4UR>KYBLn -zzj`<8KU&55pB8W)i+-1h7Cp5nW@s+gU#C(3(<$8l`fgFo*27u<*Fw&h(4QmP^)%N1 -zbQi9_uEqFIm*qyME-Z@qdP+rf>1z7-wXH0=^$F^K+Cu$LyBPoJBh>$N1ml1Gj{1)- -zE{LW23irRZaZZ%hF#p#VS^v{xSpV0jsQ>CFoDZU7GOD$czbSmRNeI+ZZwV&&+6Y2lbbs7I_YeCfN -ztywW%e_{Nm?@<5My>g;n&!GQT**Dps7c&0So7i8gFYx@=6{BN{USASZbzCNzbX(T{ -zbya>e>)zb|`VP;3&EY&A{T=mR-GucYU5oX9-GhB+dIIO7>HGA1>ju<+^tahDS8FSy -zL%(MIS7($(r|!b|U*BN-r$3d(0-Z_yUu)_A)CSJ6($QRhT^7-!E2#hJgS`Ls7T*8* -zGkyNL71v)Mp#H1-^8D8>uD^ak{Z9{L{;%J2?w7t(6hpc{_rKmu{YT%W{;OZ{{@)4T -zp#Mv^84>xq5A%N=q|aY(=J~ImG5^ySdH(A)%>T5I@xLBBDr$5b`vdi9`aks<_6ci2 -zPSj~9>pyxX^&dTg@xLC={jaAo|JQX{|I^2~{<;tSKib6nPgj&glm4FZzy7W~n)Pk! -zf7;GIQhl2Bf8Cb;FP%yKM~`8Du-?k^U&k{3({JeiNk6CmLpcX;uHL})*Tbm)>eRgG -z)b%nkUzafd*9Un1Yc=CP-IejbK2{!!^aj@d^=#JvbT#+Cu220(kD>ohe`5Vt*RW4Z -z*XH@JpR&(g*P;HeyYc?lx9R`UO6q_5IrD$robjI?N&Q#f$%!@kSL%OtxGDWV`tO3s -z*XgYP>ATGT^jY@x=;NHnq|2%Q>s^fhHIMqQ?wS`hx;^VZdOrPsdM))|ZOe-~ZRh!~ -zi|PN>R{Fp7xT0v#7dQu3uV=qj`gQi_X&Ln&-9I~~Y8Lxr^$hAix(D-rtzv(VuFd+7 -zE@1wzmoom>Q&|7k;hbpI35@^ra_0ZKC*yzJsWRI2Qs#d;DmOaxRn~v?apwPe1M9!~ -zKqk8M-+`A}1E>$yw2(*Ktmv-og5>9?kln?#cbHea!!K_lSPomi}Lz -z&-%Z9NdJe9Xa1*U)PHmX>c9FR`@Hln>c9F3{a<=IjZ3@WnOuLpobjKY%J@&eEsc!6 -z%=)iRD2pnsq5h}uQvXkx`oFf)|D!Lk{->k4|Mfz~|GJ9tzkbO0U;oZI5n9jqPj?v= -z4f^l=n55Hq|LbJd|Mg1tf9Qquf9gHdfAk5S|9VqJG;2QRpz2GUKcah5|JNs}|LR5D -z|GK&|T6LJ~uchqUPQT7M=6WIf(De|`eblF^|LSEWF;D+*M0D!?Jpc96(b1)MX2$~U -zW&KBQ;`yI`o%z3h%Q+u9p8Aj8$MavGp#Mv^rT(KsqoPlP=fAE)|Bqh7elPuQL=5Qs -zh!wgm>p%KC#(z3xbPVZ4`u}ti=YVJf7A{ -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 -zBi~z!Czw}hrfAqcVXwuUnrfC-E -z_3D49|L9`&|LZE|f4T$bH0wL`f9VU<|MWcS|H}6cw&{k9|MWTb|LT40|IsH{|J5^C -z|JPdjfAo6#zx7P+e|?1YUwxeQAN@W1zx7?}zj_b-Kl&)=v+L{Z|J7qgMXwex{?o^) -z|Laovzw{5R|LT7^|3M$ijR8HJ{tunQ_YCMutp92k^MB1}{ZH4W{-a;=eHgli17Hro -z7Vdw&kp4fti|@JCPuc&kKXUzbF5^G_EA=0Jk@}CWiWsXWGXK|n&h^!MssHMFjQ=!; -z{hxXX=a%aZjQ{l$_W$Y9l4#I>aR2KW5si9g#AIDg|G)l|{vQqczjZR>Km9-Y|8x_+ -z&rWw|{HOET|Eud!|J7E`|I-zD(W)2I|D~JI|EYU2|I;ry|4pB!|4%!3|LY&w|EGsB -z{?nJJ|LY5^|Lc0}|IxqF|DpZt|I-yb|I^Ru|I;U_|LP3tzd9lly}Bl1sUFSuN9bSq -zo^$Qtd*-#B@5R=CG5^yAqhf_FDULzyq5n_6j2P0BSpU=i(f_6YV*IabjgB}FAL9M5 -z>r?;H1F8RN3;jPjkMEb(BRKy-KV|(#&!_&YE$si&?HK=Q7wdmIm*>B3%=r&`0@q*9 -zVg9G5QUBL}Q~%Xl+5fK@`aks-&VSM@?tkrP|EEr5{;$W=|Dmt*{MWOX|La_y|GFvT -zKOLn1Q;%f*Pg|(}>dW;1=nS6!x+CL1-H!T?o*mJym7M>oz4ZU;`t*P6iPV2}3)X-2 -z1@?by8RviK+j-HgmvjD$oACFxNHYJ^ -zLF#|{d-nh9RL=F*kE#FbpPB#b=dAzhGhBcDi2e`Vt~6?OJomp|!uVfL=lQQWjQ@09 -z_Wx-X&wpLO{%@_O|64Do|3~lP{jZNO|JUDe{;O_H|8L4X|MfW5e{?&}|Im$@|LKM! -zVy6B~|EKPniB^4+bNY2P>;L*P*Iz&8{1+Xh|3ly5`LA~t#5|ow{Z~sl|3|N8{;xOC -z|E+IDbnC&K|D^-0|LYyB|0@Sr_2}O@$6Xh5{-3Vo{4d>*`M(yk|65HpDxu>PxC)BmgQF#gvU -zx&C@F-#4QRGciW*r~a$2vi_%KTz}2t{8wGc_+S4(|A%hG`(LNi|DiS1|MhFWpF!&x -z|Larq|7&h>G-?gsYoTq_|FwkqpMJ^xuS4|zYboo0dI;BFZ)N|NUd{JlYY*dp9Y_67 -zpQZm_@8tUHEv*0Pja+~I9p}I5T6FL7`Z{+^h^CFh$eeD0x4A);b;`y%!(f_3lod2fTtpDq4Wig=NF#p#h -z=>O2YnE&fhtpDlH)PMCP)_;}n<6NWvh=||fOvZo7!pPURSpV0(IsaKpsQ>CQod2XJ -zaQ?Ucm-)XgVEs=w=lmbNjr(7J%le;wME{2#R1kH#1J8f`fcmd)O#g@ef%>mLMg313 -zng8qMtpDiWIR8VB<^8W$aQ>_QoBe;xAp8HdZbZbv_%i1|Yc}7Lq^B|d(+$}Fsddc%^e*;)=^3p5=q8m> -zt^2Y5r<>9Lt><$6_0s&P)oqGnylz1MpH?#dOTW(eU*D$wqqlMY>#o%QbQa@3?V$dv -zFGNhy59t5UWvu_{rriJfIO9LPo%>%muZ$Mmjqj1t=UD&Io!S4V|Dyj-|Hk^i{)YZv -zJ)84C^cTi|x(?%ieUbXVW~l$`{Uf7O_viVqZ}a}w$LRmjgSh^>F89BlO#MeM=l<8b -z>HpDPsQ>EksQ>80^#AFZe1EpKasH!bnE&fkzNbhph#1hf+5e%1jQ{l(&VSHiKPKq^xc_xs=Knf{^I!B|^ndH!)PMDwvY4y|-2eI( -z{olHn`d|7v*I)0W{-?_`FPp<3GKU^Z)d7>OVS#@AcEuIsZ{_tBh`4i}9cKGyl`A82{=1h0&wi -zu>Pxea{ue6^#ABE{hvC>{9goDU#eV_hs-H`Pk -zoy`1Ck7fL)+wuO_Y1Du8c>2Hf8tQ-gU;01v-_(D#i08jP%l?1egYm!a%K7g)f%D(> -z3iki%ww(W~n^XVQ9LE28QN#?rfc_7i!uLPuboT!zx&QTI_W$St-v22x{?`+8Vs4V} -zf6$Yu|7aiAUmxQ7>k-s{bvffd{gV2h&g1+a{gm}zeVy~4^={UGbPo5wma+b?H?sdj -zOZk3SeVYCMx`gYmh17rb-^~B@XzqXQW&ej>!u8k7*#D~=bN;jL!~L&|vty0^oBRJz -z4ElfdPkgVBmeK#MTQdLCrSyMl6ZJpckou3l#{I9A)PM9&>VMiw{a63N{jb|_{*N{= -z|I=~w|LYv)|N0!)UmxfBuTz=->1-ZP`V{N``Y7i=Xcp%`=+*Rp>Y1$n>j%vLbTRk8 -zmhpX!dN}>x+RFNmPUm~=wVC;!e!%=+3yY#nx1#>5FEIYsQSATG*V+G}tEvC$1C0N4 -zXX-y%K>bJGVgHX7bN;t3Vf{z58UO3{)c>_>RP^Zc)c^Fvyy(>y&VSTXsQ+m@?|=caf8BxcpRVHkKiz}zzgDpRtBdLX*Hd}_>q+eY(G`5(kKV@oU(aO!uTJ6p -zuVu{tbt(0KozDIb{R`J$AEN(LbJ+i(t?d8T?Ro#}y`2B43#tF_2% -zY3%>g-?0BzuciM}kD&gef8zYFWJ&bs_00cuKl(rQ9p?XfT2b_A9{s=i9OwV*x2*r` -zdR%`!fc}52XZ=q<=KOa(uQ-PE!%?wXkEZ`8{halGy^HnV$^LcJfAlM^zg`(pq`Ptb -zbrk!5brt=8dN1cc>Q}7)=&`vmR)0(Xr`{4VPLJUHXZ?u!k9O1luj^LC1f4_uU(cui -zOE2O4AAOnrKRuE9fBHH7pZXf_e?6D^zdk_!zy6*1zm{HpTJ82{_h -zjQ{i_#(!GC_1E3l|Dn&(|D&y}|LHEA|Eurk#$lJN${*zRjH51ke%-->xayMjHNX6F -zY0r$j!RywIxMWHGQP2C!|Np;!d6-&G{K5$0|NGZ3cNXzqnhh%le&Jtt((4&K@W_2B -z^X!jif4H(I5T&9&y%l>MbXhrv&E`zX6U{B=NZG%2^Gx&5&-~y{ -zn)jo*)jW{0|5wdz=Dw6Co7>GjDf@rj++prcd8)b7+?jHdxy#(1@-%a|xiw|~(V7>T -zTT-5G?lCu|>_2LAuemYh8RkB7eail$H}{)sQ)coL%>(A@lv~Y%=1j`7%|qr$xy?Lm -z9{S18KgS%b@UI+5x!uf4DW5;(x#o=s -z%Uow}NqK>}-rSUOx4FUGnDRn1BTPPj%8SfAsrmdVFE%%st5fbVH=8plFEO{6BV~VU -zn`fGbxKn<)bE&!2Jdm=#)y-|@zLb}l+s!>G`&-}KVeU?Oxw+Haneu?S%j})_%bhFC -z-R9Pmy)?~>%q=OeGWVF9Qub0c_nI41UTy9(*Qe~IYwkDKro6^HV6IL%_^-`_=1j`D -z<{@*WoNpdB5B<-7z9Mr_;afS7a>kr*?n}AC%s0pI`BSbkSDCw09%HUHccxrzt}(Z# -z%;GcG-`tvVjk(U;lJYony}2pnT62TBF=aNpasAEpDc6~&m}^s>U~V#3r(ADtHfK_v -zXl^k_$_?h3=Aj?`{FBVB=7E$O&28qslqZ|p%{?hkF?X1|Q)ZIQ^*48>++^-Dx2HVK -z+-+`6x!JtP+>-KibC0J5%m7*O=Q=o^Pf@ -zoX?+fmzfn^K7Yy!%=PA`l)KGTF!}r`FElrr>r-B2o?@;|d9k_4T%B@{x!Igad5O8j -z94YsjXPSqG{rpSKt>%H0`^;_TzLb}l+s!>G_nSM+-6=0OcbYp>9x!*A+f!a)?l!lk -zJZN5IZb^BSxyRg;@{qaL+?euebDz0B`PYbBDP*<*DXQb7#s;<}P!4%G1o<=GK&(&5O(} -zDNi@|n43~=G54AqQ=Vb&GuNj))7)>aO?j4iz+9bjt9j6zNqM$;$Q&uRnTO3o-=_QD -z9PIF2IgoO@nU#4yf68;sbm;NTVnY&Y-XRbDPrrc>}=E>(zdA^wr2tI$xUFJG- -zOUet(_2#COyUh*e#*`PD8_o48FEVpNAD=(v#pWh+b;>>FW^*RxCFT}$q}*$sX&zdg -z?tgQuc_8IJbDOy@dr%FE52=FXG{%w6X8lvkL$&8;a9nirW{QeI{5 -zF*l_=WbQRLro7tRXRc3q*xYZfO?i!Zz+9bjaBDXYnlmZqnupAha=v-kJoHVv|II;# -zf8{{R8FRk5FXaj|EA4##l&j2D=I)fon5)g5DOa0o%(Nby8q3s -z=7E$O&28qslqZ|p%{?hkF?X1|Q=V$>Gu+vNx!JtP+>$ayCa%A^ -zDdiS(uemYh8RkB7eabV<{pQ+~XPF1g)hV}{2hEw3XPbx2k#d`P*gW)Ay8q48_W1lM -zx0~tc6t~Ix&+-0WX&gV~gfw|t? -zlybMZ!Q7bgLUW_JKIKK`DdyUg7n_^R)hYLwo6VV&mzZ13k#etjrg>;6-T&rR^FYdd -z<~DO*%FE2{=AM-M%^l|Ml$V=3&7CO^n7hpFDX%bhn_E*JG%qr@q)f4d>u+vKdC1&r -zZcKT#xzAjm^02wzT$}P5^MJWJ<>1lYJZR3OoNFF3N6Pu;Ve`HarIK6xPJj5*)j -zmvV(UW9~`0%1oy`pFia>=4x|i%GKr?b9>5T&9&y%lxxg&=9ZMlnd{9>Dc71C%#A6J -zH`AHQ=TEuLOl6+WpE6%=%=I@{r(AEgfUz=@@DX++%J^xy9UTZcKTG -zxzAjm@=SBTxi)2*lezxp>Xci}gXT=iv&}>1NV&~CY##bN-T&rbhxf{Xl-tdmjKk+o -zd9ImnpyuJ5%m7*O=Q=o^NI+H=jS{E_0o^CFKR?dUI3C-R1^! -zW6BH7jpq847nxZB<@)C24Ia2O5&omFMO839H)jW`LpSjK4 -zm+~@mySXRjeshPpJLTo(PIG6<1LiJsd&(=!-R9Pm2hEGjEh$sH=K7nPQXVq*nj2GI -zZSFJIr#x)#H`k`T#ynuIPC0nBHxHUKDd(Dp%#m`wdDuMkS-StttnBdlQ_h$<0f5h+ -zGKX$({mnfoSDCBK-6@YTSDQOit~PVxGM_)?vF2KHYsxj|I&(|PG$C;P%}puSnj6fG -zDUUZdn(I@pGfy$sraZyiWUfxR-rQ`?q&(5wVvdv>%rnhHpQiiY+-e?3xzXHa?n{}b -zQLewaC*>*T4s&UH+QDoWbQJzr##KvZEj7u*}TZylJazOkGU!37IUw;G36QN -zK68D_GtK?x+LULR2h7zex0(mdnUrUnhs=?3n|atgv@+fQ=3s~S%7K*I&H3iOl;@f= -z=AM*0%vI*@l;@e*;mqexxzo(aUwr+ -zW^On4q}*@rFn6cC+}vsIOnJcEWo}P-g}K|@n)0A|k+~)1RpuUZQ_4f;UUOs0tId7p -z`jm&w{pQ+~*O&*))hP!wDQC?2=Dw6G%yhEw -z`BSbkSDCw0<}hlmzqvEzYIBXbJ>{|HT61g4HRd{VOUg9aasACrDc71C%#A726w38C -z*QZ=(o?@;|d4jpgT%B^gx!Igad7`<+94R-L>5%2~f1K`rbE|nE~;Qx!2s7@(gpIxjyBY -z=6-W+%CpP^=IWGN&4cDl%CpTw=195CJZv8NZ@T}@!499511YzgIgyLcpYmLD#@v%~ -zhnbVV`1~o)Ggq5CQ|>g^nA=mHZ>}}Brrc#_CmWwXu+vKxy9UTZcKTGxzAjm@=SBTxi;ll -z<^gkc%B|)>b0+24<{@*W+-4p&4}FmCe=|Gk`TQxjoAb?mDbF?YjU9aclsn8-=I)f| -znXAp6DR-Lr23|gY%Ja>&=GK(E%ys6Lloy!m%}ptHoB76FK7Yy!&5h>zloy$&m}^sB -zY;H1Fr`%(v5yc=I)f2 -zn>)>&DG!*t%%G_gaN_oiKYi>+=wYkq+pYpJ|-&~vW8uNg; -zI^|$$*F0#>q?~IWGDph!=3(>D`+oi+b7aT^DQC?2=Dw6G%o%e}%2nnnb9c&YKIHnF -zJ5#PU(*eQfPkF4l*4&zMjhU0=`1~nz2sqc@+>~;yxxw6+@_2KjxjyAO^AvM!$}~fB -z{ms=W*PCrvSeZ$AqM4mM|Bs_Ph>|7j19M)ByXeKYDCb;soQp~_Njk|*Qi+?SliVbg -zUEl)_^%d@MpjY^a`~R2u -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 -zPN#T0tP@dvU;_{(yTN -z=n+2R{$F7JAK)M!-02XHaH~J!5I1^^$GFy?aD*!z;R!DF36620CwPi;{TU}X(=ndm -zRDZ!KPV^Mdajd`M3`aV_JUH-^P=CWY4)hE!asSW%beR8#xWJuG@d~&4J1%jf=Xi~4 -zeTpkw=?rghsn2kY3%$Twoa=Mk;7sRuhf{rlTb$@6-s4zb;tof;zy}=aE8OEiukaD~ -z{~YuG2nWA(aHmT=!mYl>A#U^)s_$`% -z6TQWA9P0<1;Yc@lfkXX>a~$X$UgG|S`G1TH-02ptaI2qii5tDgYh3GRT;WQ0c!Nv* -zf@@sp1K#3Xzv2dGy2m@5>NnitL?7`U$NC+2IMTt-7<|B?{(yTN=n+2R{-0(3AK>7Z -z4eoS^N4V7=afll|#$#OTPdLJrj_?GR`UJ`e=9O@6a$AKQXSl|NUf?ax^*L^ErgOZ*slLE1PV^G*ajY+K -zha+9!0}k~S?s1@3_=x*|!v1ma%LjM5#3S75YaHT6ukjey`UXe1(iNWIQs3ej7kY!I -zIM;VL!I`e{45#`Yr#R7DJjbzqz!{EogBLi|k2uGH-r*(guk9ZfxYI3O;Z{H45;uB} -z*SOZtxWbk0@CKLq1=qOH2fW3(e#H&WbdPs9)o-}Pi9X^zj`ch4aHNCbXwTw+L;V5w -zIM5?}#Qi^R|2X&+gF7AK5pMNI9O6cg@fg?o6OM4DBRs*SKEW|A^aM|Fu0P`hXFA3+ -zoa!$)#fhHcIga&LoZ(0(c!5Lx4d*z}GrYw8KW6{9z@1L<3b*<@E^(vhc#Ug)iYr{{ -z3~z9$&v1vP=TOy_uqQ+NnitL?7`U$NC+2IMTszv})n9Om6FtRq9P6(*!;wxf4-Eb! -z)ZcK913kk_-2Yko#|7?midVSR-*Jf>J;!TY>r-6eN@sY3OMQlGT<8Vf;#{BO24_0Q -zJDlnZ+~Pzp@gB$e5_dS#1wPj#|SNH=(aL;Z+z9OxZh;{HeW -zj|<%C7O!xtpKysAy~k@@>t|fyN_TjJOZ|dtT<8Pd;#|Mt24}j*JDln_+~PzZ@gB$e -z9d|g=!Em&1aloPefO{P15kBJnAF_WO{OZA-4)F-L`Xdf;qsMrRYyAmFxY7}x;8LI9 -z7#Dhir#RQ2ae^});~7r%7o6fmPw^bb`YXUEl)_ -z^%d@MpjY^a`+vaxaqw#fce=zQ-0Eu_;zqCW7}xp+N4U}zp5Rj7;usftgQqyxcR0bB -zuJH_~`W~k^(OW#nv3|fAj&y?;IMk0g$ARAACGJ=Dj|<%C7O!xtpKysAy~k@@>t|fy -zN_TjJOZ|dtT<8Pd;#|Mt24}j*JDln_+~PzZ@gB$e9d|g=!Em&5aloPefO{P15kBJn -z@3(&(d>!2B5RY)HKjIKKdW^@o)}L^MD;?npF7*kHaiJ%8igW!LCpgnFp5at~!6{Dk -z6wh(2zv2u>I>8GZ>Tfv5fu7+d?*Bgf#|7?midVSR-*Jf>J;!TY>r-6eN@sY3OMQlG -zT<8Vf;#{BO24_0QJDlnZ+~Pzp@gB$e5_dS#1wPj#|SNH=(a -zL;Z+z9OxZh;{MA1ae+JC;uUW76E1P1_jrwK{fsMI=?-sjsb6r73w^*_oa; -zhg1EATb$@4-s4!m;|@nU7>@QX4mi{waE}8$!bjZyJ@$`-UpKhZAs*pYf5ahf^catE -ztv}%iS31HITWI6DW2n4f5jP&bb=Q+)ZcK913kk_ -z-2dJ7j|<%C6t8frzvB`&dXCq))~C3_mCo=6m--CXxX=r{#koGm4bF6qcR1A-xW$QH -z;ysS_CGK#f3w*$#zQR2Y^a>ww|99Cx4u1XMPM3IuTYZf~+~_qP<67U~2v@qo6I|+B -z9OFW7@D%6z4ktL%HJ;&A-{TY~dW+{c)(<$tk#6t;hx!rcIM6%1#C>7^xWJum@d~&4 -z375Fhd%VWAe#RB9bcZ*%)GxTkg+Aad&h;y9aHe~_!>NA5El%_i?{Tc(afc%v3`e^c -z2OR1TxW|DW;Un(Z&DyvMP=#2t=wfe$#;SGdQ4 -zUg0C||90m85e|OC;7*r#gj;=$L)_>!9^+cy;0RZ`!V_HTTO8v;Z}1f7`VJ>J(>0#q -zRNvziCwhzLIMxq1!;x{Q>tl&?9`r{ols? -zKfu9n9Ng&;k8rC$;t)4_jK{dvpKydL9pMQs^$Ct~p(l8XbNv}7IMXqn;Z%RYDNghh -z&vC53;tWSR!3!MfZ#c(+p5Z0#|5p3Q1@3f;SGd*Rafur}$7@{cQ(WOnXLy54eTHjX -z=mp;5T%Y3xXFA6_oazhQ;zTd;9>@9;cR11oKHyMa;T{Kig^#%ZTkIbPziDu%OFY7@ -zzQ!SL^cs(Gt#5FID_!9UF7+*raiKSOigSI36P)Q9&v2^maf%bY#d93%2b|$ZH+X?V -z{fKiM=pA0-erf->z@2XK3b*JPZbfga%_?*C@{$HBM3oeuE`xB4Rvaihn0jBEV~ -zN4U}vp5RiS;20Nrf~PpwpK*dS9pf2J^%tDtL{IS?$NDSIaHJEwz@h$za~$XyUgG|5 -zvVUCQPN#T>n4n(=A@%RzKkq -zH+qlPxYp0O!jyYki6< -zT-c!yJcfm@vDCEnv$U*Zl&y1)k<>MPviK(Fu-_kW%J -zD#W61Q22XLW?{I=MUE>)}^*v5;qPKXC -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 -zRNvziCwhzLIMxq1!;x -zvca7W@d&s2BMxz+$9Rlu{Rv07(h;8EQlH=$7kYxHIM<(Xf-@cC8BX;VoZ>`J@f^qc -zE6#AF6THBo{)TfL=owz({@49vP=TOy_uqQ+E_Yh369-r`)p;s$5B -z$2*+rH{9YxAMqZ?`W<&T(!nnse88dpfO{P15kBJn*D(JNaPTJwcRIu)-0F`w#El-~ -zF|PF|9N|hwc!EoPf@56h37+Cyf5r*Ubc|;>)n9Om6FtRq9P6(*!;wz#0*Cq=&T*h; -zc!~R8ZU4ByolfxzxB5FSaiiyWjca|1D_rReZ*Zy4aE%MSz+0T_bKKxe=Xi%xeSuq? -z=q29cSYP4}N4mfV9O^6F<3O+Q5%<5!{&Dc926wu|Bi!n19O6c=@fg?o21mHk6`tTy -z-{Ke-dV{Ap*LOIE_Yh369-r`)p;s$5B$2*+rH{9YxAMqZ?`W<&T(!nnq -ze88dpfO{P15kBJnSK2=g&IWfn#3S75k2u7Q9^)~t^(P$RN=JBtOMQZ4T<8g&;#_~m -z3C?tkXE@bgaEcQ>#d93%uQT4Y0Mz8T0*ZKxWxY8A#;8Ne>7#Dhjr#RPlIKi2&@eHT>9;Z0b -z|37Kp0%v2@{XZBCO_?%9A(TW^Lx@sMm~yQl6Dma!q8b@euBT&S9H*v+bdjbIlA;h% -z4I?B)axJ}0r5uL0srV&i{@?G~m*;ZMq|f`W&&QngJZr7JF5kWP+WXn(IV(x`CY>Vm -z8q)np*Au#c^kC9SLa!&CNjgsGO{7PYE@>hCpY%l1MM7^QJ%#i(p?8qZC0!u&9?~z8 -zULy29()pzGg)Sn!fOM|V`$;b$JyGZg>6N52g+5HWfOJ2hOGs}boi6lI(%VR<3VodP -z9?~g7pCVmEx}MN+*MN?YP7*qvbP4G=p%X|SCtY%l^ncQE4}vZdI*D`w>1{$MlTIRC -zAaqUAHAycKx;E*0r1OQYN4gQ|T%j9~P9Z%}=tiVllg<>nDd|+w{e(^--H~*<&@D)( -zlTH=7HR;}@Q-p3yx*zF!LZ^}*Ogc&E4x}?l#|hn$^k~v0&87d7o=Cb#=ycLkNN*Fm -zC+S?$1w!{G{UYflLf=C=pLD*^{YWn$oh$SJ(o0BB6nZe}m83I;9!9!=bU&dpNpB*Z -zE_4>@ZKP9$9!+`==@g;Ik}e`$Pw0uHBczjro9|3li-gW4 -zoj`h<(9=mLkuDJWMbb4%FA;hc>3XE|h0Z74h;**db4jO=o+$JJ(yd8n3jH?eRMP!~ -zUP8Jf>2#r&kxnO_D)dUyy-BACy@qr@()ENcAU&9LlF;i(XOfN+dK2l?N$zR*Ra7m&^sdOztUq$dg;A-$4xrqG8; -z7m)5JbP4HAq|=2yN_rdVRH2WP-a|S?=u@PNNY@iOt_A1_=_H}!Ntck06FPzPandDM -zOaCX0|KY#TNu(1?eX$CYu6sETW-@=$444Pp|Mo-85DJB5Km=a75^OO_aftzzNbWAEv0Yb -zYU+y{*&q~L1OL$eIicVlIFS?IAhP(6($WZ*0ULtkDyJ-^VPSrcO6x;K0sB6$F8+n` -zn(l|1?OErCg40il!n4A1P23U<2QP!lQ0)eVx$rMit3t)Nz}jgL4+VCdrbM+F1=Us* -z^ev?K2wCJSum=hs0!QR?u@MZD3bM`)r6thHjVnq^iz}|AJ<32M_mappr(9kPxvk^N -zkn1mUC(eUKX-NoTLMSbfvDEDiy0^5{HWbQ8#O0D|Ym;)eiN*Rtxg?>2hm&wS6ql2B -zihn^QmRm-6EzQ|Ly9ucl4I)2nLXOcw=ItlA4UKJh1p58KOrZ32i#$Rv$x^Hz}J%* -zp|t(Y3c}gjkR58v+*Mk-5$ULhTP9DZdg2}c8xCgwagv|n9sVM8lW_Jv>YYKQ#;wus -zDYxWSPIesBhqH@>jh_wMT67_LAI#I5L%~FC$(=(WGJ_(9xx;d_l9vTsnJewS08j9> -zDA|i3>*cIT&g}hB2IS8Y0}j?gwA6h@Vd`#NEr`#_ju*QRix@wfhKFdeAV%SEHt$pH -z4kMNzVy8rmpN&{^EmlFqc%NdmA(oR(zr)$)T7prPB$tnhDhZ9o+T`bT0t9is11AQKUCOJU83?C4WkI;o&q_BsiP3Ho?ZR3f&!Q}lvS#9K;{ -z5eaEU?bv!y0L6jWLa%r;Z6jD{cO7XUA`Q5)+tM_^TdDyga)oZ-E!63Ai|Ki%SmH(h~)g0Q&N1Lx-Qv4!zUlo -z*DuLgo3pLBw)}g6{F@~IR+WF_`ESnFoDIeCN?tl2Oh5@NTa^1*AS&kPJz-rX)yqx3=Gc@E`7aa -zzDA5`uRUP^=bJe--Hr1p^5dqph&?$t7`>y -zasj+g0&FzVHOHy>Ir0A(zj;;c{G7V#ALi%wV@P?V3ukjYJPqc4{Rg| -z!q)#sO2`cSCT0}Z{Cq3!xaQ|6xT~Q2F)CM|?J_?f1}-99k4gR$ssPLNFtM=!(eP`v -zNW+iUbFv%Z-*7fp&!HLoY}h7DQ*1G2(B%6eGJ_(9x%@j2_spPi8;n}!WV?(<(jcg; -zA27CYP*Yk5YyMw-dE3apBZVS&4UXBSf -z4O;e;4m+7#26YvKOl2KCkr-yjBkVGZi3uV2RNX_LY; -zgi)-KTiTk2+M2XUE>qTCD>BT+FBllY*+yAMvBNZZo!C)Z+0jq8w|pA}f_tqU_vq`d -z@_O2|@C;!TJLHzOV|GAAC2g9^jy7V)G}>{m*kP0vd`GKHlkbsI!|}$w>Z8>0Ilr4a -zetku`qO{W>ZEi;Xp5WfaJdfv8y -zzTP%sg8c-zlo|>6RGb1(q>S`kKGQnT!n1&^d%85WQfj2$e>s4zDre{Vo&aZ=Yw=!L -zf-F1N*GOfKWfEUAT{RIk*9WiBXcV@Qs5kXo|KX>w*IA3-jXTPGsRU->uA02IBa?39 -z&01XM`hG`f|6g%2=K9WaRKrpOls(tyO;T(z=K4l=!C22+f5Dru#WU9@e+(Ww`~Gq- -zsd^e0Q}zNo(R2M;F!|^DzFlrh&gXl+CY{r{Wgj$Q=4J~9G{_s{il=MVbo$JRV1$wj%&frJsA+0gS+PS`wPSOYrPT}D9b_QvnuiwqMcnbts~L(!%}zh-XKtRu7{M2Q$M2Py65_) -z`ub*Gmr>Ya5(dd#ZP2DCwLvnDI0o_glQVul)q<4Kx*uhrgWp}C>|Bpbi9y}Ppr34n -zATQV3h(TGP!ZU_ULDRhTG#C)W!hc_DwI}F -zRUsX9!&i$zP8HHYU$4RItcHY9tdU#Vnwr`gPc`)ZRU$)p>}k%Hjk4>+4%1{)v7>>q -zBVD&Qeg&()I;$aJ6g%XWwj+16ii)QiY9e;XjK}BI;cTPqy&a@XlXFR_ -zYG~Cq^--#!6l+9JZNx(eudeN+meNuc7VvU!FuAIs8;isucQtg6R#W{}wt{MiA}C!@ -z4fRu>Pz?za{d20J_g84=VpKx`Y5GG`U<-ZaQ!Ch7UwNN`{`%`G -zE7(@EO|ycg=R8S4PyKZqy-vAfFn*_%GC1!*DNp^i&Po|X*0WOSy7hB-#i_qun+MXV -zzm{M*sY(s0zlLK|K$&5ZTDKPy!tFCBwX3nRQCudyf8A-+$gp3vnIWbA`ur2E1F)#J -zgM)^%)#B7&`TIGkwK>j7Er|%)G5;Uxuia|X$<|*pTM<=KShWqQCZg)E3Rh_S3)``6 -zl#mMRx;3!ZslUF(9TgP0TN`&(LD2&ca~toezlyM*5GZ`&&xGi`md!7zhR;xcRoAm< -zjQVQ<(rM?qcj2r- -zTDLVYiF{yVz!L>t3ntq{j2)xGbujZ_1CTU(Or%X-Y{*QszWaW -zhi9*4E{Annj*QA9m7?P{_2*atzy1fx>5wMb}>ieWAs(*K+y-bp?Q~ -zFpVFjhphabNaAx^?6sKjJx|uoxK(_SgzuAUG5047$kSKK_6u52#xg` -zbh{WN7h%wFj1W$l@%0u`rtMEbh0=8Wh3+VkNEL&ea;K}l-iX&(?g*n;Be%3QjkPtN -za%cTzBEw7_Y|NI8vMy-ZDKl;WWy>y1t76AWuDx94PEUP3pVwLL2&32`x3nFvKdPeQ -zDRvI!Rqkw-qKXd_@DSJ8{JBRPF=hnigpxJ9mP&q&m-~Uq -zRqou5b%1a4XMk4I;6^rxa)%lbV1Vw5}QR4KdMS)%Ug9g1hL -zoJ6b4${llQura41QtNDm&EHJQczp173Q12t%@C?`r*I_(;pOgf=eNo5q~zdBzN+OA -zx~-aETWH@qLcO}uT3=~}D^XR;QY+Y2vsJT#repp683g@R%V;auK@08zn`+T?fb|sg -zR4whSl!0o#l`=i#8A^GomP9LMfc21-GT`dXD^AsNa280XYB{l9+otle`VC{M$<2`4 -z7*|!b2wIT6inbAxrS{-b^SorLXCp((oOS*OS_fqN0PF6F-&8IAB8R@^R1o|%dMa3s -z%E>zw{E?)tK;iLhC=9kejV5HYew+Aek4Z-g@V9|(H^qAzY^ -zH`m^PR=8b{7lgGxSe1w3Qai9qSkTzh0EXKo{miglq^5YZ^uOW}&FVVaRfkoZv=}pB -zIIYC>DCzTs+PuTzj1sej+HjG%NF9SOLCYJ$!Q*;zbDnrybuI2>scqNa(UNyth3`)c -zryZt>8Ne9Y%bmO(S8P~_2F(?a=JE1FwWdv$r&y_QOQ|v?tP)|L5QYZolh&b@Z1D7~>s-==obfs9!f9)a0mIA=zUaMp3=GJyH}6ZKJ!@#s -z+$pLRsf!as89Y}cN0Rhpu+BIldKy~mMR*W|UDhYKtZ!SE^wmu@+WL1U -zYMe-`{C!xL^{-=rqpkmC@;_VOJ3%i}MbF?RCiY_eLI}I8?~J=9_Tx7yy}oC^>5(L{ -zeqph-zC{e{OD4Fje*?Q1F6)0{fvIBO=nU5X*UUL${af#PtS^4rWBoMTHP#nkc8bx9 -z(<420Gxo)Yto5TBN5{Uo$NK%FJ=S05SpN_Vkb#M(%VHpB(pm1xTYZ|Jpt(3Lj!Z*#2WzD60=Uv#$H`m4OwKMG+Na*|xu -zclcE4jY7^YY)AzPA3bPef8z3J>sO3(TR-@5PwW?BAkxVB@1%dWe#tp*>oZaFsF6`{ -zzZAkQ>wDm?iT%@*vH#$lkLqXF*1eI -zBE0j-Q#3io0pLm1pkAqB7<47zQyyc1IK}>NjBuvF!6U&dWhv>txoCqEpxgDDh -zfx^howvefg6a-7k;b3iBoIS;S5f|zA95kUWX?sjPvE~WjEvQIB!T7&%2Md}|Z~!Y} -zRB61IG>5GvGt!@4Qd;^kbi_g5B%1AcJnwlfY`WR(BChi5~{<8->Q0KjKP@9!N -z=$u@A@A~s`uN=;EiQZS|^B7`Q4b+Ya}vPctvBN@ssSFZisyx^ -zR%@V$vLqnA+6tOjSF1lwAQi-`vQsv~rgca2XX(we+cDnpqg17PsPJLjwsowGDr3UD -zGT&w0OLyr;6L5B}HiHt**aM4ds@X6(oG~9%QYeF!ZHx(Il}WznFTQ~KrE$)$+OnVJ -z;}V**84SgJafr|p#-r6Gj5)_~J`pe%Rr!vpd5~8a60cvdq^Nuxj0RFeKhcnq<8=1S -zbMWxk$jPn5)byV$rncSy&%KyRd={#Fm>S)(Y)q{|VW^Wcyk41@YJ~~{{lkr^IqC4I -z3``w3PlBQKcA6IpQ^7|?rNvYpx-!Fi5|fb!Q{SxA=@m?^L6zgh)LXdX#Z>Ft(Y(Rb -zNpyWLrY^*7FQzUJ@roN$X}xu$|0AZ_doVRKnfe7&voP~&Og$$b1puSK5RIw)b0v%( -zOm%fsb%(qQQ|&A%DlY}2!BmZp%EZ+CFNmqsA1tPZz6sC0m|8h48dD9fDH~IRxsp=j -zNu7(!#MFgtC@rNz|u9IAn-%Wv>u>gg3ay@Dy$ -zKVD4Ti7Q@A?eB`_4W{N}+2F<0r?~CK)Yn+Ecro=`hHmtK#MEj`qB2Rz;L;v_Ok=7e -zS6%Ay!wvFL0B{LAVbnO)wVH&{gQ?@dnO5~TdZ7zboL?0wDz}2sV5;!LGBI_>=fu?E -z|5!|2-Ugm~F*RUnG^Vztl#Qw6Sr${D)hZKH&!DsWFmxZ=fBZf7)aFm(qO6kbdX$89gBCSWz= -z#nh{J=tloXOr?1+^((-kfpC;78ilEY@=*ZrCD9XwspE+fMh~XuI;s{z-i4``Eh#F; -zfYD&;(UoOlsub(|K;et~ET#%yhv!~QC85jt=f1I5m5r%_mn^16URWlku0v<{VQPLS -zcvJ?aiqDc@XiRm(P#BG=$%93u#niPJbBU=5t$mpK&r+RU!BoLxeoVcCD_%^s?TF?L -zrb_j|;M7xfaNCQiCK!gjnCjGBH~K$f>Z9}ATTJDTvY4779|ZtUf*~4HbE`@i -zJ(x;&RAoTkg{fOCDJm}qqrp_I6=h;-(FS6w!#5UF6I#G?FQ(R@B=uveQPZ+9HEgEE -zRQ(!dV(J&n)jmw!aVtD315-1rNH8>}{(2=ArmlHVR9Z~6AFeR9=n)^LroOAwE0`LV -z>BrPvxZ=fBBn{0QOf5pWKtp!IsBtPiLBi<4)G6Rht11V17p8v40PmXnz6PVg)W-MA#8j{K#8k;{ -zi>X?#!gDXC24ivV$JCC-Wn-%542!8RlFP)@^XTk8OqF(k3uR!cePs!T#?(9vh0){G -z_Ya6li>YTZ=5n0ceT@%OtrqL_3Z`lTa^AVG60UeLHN8EWH<;>$a?6XUk+|)}R8Ur6 -zZcM$7n(O}uQ=ga(6sf2F05~)dj-%`7x$lU46ijU=dZI9Os-lF^gQ*3Ms>P6ZVQRJ| -zMdbuA8cdB?S|+9{tRtpo?X;NMeKkDyVk#M3&X1{ymzRyH_0L;OJ%K{8jJ<>#(b;{N -zTGS36m4T^W<0TjxQ{6EXMq?_}UsPI5y)sN;s=`A)O#S$lPOo5U{ZK!q-oq6yruhC+ -zi>V4Ix4f9DkK0~MU5#PbJ5F`$tQ-9w$Ei*pOubf#`eofW_fcgIde2MpQ2;O=4AGcc -zP(i}z!BkI2RUgQ^FxA_aAgpJ%Ykq@cy -z>XYp9bi$a64LkL$Mz(jh-Y3xsr|oxLya=5a7{Nsj4bxKLX9hP1<(u!&&a1oX(|cj~ -zygWZfcy%KBjy`Vn^AJ~hlX&xMT(RjD_Wn1)Z+t6V9zfac$KnTd^ATGs}y!8Xza -zLr*wuH>Mr#xy8Aj96q9Ql~Xc>M+ZDFEVvi9iaVk|DVuA+W)*QUWD{Y2KJN6Q5F-W^PuFN}J4 -z_a)_m%3zJxh$aMK}6C_UMPJxvSYP -z1ijLuw`2U#v&2UEDBbUELM3XJ*j0L(Vf6IqryNz2A@AzZqb(^a`+(8(=x&Rmd$eGx -zZRESv#MG#*7E`ZJhv(i|g6nxdrtU)DENjPk_B5y%mmD|pLcQ}FMxDUK>}&#|)Rdew -zyl5kV7xu@|Fm*sFZ6B{}mq~pedL`ZlBHyFatQX4oCp_Z;FMTx+{g`4WAE1f4xr=pk -z52CqhD^e3Mom5`QjctwBDYrnkwBJ*UuYvf6)GFolAtilx6lz+n^79v=f1|#BF{RRW -zU_-tElt%8;ZSy!c9OL;fymf@nGw{li9rPq;tlEli2~=o>Pf{TaUv~xm>azqZ;Cpck -zju7JJOa!Mm30ub4#2<>mBj>bhta$4UT#&IMbD=~dxV|mFNsX;vJ`K^?EnUUzzW9aB -z?$?(`Wj6`n_h)x(UFa<1c|yTdo!x}U3=UW}nZ5ea5O*>wVu3|xqLNt~Q-bz#DL}5{ -z`a%%u5R==IXps)o(gEt?h4-H+nZ2}lHHagbh_oE^*UEwsc&iV^B^AGQ@5ZT)VZinl_t4alyZ{09I#{C -zXHM?wM4Q}g7!YZAP1tCXn+V@s$vtw)N$y(oT2FH0Uc&`R?uL23L&=aR=JE|G0A+KQcf}>C?Nh_GM~m-53TS4 -zDuj)nQ&{)Zo8Y@Ene|RO$vlc)>q+KM?7EW7zvlRo>Gaf`Wz6Lzn`|z-g`;x$@(5b* -zeTrM@qOx<@IosD$+dQv42>>Uao|^lYzo(AREF-y}4zkI;;)G4^P4_9y^MMkZ+|AFa -zi|3)af9|PqT6{3XqkHNlDA08-9;Zr^+|2-uE4gRsw$I#CZ?0;S+fdv1$feMwlY2jW -zcO|zyf@6l^8W@~B$-VOx$VqZ*zu`-+tEVn{kJ;_8!De?ty{PQ2LDA{YZljuIXLlGT -zA*q-WA~$zoAWVT&p$`pl_td4bGKn$lZt7)|+4s0jX1lRa2f&};rh)0HeTjZt{PeCf -zC9{GSUk&l-o_ap9r{>hERB4j=#TXDyPrVV%{JWl-h%;qc;VL2kHrA)GPUZ~w?n>sU -zKb>TDMz8fGvkmGBmCW1oeaUos>i0{S%hBs?F6ZP#<+22Yr$3kXTu^o{^8>z~`s_2x -zlik3Hr>FjM%->UYU>=KEFx47hlRNSMY;tE{aAu7D?oAVQ;Ogn-2BW!u?x}Zb@sA-M -z-BU*ow8{MfP(Q7@) -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 -zsWJKqkBCqGK41@KhDTv$#O)FdrY= -zkAjDF=i5N>{Id>J)4y5DS^#w^?m)x{M3zEUMMvbHf{+VOBP=Pg+m9`36|ByK5Uk6_ -z#K6z59mnp|YV -zv<(kIb(ofKws?B^zB2Lj8U$Q;ng}69iqZWcs6ur4g9uUiCu87gC90J`VfU&25P9%) -zT%LtkJay_FJqAVN>C$fhGoB*1FeHMBSMTLV!NX(KZJ-9pN5R3q6J_G5KV)5aY7QY6 -zo-Vbd=$Q^ZDp)55AXqy`$G}r)B!kr;#~&;QPyhYUji=m8Ja`Iprvs9jN-h5do|e}7 -zw|M&Va|ch~*05okxX$8f;3kWw&V9?o)9ny&;VA_|Er -z3d>FLhscAc1^Z!)Gd}&5@o(_-b?5&XPcL?0NCZ#aFn?-1U2?7sR1NtkIGA?4Ogxup+8-3Sr#UQ+i5)#nbti$#mN%u!&p7d{>I;+J&d0PYo%Z -zU@Zhyh$ds^i`+jl2A*m@#t<#d_J_!Wr`~vQ;=7JaufxkO-ds?!%A! -zSv73OR)r4KM)@c>Xe*E7W6pPLA?w1^^AJ*`;3;TH(R1{e!P8xsCL=Ag+;~Dc*&uQR -z8wNQ4IfiR=1~DSsm!z|i|YGTkJE`kwks9sL5Y -zdoSo|X{N3;BO6AW(?uUu--Ho@FOI{<%TOzz?C+wT@L?BEq|eR>(}ai{4t^^ -zp^&P)6nl5Nkmsps@b+!Sj-;#ki8$(w7mdm9bO`^Wa)Eq1F}DQQ*VFZ@gvjoe4G_Ej -zeoA2$%)O--i$`^2{E?=Hc_Xyk8=>ANLi;B>5xR2rW@=zUv>gdQ~nEPY;Ma -zv3uO_SkDIvL)a|RAlfy{Mre_=C=u#_C$6qB$=Bmj)brSI-c{3_2)!$x-FT{n9XJ)C -zuYgqlm^4@{DJPZ~Jhe%V#?wHcQse0g)QqkO4Fz{hJpF#D8&CVOspyK+PVO-Zp00;g -z|BR>g*oz1h_8o7dweo!%t#Q5V2>y&WTFboS(~~AzZ-$*{)qKW}rz6-WQ+CY(QvK1o -zPAvI)oLHjq)C8wy{o~WMK&8ghK8D}H(|4#Hy?8pS4j2rc?(Ma7WmPc{@y~e5 -z!fr*N@NBVBhVa2lZM3eG{7CPsix!Bigb -zDbQakMy`26K+oKJ_bom=IFSN -z0CalP_0IC(3K;1MbeD-X&?~xP?c>zh^FgXWKOCdQcxmy~$7%Jy33Q(~8R&bwf&LJq -zvkmlfBw_}71@3qP{WC7O1HFY43Ie?zf1S|y1Kk}PCV|33qimoL9)*}6(bAX%dXz_- -z3iR2c<4w^aIsOg9tSivXWs(%&EQXO-ZH2p)$nWMN8Qcf1J02$Tsesf8b8w>C74qpI -zRme|tkLsYxfN9vs!0+EG1O5fTf0)a-5AeqQDu&tsydsI1alZn0JaO-X3+}l0gq4hY -zSNttI?t8JZfb;(&ZQN(ain}x>aX$^PI@*-mGepN#j*dPR(6j^ayShodXiR+==>qtn -z5fOQ%J-N^kUrc1bQDXxC33x -z84kYvguhN``~c6yrbM8yikK`A>>Vr6(wGE#hDVzUbW_ps=?HO~O(wnT0eE+rwMF|} -z7#R)lkB7Sfz7D&LE`YxeQiYtqcjuddlmUzGqZ1vJ0sjKvac?m0S>CvFJJn?_m~Cv*|Fj-jY-_=c(f_Emx+#Uj*iiB9)LfA -zomV|Q)r65QfY%vf0eTVIwhFAh_`li1|lwX-opW3{#lj?JlBY -zf2IZa)i~|p8c8xSbLy%86&M)}@ZTPE1N;YU?zsTI9i$3*YqT8`;G4165GZ^=8SpOv -zUKiUk;k-%SxYuT=P2B&$*@oBvuj!9Fj}W-y{(Kh|_o?{nM9Lrc8e;O2M=ij|#)`W% -zCUI};(Wc<`HMR}{g~J>jGw~48755i!wE(XMBV7QW1)%ErvN|3jxS|~oQbl_+x`$)G -zYO%kxc;b<;R^J#m^n4TaqcJvz%!9;r$mYS-UIO8 -zcm`T(mtJT)CcqD3QIGe3Jp6Ctek1mY!gib{VM!@+OQ7sy(gj`39iO;0STH(3NY5ra4GR+ThH~%KKeca7U6HkeFEvE@o -z@})2Z&d$P|XwRFf#(E0(k)hVt%`RV0ajrSDuh+!(^)GA!1PY%Q)#7WNsZq`E6rM+% -z<`3YErSWx~yZM;Dz98aPJ54ygE_pqwvBAP!&S@;}pp(}mcVlJebtvqMk=L_D^_ved -zjN)svoT%mxV#yEu3y*Z-x-MUzD@Fe?p^oY6TO!`xX~OY!J*Hq^UdIae`A%auyL@fn -zZmeuy=kWEW(HQ1YotEOZ%PS8+D` -z$GmRu$xsb-ns9tQJUgnfxx#&e)7UDPuU*}ZmF;Ww*uHiW)jtlhzCQePRP&b!&&R?e -zzHY4G`1%Ep{rsb^zuZAzCpb+wzQ#rSx>C5iJB^jNeC_9MtZZMqz`huH?JKJP??LNp -zAUn#}Ho~)Ac*NJz@{X@RoII1SC$LR`^RG@5j<3n6D0~>^Rz;w2pwn2hL(bTgn -z!nQ!5@Cm1}!7g8?xEm|m*VTMwQS{i9Evhee3|SbAYQDeloETtzeH6M(f34zfKIS-l -ziHNTjai6bkUvV`ilkqX^AmIGB!#o6=%PJi94SHV*&qEGRS~SmM;km`(sUOXgBRrQl -zJb%xOYHOhIoPNOKes46-&BF7I!?Qe^r;hNfaCn}J=J^XtdCdO~&%@C?JB8;Fho_U} -z!6SRTbRB1ovM%Li-sB~7G;?QaX=!%BNY9UfIT(oi)t!Dkq&55eSc&4T)Oh6oyD=42EnOs* -z;LVttcmBe;EIwieHh;wsUqHg*o`q&WwHfr#oN5%~iCi&F-;hx7j@* -zzRiZmDz2hY2+{hc{H-=Y3!$N)8YkAECH*!jbJ?*I3Bq93Aks+eT6-Vul1ZW|8WW#4 -zzkEIZ;t2wpiElvMN0vN;Ndvpt8At6SI~gqpUn|SQAiu@tdVSRvYz<)k6Wx*t{fhln -zIEIZyCj;R=^rT}(-1|K_lYh)>y~sV%-m!bFFSK{a?{V;C=%%=GU#{Y(KYs`(UXZgn -zmK!%$)Nb%0wabrq(fg|Cb^F2h3rG3k%Ym|7Lj4i81MvPYrG`o0iVNru!Es09_>SkJ -zymt2U9N*2i0agF!^>4vz`?%A$hltMd+O)jdf9pXHvDGKing*n^>tO}gH>OHX(z -zB0E6J>{dfGF6pa)8cXAKA4k88@`CART2jDDj%@8jZwD(q^q~4dF@zr@d4BHKh5I_w -z>WeT-#(n=QJ>Q9v93+x)PCMW3w(U%Gb1RJS=zO5?t9ugg4UWUKC2=Cz@n}}g?_G>& -znUu6aNkwR6#3e_%U?T+Y|GHb}l4GVsl@`GDudv4R2e_Nyk6&N4wM<3PGFxe(Tqg;csJPg& -zv)862T%VR`<{nTo`pVy=oOBG1ipMq4jy#`t5uL?*;M!WGPS7TmGY^2+*PCd -zo!DFq6#jabi~_jF6efmJ^ze2iP8YzeQ0I8eqMWR01tX(jZC%h!7X^9VfvOPeurqWUuX&O0W>)qW=DE -zawJ=HU92rY{8wGBCR?=2bXVyRSdB*?eIx#1W;T`2=h)rSH{&qvYXxbv8o9_TutSg<3GvG+Hz(wD -z=ZRB&;OL>p0p}ZtZW-}be_+rpmhkt?)u!W*EjTA?Cuh7x(9_h#e#%Q1F -zt#R&{VB5SCjc83>pvjN=UeB5V$)diR=v<(5vfXQ5wkjG~b|6|svP~G^wHxPdKEf~o-9}=$_sQ{$D_%s_L>U9(N%^3_3N#Wr3U)6hH$$a$~ -zm5p?aNH!r?)HTzPd`svku|(#lPzvi9_fiKKwOxCWK@=M$#qDeoT7kigDVrNgD(UmP -zsJZZVfJhx|#cvIsD9sYUb-D&uare1>Xuy7_Oy;<~?HPv0dZDxmu7*m%lN_Yb!{ZG& -z(JQk%0{~FSxJrY0)+7=0-xK0tD6grhO;z=`vpKVF=0(Z+!_rnIw1rT)1azqLHb&?9 -z(Qs6rFBdHZcZwEzRg8n*T1Bd5H?!JbIEjw+kK$G*y4@AQyI*MQi_B2#tO>;CRU+R* -z%ja1(-QZ0CzaN{cr$yO3LbN10Hh+LAL93W%*^SLjn=4x*Y=8RXW=5{J(!w~mzs$mHkAK5FCBmP&2^2O~?5IPz -z3XvJ_)GvTlT2XLZQC!xIcqg^$9T>HWhRRiK~9T_?iMH57Dswo#1Mtq -zM6apvcJTPD^YCwltcu8aaiU}!KY)$xBsB@EiTAsk7?M$UVAY6BaDlH8GK6Pk5&ix$ -zpsQrs+;_#zDkb`Hi`4$WqFS|C>;y$~ZD=M?aZ@iOwqgFUGaGI>b#Zr*IMhQVbZz%M -zcE~Na^u{K_wO(=2!q+4Up6aKv@Z<}R%&)I-cyzv5(X_R7h2O8{op!1mP;0X2J&WZx -zGETQStv*qY**2}x#Z>(b5V0~__%BxcY6Ap38&joA$S1Wx^_BMQFmjh)a^@%fCElUC -zq`z-S?HK2dMuSKlX=g=ug@5TxGC^N)op=ZV{<4_Xl7?p?dUCn$IZWU(G4Opewx57E -zgfBj)cGPtrO1uxnlBl(^!=;cu9g}3B@JhEK5oRZ_mzF06kC%>YNbQ_Q`P*xl3?uCP -zobHfMozwR?iIiHvD2kf(hfj7Ex#`9Ko;K3o><*^ -zm(N&g4Q8oc79S4I<0sgbfyZzY#~p~n&%?8I^o~;e$AL#oZ-oI7^J|@)4XTiri}lq- -z8P<+9arb!1dl-{%ps-=O=}#7Cdr^})c+tNGb)Rq_zuk^rcc_vllsCnU>ykZL<{Wq! -zDQkq^gWrW~H2;M-7<)YDcRR-qggv~m7-L}6uQ&Yxpa%-4skUM^@XKNeH8orh)&BY6 -zfZdt5ef%}i+1jzcJ>DLnty^i?&73w|xT`8|-M`Dbw}th#ODEy`@irTk8&o9}%9~}P -z5>7inGvhHepgCES9U!P!PHRxD+)A(uTi=t2+%=4xzR(pHw3*%c2+keEdRM3*4*r@! -zR2wz$Kxb?*`W1fv$Fc2o9Q=hUmu;Z5b1jGYGPeJ;ud(+VtHw@lkCCyPrLAweNgQG} -z(Bf_DM-Ei`GuF~RU$7ZF(uVdwt#mSkUpW*H<^IffA*`~QktTXg|ClqwaweF347=>-6k>?RlSbpLk&P?1XcDITBCCuw_S%wXZWy9vI -zKP!q&v%6^QxO0Nu;_4>-@%+L;Y$3{%>;guksq0;6+_nq{okTU#7N2h)pILl`vA2Qo -zPq*vL`X6Gxk!~{GbYW1~-{O9_e8St4@!ka2JGhb~H;b-sI%^-?k_Zmdku2u&r#Pm$ -zaP^(f+}7IM2WQ#dvS?s5#41~0TW>yTMQ?g53)o;Dx(LkW$356kaodZfm2h7H?nsyO -z(69M}2PMIx3JUqdTme1kv#`6iaQ!Qy9zT(Xf=d?&_6;hx&a{vkc?)AHdn7jZxFSET -zM}CUO%cBO&uGOqu`H|;PE>%jR$O7xi*%%8 -zLUH<032jyD_?n_}X-9eV!LUVMIpoBuxp`L55X)FBpqwlSXh4r+v;F -zxL1Vb95)eJ&f@PzTe7j?kyRN$?5iXdb900{RUp)JCi$Q@IW&UsQ-dg<@%}HEMs~() -zW7<(z7+2hz0gJ=l+sK=w*Pl&VG%4kZP|6uuG+sqFPA(~qcHq!{F}CA8@t2^#VT0~e -z{1`UlBZsjM5Gc&PRenGyF6-O~->-6gS^{byKCM6vMC*d<t+8Sw1m&3w`pTNH-Are98+(21QKL|vivHfD8mY~xU_mCS -z&e-)XzD#zOH22_9!p)oC^+#eQAP-zZB%5#Z$UJcpn-F;a-z~HqxRS2HMGyt|*JiGz -z@haG#Q|{Q_zg8sg5=r?^4S>YpM7k9l*BuN_7v?J!v&&Jvg)+68R4T!O-o%;Sfj)Lx -zTnMLUl8g95cTHK%y5%sKbl-_vNR)VXliIAJ -z!e#xUhrOh+bVk17XFcE8j4|t%Ci$k|-8*fti^dq|)%=I~U$~nqZap$Txr!4>wHXDz -zm_97Lm4sKU8;-qQA5SOY`LTm)9bqwXp9k|DUe)(&3-fZttkNq3ryG8JJ|lw$H}+mf -z26YUNVTG*$=Om@y-!YQ%3f$32Nhy?w!+Rwpm1w@H;4&E=BBQ+B+cwcodrCz97s>vkoE`Heq@=3 -zaYF4-c5(YF<8t|N -zm5l<_nrGo%+N@C8EPQ2cLNy!`A9p?gHfbKDid*6vY}F>c%#SQg&U32DCKz|zb=3WO -z+W!KNyr3&5EkANzRXzyF$MYCG9VlPiJDj$FmfkIO$HZ{P0(m;+_h}Z2_?)!4!Etjd -zWL*HWF~t-AvYLf-UkvfNT2r&(fM2;>%xvcMWNnI@Gi?%pYYLpS)u@9>5jVtu6PeD9 -z(->YNdsA>&Vm*!|ILh%GC$;Etw^(oSq0;P;Oq7aW%;Pqw93 -z=Y1rtNHOG$yjF?Sg=+4fE()&H4XffQA(RpsjybH&28CzVFSfMwrMfX%a%OJ5+P+DY -z?zvG4yV1Z}UJj>zVHaI=Pm|{HqKqS+ZB&}V9 -z`H;cK$8BzIHCs&)_WGJ#4i6Ezde+^#jI#2S9F2c_1pckvh@P}osy7JQ+JB5d8kgqWl11mUmg;V*F?T$f1n5w73c -zSR9N~OJV8Zn5k_btR0t&M1do*2-Alzz7>RLmg1o*jqsA+4J+`Z;<^V<^#X;%wYsSO -zdKVp(sxJ#0nmTS5qNZ?l)T$s&NBvK-?WnXE4u~f%oDGr&;~e`}-)W4Zgql&>3DdW& -zB`l$o?ElM3;`+P{!<*2jUPUomlfnAbCH^h^jcXS9SqxNP~EONb0Z66i>AGpN%8z&HNie+q*^dTiuL_F3~+e< -z2?30vQ__xBTLGjyBheoN+&-!Ni$n({@edgtjV#a``;1Ve9~S9KBAu`yjtewzMw!_u-*Y}CInqXq-QGfSwICAQAZDYU95e0X|-!|&D&$_ -z#xWe%^)al*;$Z!u)?0w4s)$UV>V(Z7aA8|uYDAm7qC06ebieq -z@m{Z&KWMyOgzX`p*X>cQ2MYIHBU$%a{p#N)xaF+>g05;Jvp{5|fY9Mh#J&-;XR!zZ -z&q^CPwc$=|I-venlC;+819k6qgzag$7^wG_|`lDY$wb$5bZ=gt@Ztl8A?q)y7h);k#9y-2U$mTPCK;w&Md#`1 -zla?LW79{%SDm7!3^{?nJC;DGj`t1aw2avzYo6cj$!mm(3;{2oH*KFsxcX>tYBH`-b -z;X3@Can20H*}`?Pnej+CqI2H0uq&oAwG)a#>N&;11EfN)MZj;OTwwZGvBG%7D*ZBT#E{J#|3z=m0FMge8L-h4l#4995OB -ze=%da_JvhV_D(HAaV4FYjTJ)TOTp--p{bL+}W -zo3-KM#_C_(ZXBtoCU>>p{pcgny{`!;EbnuHpRh>~C>(p0?R}F`f-zla{FI&c?Tooh -z*t>y!Lt1gUiQ|gnvf6vCtHp0I+D*DkMCh3<}Q6<)4w%rOV8=@ofs=Z$U_xWQ|Rf8wWXI*zNs3G6= -z6cnVDgoEzp_xf^gc00evDwpbOh!B5Kiqyd#v0V7Ur(>;l;T7nJRDxLtU&lTN6%wxM*neE44E*I)H1ax@O9$Jc5!YH! -z-Y&pu5i-t$`f%sOYAdjt(X~Mms#^KJ2L8(4G1p$)lviK+k`W!nLy|`WWz|wW3GCdz -zmERu1UwMq?h@06jHBt{dB7wqHO)P{vpwqx@Zabgr;NV6d4z}tb-Z@UZRvx6_&=cFx -z1=EN7bi|6n84+A`7gNu01lIiJS}<%+z_K#gnA?R8h^c|%Iohjz1ryLaU(2-hsdMOA|)85R@4dXfKN -zksm00oJ@EV7@n+Y_fG->aFM>iB~v7SnkD_Omadr}M3HDX*uaW6Y`Gjlh348-7zt+3Om0$j`Y| -zI0q|zbm@<|hQ-d>i-f0x!*f%fn@6AF$`-DR6&I!kDr>mabn!&jX^jp(bne&aT=^u? -zDTSy8P^Av?y}#N>NaWB*h^Qcovn#d(_Li#tpV@+)GF|>fvpSzcQNC*}DX1{;BzYr+ -zl2I+@oL0aSj8?}@m8c8jIsG}`(-Y*qixnvLe;Nt$La8nAutH{Xe{;3ltDcqGf_}e) -zS`b#6;HsGS-)(y1%Q_Q0J=|6Y8DH7B+KE^zNR>#f(!^(i5B$ -zN)Jfery2_C)ijS(f|GVE0;cd$)VkIjSBuOhkx2;Wvf|PZ;gj?K!=XhRUA6yk8cW1L -z;Y=-%j%S3d?66}ixS~+^H!;5d0!5hTmLE3Ruf^)v%ya1nC-Oeb8gL8@JmDfnw(4r} -z?0U$z&=)K-WknvxY;p%$C>}#q7mBK*IH>B9ea9zjrp&h?OQHQZ!J-@QgPB-o%B5hL -zPl3tQP&U2`6JD;fgRUa952Z(-aO7o@26d!JeRIxi80v33iN_tf$N-2FCz$F|tEfrV -zb8rN+Pd{zp2Y@}uW|};XvY0(q_Vt_0Q(w~MgkgSGY37Z{#1>r8Je3uXJw(#$Ros6Y -z_qD=5#{$kW%_FTYdpP?gIkVp`Ur1VL@b*S;&@H`+QI6pq*je23DcJ2(@TgW$!%=V# -z6u7onU)`_IGZ)v9r)fB;hewAPpZT~WQL2EC>A7zH-ap~U>2i47TRYdarFttan=RE4 -zMmJ}FK-J=xpv(yruD(Y#f38g_dU%1OjYs_j`~X4ZovbNIIIt$ -zKH5gE;h5wx>2rI*2KPIhp)9_iTsYvhC4?WnNZUhpjAziKy4(!uBP54)FW9tJrztBLG) -z*i2Bf+ME)rus2X5Rh;O28Fh3xV~?FLQUBn%D)fnhrl`jvGqH3muA#47#4Fjja&Qm> -z0Y*`ihXKl9cK0c;yq9Eug2Pl@sgc1rcZ1)*sV~UQN!!8UIBlEj;72HJN5yKHE8rX_@#j>Kju -z)sBK$j)(3Ix=yesM|Pu_2oz?DPCPxwd}FUKac -z8l3G~VS@0~R6NWj!YhT;S(QzxW=4gSNDpByu1&|{bJlSwsH^uImda2?xJt*79=r#` -zHLTLhQ}sK1@wDT6<{ZQCwAo>kY+4 -zpN=dr&DqTSj0E8PgTu25Yg=FT)(X#E4o~(sQ9S&qfx!Rc?8^guD!>1&8T-h{t|?8QdEi}O{gw2*^A2Zd!5&_+~?l+ -zj6UCAe`M}`pL3qGJ?A;kd6pY(EHD8HSG;OK)jYi=h*=$Z3Opht#lNT^VE>oG7Hu3|Y#OlI*hQHBKFsYCV_+5& -zrkxM7tiKDR;{6x`)gVy3a#j|Y{#~z~H5)$d)>0a@7yl&8EKDcVNW;g8cvK-{490t> -z5(^Q1ZB}N3pOmL=oS1v{T*F*g|5>O&M4}^zp;kOmck=uD@filuYUfj8+#S=#_s<$o -z0|O-~C+SO=e1PE?R?2ISnT_~$XnZd@VhmVRqH5 -z=>KJDN3qadQaKB1e=uP#RWN$x;d!LdP%(0ILCS8;C;4;AZ3Z9uVlnA)uL%i!eHm7( -z2h3d~W3(O$q=qvV!7Zb8THg8dJKx!Bm&_CAAZ`ua3tHWkc3 -zU$2k6STSNC2NUwr7|7PE!;p6p(n|=_tmKXf(uq2FNd#R5P_5-HEv(5aCyN?&van4Q -zyJv^`k?F$*d9(FZ?H1dVGi)%<(EkFs5@#UT34rOZ7;fHe8`z7tI8X`$6X;7HXexkI -z_o3+*;}_F?Hlt_Jxbi_~*w#j{2T-?)L{F5aEp;rMi{N|8SP16dQ1YyP0=m<^Y;x1H;`+~PCbu0EBbZFjSI;xw+lc_Q0anx}XX -zG{HP^zsM!(341*?i8YSV*XS%BD0M{H#2P%E}H^w*O{ -z$lBRfNb4(6lrJLD&Z6Z17i8BN|=>C%&bl^Fc%PuBhiTpM$6DVrnMgk^^8xc4!Ubdwxxu*!-u&o -zb}Si3n5zS=ee;%m|r-r@t6aBTd%1X4}mZSU--qf?Rm1)vQm%$dR`&>PZ_^VxJ -zW(;&ULZ2xva$aoo-F8Q~ood8fEtrAu{LJ1k40W&(hjZpiGS?jlNZa^%h -zYJ^$s!~DJ5g;7x>4}sqHfev<{7`SLQuyLq~r2dd}bMvP5ujcZXmx|Ddk)?N9i&pqO -zb?vRoLo)e&#T-LmmA3b}V5xbl%N-4E2ro&lO -zS1`J`iBR7wC~4~HFAa#*MR~$}?8DqN3^14^$c1zk>f~u@?^Qxw%-6cNGYuFXJ|*Ve -zf*J6&naHez+`dN0nlX^ISA`*a5%PQyk^W-bH2BJQJYSX?#9k}d0gif3$_e^!tT$l& -zI|lkWF>Xw~;0r?cBxj8DB|m^gq4`nI8zHPt-zRJn1*>hC`H2BD`WsBBO9N0VVxaCJ -zRCZzdgS1yRFb;BrsYjSCKFqi8n#L?oMF}&VF!3x7Ch&AVLt4xCA -zQSk?WZNSXB-A*8j1655bh(5+gzZU4~7m}FnlSl&zmBHPKnh7kfX7291;}^{5vHn*` -zG#=wA<>6TYPZ@+6d(NKnHt94V9rl>wB6zR{Fn};66pZ$iPZk?6<0*F%%DaR@B#`SVLlK69p3;wR=qZ^P#kHsW -z`A*1FlA59s77}7T<;-LJO)L@PDYfevJQ1hL<*(}L`$`H7O;g90)61Q=ng?$SRx@ln`q2m1(9-3i5tUUJ+COg0D -z`x9a))gja-1tktpYF!Ma!i1UX!&Ls*h0!~-4jdKT4Dq2hGXx^ZVM=q`cl3qy@n-|6 -zQgf|{j1EYM*k@#h+VoBW>-=a8N_cv0wa0GdQ62io3oNi@q}D&_&ukN5G7b6Z0!`v^ -zk?Nxf`YA=8R$(3`R%kxNm|^&E`3wKyb-@w%SHLb~_Rbhyw6Cn4mK@O<#X=llk}9uP -zV?O*GC7S~R`}r~d$>h0T`94c!$M2ox56Q-{mqH^fR$-Jt#= -z#=C1&O9!Q;Of;MIJZgVxwK)P3=!bYDAM1rF6c;NX%Bh`bu0#j%Ryr--rLG+!)IRRu -zDrWli&hJ#*`n&b-eFQoIjS-i5t9(z{Qfno@pTbCD-_Yz+mEz^c-#-OQtQHslN&F|Y -z7j7B~1CeOcysp0YjAU8bOfYTnpU{Q<(9$Rm_!y;Z}&w!b2Dq!Xy>bk@+V -zMx50O=OTM1U%w^HQ5NRE3GG^LXN5}_bAa9261oPgv2w9)pa0D#6!+_ZS -z{VZXM`7onaig_2N1(Uy!W@n#fUPXifqtTB*P_=f> -zEhHc` -zx9J@j`d}x0d1V2)G&v4?>GWz$mr?R(wutmdXE4rv(WKfEzbHBQYb*S!y5#deh_}=a -z+`UnXjL$hIj3ZtY5PEmd5jb~Wbk-sIzk(8wdJPPS_0`RU>24@dsx#xQfEkrt4AEMm -zH-RX1h!QVk&%9t9hmyQax8s%sy&m6&$tr(*{2@^Q?*r8;xmvZRm$V$$&x^!`?ncDY -z%*#A!FAjgInmm6g50Y>e9D~&qy=AHmfc}I(l^U$1W -zT6yTPTfY@@dOOz+VPN15>J9#!{GgE4+k6OK;qfqdpZ*s7-PZ+N`xj~TgNCIOu;Y5ZNSm -zh?gf8_yjISwAa(Q#1!Q8@J1&qEmc -z<2P(!BcZzzI(Y5Pv9GiU=2i%AotIy}|D?GYH_=pC{k8{^TD*pEzfTftfMa867<;b< -zl$qmqIc!u@rbu8D^Uj3reEcr58~cp|oC9tiXFhWPHbmianpscY`(ikD{NVH3j34Ad -zAk%JX;+h!5Ys*l1 -z866TRO@fi8;&YmjSDg#^(#NZ(N@*Pu98r&E8d1xzKban=TAqt=6Nx5E%iLDyiFcr) -zR4lKQl~UK%G)>lQhb9AEuJu!RlbRwNs1L2s$H()<-8I3)ikiqfKn0`}So2nC`Rq*w -zHN|N^M*L9yanLu`4p56um`aelS%0w`3H&oPv9Yf}Qf-+4R7V9v!rfX4P1?-QAO&Fb -zT+4WbOuT!2`v&;y5l_=omtYQr-;w6`l;dU+xd18k3rXbHN<(i05aE-@O4`rD4`<}< -zw_jt+y@_5=qXZF&77^wGdRa}6hnHlUo@2d4>AVRMzy33fIAe=g6}}s?cAXS?4}xp` -zHCp==vUWt0L&n=0;MI?}s^!(F2t=ayOUoCx_6?E{1*EDO5zXzC*`sT1zKF3l-^N;d -z117hMxmR|$%xP;UlDkh&S!<6#s5I7Y@&Rx|)?U)a+E&}JL6Us~b4{1nmO98*8X+7vUYB#vM>Ig5urUgAHM&1k_s0O`eieyyA|8DZ;2+{ -zjIKO!J|<51wyM`(aiGN~)aCzd>zALUt>-nK9&fV_3v$KE`R0?F=ULrGUzd5G+p$c2@HwB|*KPOD|MzEpEY$!pz$$LcP(YgPgMuuc; -zbKUOYZ|RqyHFMj4&~1KtAH9#x_UtyOBe+|)C>x%BtPoER$kjDkC(AgRxg95SuP9?M -zKmj7#zXe*hDRUb*cuu(=tgO}EZ^HN-Vzta2YhMdsc>yetB35x?q1Y~4F40mk@<-=E -zYJbZ3(5vVSIN_0MHfdA0s{JJIYEp_GCD)?aC)WTP&I6jvJG;uWjIC+d!FEa@+UYk) -zD-})KlYiPHDtJy26MyjY&RtA+O_s-=ynxWRYG~%2>sCY9U?n(>P*(y95>lr@^NmRs -z>6|lz^vrvRm3@R_QJgG%Jrmc&iPOn9At1-j@ze{BO+s4Un*38h9(;<3RAye3O4lN} -zP%#$Xf}{Z7zf?r541O1{Q_7VYil*X}_v^2J$~~62i4*bG9{h^KP9^`VpVVhJHgx6> -z6#|sWh!nU5vqWdp92n%!er8>n6h0vZ_K3SG8enVVzkd*MUiV>sx(N!v<=gz88n}X$ -zcr6-cW6#hwq;wjg(zmSNx8uFpBzTKYa4r%JFeWB?c$568=0AOTfaMN61~Yh^#*!QJ -z4Yis^+{9 -zS5$9D7KY&3-p{*5GlPgrmcNy0I?FYjo8J2<+LP$dAAg%qwPmzF2yNN@>fIrwuI+Ao -z)~ez8rV{PMShzI=6(Bo2tm{RRz;Iq>BaERPOcslwcm~DD$$B))0`i3}Y&NY$fvma` -zK>6}PG^KRXUlIgqNwnV*abLZD0IyAL3vT0IX{IkI6YroFI(t9t5-mKFMK8ov;3Y?# -zhAF%nnCM6iUB1lXeJ-OK4_nsL+L+zXX*c~wJfx^)&oxg_|DnyyDfej>*CJquUNHHR -zv?e{zRqNAstUHsB-;-5gOSG#;({C{T0xG-!Bd?n4z1y@+1(%z1H~8Efe?tf;f1HQc -zFosgqmh!UcIG@0hu6e?HE-(3cKfgE33DdGlN)*?3AO -zrvvp5zg`d4;6dA*3DCL+w3s`bmuKVjOSkA;sE2;J+fhgZDI&;<=ic;=a<~#*O)A5P -zi1sYuQ`Whmscp)!_lmQ=iD;fRL{v~;LIF=5;q|bO&RKxa|n{68-e!T0E*QJrZ+YpFOvFRF+&U{GBn-_7z}2&OA}`b8`thMs0gl=s3W?z3F%z~N?Tz8+<^G1F -z8v`7v+=ll361t2;d;9F<9c)Zxv{>JpO`ux{gd>eKGP_M19I^5dyMa)TtbQ -z{=%l@111c=_ZCRv;0yCwPcXA5lYjYh9Ehlawyh@n6u>h&B*`KdFvQ>)?^^J?@#CiE -z_02{9E%B)6W(%kyOu{)T)E9Fq#Gpf?I1n<&7zyte -zDyyrjf4{Fy`Ksv@P1oMyI6j_sm%(AZMFO>Y`n8v@)#j7_Dk#$W@k9R_RWBZDFe6-O4MrG=%EFSmuQwYr+4MQLs~q9uG-l5lyvij35h -zKj&A*^$bt|K6XM=X)7&T2*hJq4ecbg`onyIWA#~aS@M6bj!?1b3YIgVqpQHGor6k0 -zOY}y5C2n;2eigvTFDGJEr;6odLXXqa?nR?3kmpFlgjzLH8V2(>YvzX_n;e~dQa-pa -zpl(L$KhSSq5J#ray_#^d+BEqX|hrLeipzCScn+RY>pO{-v

}^gOlwwC4!}{f&NPoP#{o;$TtB9_{w?> -zNM5SmCN -z;d6(+om(WGdSl|Ddt_jIe&~uet2r<+@rH-YY=fDD$SO2ngMi(NiR*DkEr-bmlpy4x -zHK5ebFYBKv-y}dQ%@gV-1Jw;sTuWNbftdK~3DI_1P7`E)M?BTGK7F5Xmnd56@T(^# -z=Bo%G^OAJ*6$phf;mobr0prBPUF-tcF|i2Tuws7WkI;gNi8_*XB`argaCHmOa?gn5 -zI+Cq>RY=;A?9`0dk?eTCxRINLF5^?(&hW0P{XOlAVK-@kFvYjYMBm -zY(txa%SW;U?X>yO>rVq>?e*`#l8q6`lAvgBB)heNV=8nZU4g=iWUb}Wb;<{kEXZYa -z_6BF_uHKKoFgZQ985v%9n)Bp|WO+uAQCS~X5XsIW$I@Zp)%r%J$V~I+^T~!<0Z=n@ -zcKJv)U%F!w`x(jlxhQi%w&+%ux7N|sPkV*y -zSdpy%Z?fzXvvJvJ_rB;qgcjva`W#G~eOxNaBy-5_1hrEC+bHuUYHO;&jxw*qngUVg -zf`oB9%A9WCN7THN=lHUw`Rn -zo8#WaIHi1!?TWEZlzD6qX85i@tSIBSKc@mqivEhm0{q{lTu1@)it6_x4{`h-k~QuB -zp6~1Ne`k@qS^n><M(JRJRctL6xk -zY2pcTI{a;O6iIhD8ob-qrPA`&a(=r1ymnYlG5NJMma&}3UUzkWPbnv%j`wA3x`I-8l1tTH -zJxERfhHjC{@}$m^+0o=kE0vGGcC=LT^b;z2C-uj5&R@b8%zPM1`7q?a -zN?{le3|i&x`o4-1PCut4w2`M8hY^hh{Ii6jo+`d}AG7`opmWeEK0}^(dHX -zy!n3lh-mo+#e>M&tf!gphVaYU#}xJYm}@!$$hE+GhwJ%nVXe~RfgJ0jm!XUkLZk;Q -z$>m7rSW?P|BIExRbuj<Ll?v+ltRYcY3;#+~x_@@dw6GMlDhP!EW8nza>yIYydQ -z0z7-uto10(teoJ?WL&xpgQIfkW(-4sRW75A5Zl!3&4OLXEM8h~WGD(5Fjby3YYKb> -z7=@Hql4iXQ7oyXwO5jh+)EUg^KMUPqsLd4r;%MyhX;!h%w8ofb<#SQK3spvYe*pml -z4TGQG0SSM@;2ZpC(yXc9iO8DeMRLbgS_%*=UA+J(S&*h-fcVIML4iYJ?KA)3;@4T$ -z{AvUi-PTwHo_$%?4`@DwBK_5n|GJj1j$jwavZ~T`_-gq(P*i)etcp|U?R~ZU@RtNE -zMwXQabpt6e%i35Es)?OtJ%uSHAhV^hV`Q$GDb<28#Lu#x6O2?g$92Fsb;+@3KNj7q -zTK)nGf#|NoR+i;>-`3GFDB1D;*WbCEzV?EeLX<6d({1SUisq2D>-8hRq1%e+TGtro -zjBzqnKRL$71d~+P!n{;&O0YS&WBuPA?2r0+32x+;s$~&q~I9sHm)`W^@ah -z6rsrDr&Z{{x35s@i$g}IaVs6vz}#uWk`e~`gW*+t(c|bWbUDE;KW-u)t4hJc-c!=h -z!H;5nhnrFy1l07DsL0j2sC*(!w_w^MCUM$MsOJ$7+uS>ck+>&Ki`2x7#OxU<$HS>7 -zFj9`pk>|+{l4sXwK%4GwXl`QYv8&YdN&h_D<-GY)Va@2y10r|7Q;ZQfJ`T@*WXh?uVW-q5u};b-u?j~2`5OABocp$bi8VFdU4U()14-d(QYeZK -zZAppmDrO#1FBJf^CLaJ*`Q9l&bf@X;M5Q}SiuJ*<^pxXJg#u#;{1#x?z>jve`cMv) -z1Wig~jE%0T-L!&anle&$gKO??u_j1jErVDJeqq2oRN}iU>iVGscNsV6e=MhZ%x7g)Cl$* -z=X-#H3&^{LF%gB2ZNStDc*@iMj|d-{Ez&pG$pbMJj$e81n{ -zKl9GL_c_mb_UAe0o^!6_vGI{@yBPoerqN6LT^P-3i_JuI)3wT0_>VQB_zKHKtXgFR -z><(?xGwWOPK_3Q26ggiLCzMWpfVH@_3YuCYil(IKkG~8>EnJGSyA<8@v4^6YulG=N -z_7zRh46Aw?6`<$^gb+nh*~?Hgd#A{#wM)@F#jkMkJO&q9Mv3D+6pcp2wq$g7s-`I3 -zs^2>XDBAt1L(ymq?PAF&krXXBVPquhX|>jNVsN1;TH>Xs(KjB7x;dk+;+EFd2S%|i -z4MjOU6tTjr6dAWegj1EI;JbTtjBRNkoh6<5bmF8Bz!!ouzfRa38a1Cz%zOHR3>M(( -z`$eFaAU5mMiG#mamw3{+m1>25(>??zsY8Tr?q6K0{^S0|64OK!B*l#}c_lpY1Ci|H -zTuWvLd?1qa)C4-&4)`u|vU+n-7={LU>iviMluI#jEb&oJBwsl!FdCnKcYSH(b`eF{ -zx@8811$pI=Nfbra;wtz&t)eK0+fH`eyby%|zU -zr}o20(?c(B1nA}6SoEI6aKoZ^*5`hDe?^p0?)W~8*k}AM-M5qOpN<;quOLJ#A?#iz -zM#7=aespKWtUvD(O_=whV@Acr*cLw-fbh5^Vt-Tjb*30XJ*85i$| -zOd;g4Lw??6|E8DDiiBJmfZY0~A2K^3#|I!6ruZSZ{3cTB9e_;S50#UD -ziGA(UrvE2UHKXqBUM+V5GGssfDw+v>E*hxe9vh8ABWv_m0S%qeU)?Zv!&kk( -zDIu}}lM115&x5qV%d9o1i=MnTIhHMx*piwn*4F`Xwa|w^*J&V+7F^M{s{lH|{yYrX -zh9_@KJ0aVwv>a}#;g|BJ@|1E008s>a1wFi=Pta!o>2?5=CEcvCt~jN>iLCm~h|}0==vR?v(F4YwbN8{OLVNB+nA3k6m_O`< -zv&3yP&9pHvxe4>J3zKGG9RF~BO`8oHsDHOjifLnDrV*wIVJ^3Rv#1>p95%@DGsKX~ -z?d5pyfK=`y%%1&5D!&9_N)u*2VJ=6>s4@q -zrYK8H>WJUuMQJG*v*Vd|dj^JoURI9jnrM5l4KuU?LH17CMCWIuEJAdM(*x!7lvz%! -zSeu<7M9+|L$4kKCP6#dhOptO;=j43i7Z2Hrial0pk9w#%4Zf4%#Xc -zrbWMxMwUgVnM>kn4m_$3jmHFSBs0`Mp)u37*oPTXKi(c={ -zpkySTNWM}?guBGX=>PBGvX;&r2p-1}L(Nm&1)@^bRw`(f-nj;CK2qF^MK^KJ#z -zBR#E-#f?fvCJ?qJVdL?A_KjrGk9Vra;yaRM<^I?Iz)Zn#Y9d20WB(?E1QI6)pIvXx!2D@2_VM4x#Y)-5O= -z$FIwi5ZWekcC|3|&K{YQr2%wA4WjYu#6AM`pfN(iOr|SSjd#2u;CeQWchWyp#zfC& -zUQc^iU@-r+8g7jrv&m=3{UAtQtPrfwr3>r_ln(ep;lRHa|Gi*u6j?A7%(@#zcHyZe -zvk}@Tb0dvQ@x;mMPyMI}aF&-j8ohvVJl=opre%qQj`xA2+a -zS*VhPq}pSE^=uAoPrzuks)P7NA{KPdwia|B%Cr$DI}$Jy7mJo>NiMqX8r{)C!jQA` -zQ@!^+wMxX0vCE{C;SD%8&K>#bb<&gGJ5G<9JIlBjdsZ9);mCM}OtPTD_9d~^bFqz| -zVwmbONB*TfKaiV!w8CXN*G+S!82;zpCixqeUSB@*gHbuAZ1dtxY&Oisa-r&aYXjkG -z6mu$$y#9k>&84O=srh!N;jQD(0WFnJQ(Ed~X=(JGpfrY-ejjfbx*h>qw6sjBEmsnZ -z7ay$@vEI$DFBiA+0f&iOZ21IRUfcnqJ(EL8ANV2fCFHLG$h)7nAeE4si3a -z_LT#7tu0|2hj=`F|J|m|BWPoJ`YJqeJpDBqnE&lfLZsjd(Z$!>ji)E0aPWBgdrw#r -zqZW3;pF`mn*@h1Ot*Ted`w@|AQe-y4TDxFH>(jFHaZ&xD8GK!FM2zH*W^!EdK4%Em -z=Na_4h_g6)TS>O}jA8v&4-Yv>+FS>OMgY%flPHcT?wybr$v(h<-;RgN>L00cq;Fq(TIeW8`Vc9( -zEFmj5H6<^L(4ga3G(3@2T}X_`jatZFG_PfNZGt@j%JK-Cq+rQzuJ1uA6O40cMajqq -zh&7>b_20$nyc>;%^&%VMPw1jX543eR8ogAUT+5S%{Y1sKjU1UJcf<`bsMBwMsPod@ -zOsl!oAo|LNgO`9rg~%>wY;L~`D0RCjaeBN4^0IQ>uaJ5u{LEGpMQ<+%`e~jf*X>h! -z_2jzN6+mo^D4L1TqO}s42ui?ho40{Akn2VevE;KMO$A-_T-Vq|H%_Aq-34^MT$h)e -zOxR*L`LHGpBzI&Z>Qm6;=DM!capUs2ZeCdA(%!|k@N>gdUzo9|PV|f9i|qY>&UJfG -z*eQ*TnQ2&ab6q7;^YdoI+mHeQEph$^6^WhezA6VwV`%AUreUbz7fMSVl0AJhR(`ug -z1ks#bUoO|(a`08kjKt@AWp@S -z;FNcb1Rv|KB={7j%7S+O84-(}zYht=vh$8Ex`G;A`8z}a-kPo?Ir(9eaDv^NA_lR< -zZ|>37{^vkaMQcALPZF<@IiYL?X0I1eHC1P-J6+thiL6{C0_qC1x`oL`OaLbc=}dh)bX$SVa8s*9EJHc;az`wdwovFN=tlxN8*= -zBhjBVT)5M1lYll>5pg4)I7P(0(-i^EaKZJkRX+*)Pi!>yF|sZ}h3`~7aKgV^Z~On_ -z?^N%FI5>T1S8i -ze{H*Xp$MXb+jWYVG*+QFYe!UVG@fA9T(IY!q-27%(f1ji+GyEDsM=E-?H^$XD-R^z -z+Gs4my|vLlsADuAFXN$A8$E+dt2Vm$kf%0k*(P>v^haOvXxB!^FqjklfQ -zdZ#v8ryn0gy0mMfNvH%(ZM5xz@XFfgcw=fy6+iFl#$ThcQyX3Xf>=6>o<`8Dw>GNM -zfb@B5qmEFvuQqxb9SYH*ZY0*JjoOh8)<%=Ai&`6U0CS7VREz!sc1_*`dRKEf+r%fbArelr)=U=U3z)jDl -zER5CN%Xui~{IX~XWEVRQ0&)uue0Wq=fz?V*=!@%wtemoJC;5bY8w$}-TW|4xFqIoq -z&;Qqt0sJGlxM2CSJ;_Ry6gdAPx2{+8ik{- -zC>i;Cb`jy&eNKj2VH_cq2%EfHQ(@64}e>s?jI|{xBX|5u_O|tq8ITWhRDo&gkm87ET0_ -zp%9$a8oeBUn4BJZ(;Z#C+EppEF-8PJ+FLh~KPQ58(vQpFu^mCWqeRH6p=B}`2}?(i -zPPg;bj*bzx>edIJ1#&&S+K#eTKVA>p@`jLa8j?V72q}+@E+M43JG^Rw9);S@l}W7= -zLhd9X3?bc6Ped7Bt@#EG?cvpq=DZOtgiKJd3?UOIfmB}zsXbRr@V8%rA*AeMWJ8CL -z-!a~`LP*g9_$^5pcC1jkEfJx38yMR+36rD}k$+?+U0!*+dHPA@yR`K>wP!uRLnYF>jJ$7;Xy%-%9L?!E>&Pp{H8H4VWw`fHGVh{~SVAPtLoUxReT*j(7` -zfM3m~&SnXbzrGVTM=V#Oa3Vo3=(%J;vFVTiSS6wU2pJ8xMy_ -zO;cbo?(4U-d}2Vfg|!ISqE@~tiDHBc9U~;3HtAs5UDf^$8Y}DJ)2evtn9Gw0D>N5( -z=eOTlj?EMiyt&L+OVtR>&2KH!Fi2I_a)U%FpS65V9F2fOTgxq_(XV4I1>3mR^4oqC -zy`C{^$;h*8otqR~jkPSse0_Q*=B#aNSuKM -zYgvoZ`I2u%R*(K{bbcUbQ0Jc^?QqVU+IXP7N9UtaBx#**L$bP@&WjeZ@pMe{==>uz -zwsc+>PaU22L6p6M&d;A({SJ|<4mGxvLimQzf{ag=4S&geq>5W`GQSj|FRV+-v%uqQ&x -z>0#3^v{B!P(8`nKI03Id0L}bDTZfxUXy1Pn6j}@7_;axl+ImDd6J5S*34~f`_h2CC -zx3ufodJDQ?Cg-t<(8l36w$N@T$v^#M -zgfows(rK{R(hsp*>jK653a&lN_O`^=00e_61wlAq7_>v~!qj -zz~T?Dr45DU8KK=HJw_E;uN!?rE57A|M`+KEM^gx`8-8O8?Jw8?>Ys&1XcJ4Incvc8 -zz>1Zn-Q>Zhgf@*hnkXEYa@I$i{{lba#PSIwBcY^c8=%%Ucj>X9&2=Z9OAD^nQRf{I -z@y(YN5N^>p`mj|7oQ+uq94qG&-?TDbo4Z3C9z>VHuPZ)bxJ_g}OgR)z0in9`+k*l< -z-BgB3{M2zZOJP(FIw_Ev*MPsW9sDYSPrN^HCP8RaV%r`nOg>k-b?0NlDz=W3__So~~>wz)G^zp)%q&E)h`eLXPW9(T& -zw0{+uMNOQ)X{{o+P>{$$ty<^Yv-Qf`^TVv10=8`DO0MIe1B4e~kIiGk`bAkzx -zDG1p3{@pyWD0}B=;Y^2pc|V}XQJh75i7g7T1t(SG@r^s#9V@}Z9fr-pP(%fuk01#k -zccvrJvkE>*M6~h;1`SdC(#=)?n1c(fBT83?bt3q1(Vxun^@6ToisE^ehol~HPQI`< -zlyXNG4|FE!3nvP*51~hX-7wCX+_?V+t*cYApXdQhCW4x~)lEIKgm;mOInKWpEd`cj -z?i0-T%ce)z$=`F0kG8B0d-liWrWlGT@w_H3YzAeVZoP>prV|C@Z_S&50yNEpgPQlI -zBE^!C!^ksu|4G=Z$z1ggO6Y|H*rE4plx`+-t+@#oQ8QQSbs*YawpcZXH}uYg)d-zm -zi}e_u{1TGX7z(eSVggSb#Q9`FMA%OL7L_rA+AEbI-k7~vzp%sLE -zoUm6Tp%Mo~LPNb0+8Sp`sF-vXRYEWP39GjyGz6K>E{I0GtLPk#-`EnmktBaJ+eoO$ -z-Du{Q(5zaHglc-QQ9{4Mz_9*6!0))As?} -zdz;0qvyUhFY^d{kuY{gMv==&`l&BxmhE8IPkMCc7ZzOb2-zXBAnczsMum>9@G=nIb -z5d|ewT}!AqCJKEvG?cI<2zxaW`hA~BDBfFCck2NXouYbq3tU9Cp`#Ui68aFy)V84( -zqm+ai<2Sa1HlP~C{+C%sLf^|4>9=icl+Z|`C`%NSP#+ZDqMH%T1y-*K -zQE{j%VK00q-Cd1@=D-ZoGb7#s?p}Dhkx*{wEUJWFfrom$tocB19I60bgwESso@CyT -zIYJJBkcBHe2Ev@0kPw-G8H7-{CK=#xH@Tt1HYY7Q&Pw%sdxnVp|*Lvby^d`70ED&24*aGrKMEFD6U}7iM&w -z0L({(x!Z-QBJW4MbiPEGLN3f8sbjq`DTFyT!|?kwhBGeAWqB#Wwlm$f3vyj`+ntzA -z!1`CW?cE0J2nWYS%!rs{~b@K^%a-bxRXxfH%KpI^hjjomM -z?Zw|NV35JD^Ylmm`n;2aSk#}9`V?lR#C(dja@nOQrJpar07yE>tr4w(?_#u4 -zS3mw(KR$rsN5C$1z%QaW1L6kU#JeeeLc|#$f3yP8sk#Q3p#aPh+s9;@3E$GuOcexE -z>W$-o5s->`TS`q8KmZJdCx0VW#NNKE>}Ww3(Mgf4@d7i{g{g-QajMs~92NGLbKivM -z@|yUzsIZVIkmF(+m+M@SdNc}D)7sLS=6gqd;G8h -z>~QQ$-Mx&#fV`jvCCAS|Iurme_ux_q;6=<-_yll0nVU3?0+5ict)kd1j>+i33B+O6 -zbtFW#j1!skR?Vc(S9UuQ34oA@ea6Gr1a9O4FGQuFrS`-y8LH7p%3(?bf^$w_ERTVi -zb@sscN^FDkBc*E8XUcynxy^Il;l>({w$p}-CcSe|B}vH-Q^~E~PFoP&=Kd6tRysH? -z+>}7sC!-SlTL>Peo>0t;jLhZ{)uZMYxv#Q(pPs -z`-?~Z^LF48}Zcm$t@6nRKh(d)fI`=p*3>dVPGJIwrr(X6p760{Ao -z4LJWzbzvFpmJ&V@du{e}HmmJY)&mv17xNH;6d?%LpXexYR3U%IV(LuW_<;i(B#J3R(Jf%y($F8lVyFuB{N3P4{H!hxOw{`tidkYD|`% -zf}8#Zdu0Kr3CKrKp88&4&j0Y3|X{L-TMX0Hu+-F3qmj -zZyF`?=%sKw$$&DKlKasXiuOeb;@;YG@9w0!gzA1lc0?&%Koipu69+m-LzIrs{^0xi -z^FgKfedyN+bgq%NK{S`L_sfxW7uKrfO=Lp>6*b%HI2 -zAy_`~I%NNPkUCL+t_07r*VZSST&6|6Ij!qFQj`RfS_{gUO -zyjPJYHrVfX)XVto*Z@r7_W>oLn%YuQ^y51EaS9&uEF4l(R_^vwuM&z~i=?<1J?oam -zbjzH&<&Q}BYUo-C)q&$+v4*a_WIc@BKQS=* -zfj5}@&gcX_{bv(ws=2a=mHQr-WilYw&3(HuP`Ikxce)5|N9Vq+P>If-|LW|ZFOT6; -zne-;iIJn85uVjlydLpui!a2zv>#NtY1AaMn{mbXzBJon4Ela;9EsvJ!^bl?&Io~Z* -z#XF`-h-JaYMo0rO%i!!b@QxwQVPuW-&s@+F3oKLCRBa+qF9NCYtKh5QQ1!Bi)~2dR -z6si&;BZ;M~+m+-;PzB?djEMxFq8}slxsQYg@Ai=UF(l&PLoeIrW|#xWHzH#0ik0(e -zo$V7JH5cOadUrXmOe>;023`pKx0z?%+-J@BObC|LHW*atxe7B4sQ-z=tCjB&W&>JjgEAwk -zRu2BEW)i5o!*F4(m30!aY^|(ypMA$?!riz50j*RaVXHn6Nd>i1t{0_`FKuZ}>7hn8 -zPJVc_Vum`qQMQD_1A#FknM3t`FA5SY%{}7`gR>`Ur|0w1&pK5uFB5R7JpHh4XuV&i -z)&{YMn@BTbH>tB -z?7~zl1%B{Oym>D9TS#0-pRW;VisqVtUQgJVaMPS|>WJB{lD-}$LTejLk&1+0s^Ik^4&BpT -z-X>bj@sYD{2*vNP2_;_X1(1pr%M5h4%0;$&m*FT^O`6D)QpivTmBiyhNq~3hyV3qr -zYS_?m2_hlBdMfDzz&n-nSv=B}w6VXpQB7d} -z?|s@Rj$lBwz)zeCsulLci;6Ul5&Ya(f~&BJeo^sD02S>}LJ?`b4ZS(>1C_J>cNPj8 -z{HqRz=NgQzj=S!+Zcal8K-_ZnOXWs;9>l;ZKy!KyNm~PS#>|)Q;D%LVgq%4Yh;Gde -z7T$RhceDX&@Kbo1mW3H~Z`gbd{>|Sh7(ay7WIZWqkHX84%Z4TkzJ}saEdt`xJ2B?UN;JSppeE}^=Lif!w3PPh -zSYgq{bB)Cc7AqJ=F$XC+{ -zU)C#l^4l?#8d?(@`AoR`p|=s8D(Mm;ZAsYS_lyMo#PB{Kfr^A$>OvjIY@#KBPv>1h -z0wp7nAtHegQ0TPx>MitmEA1VYDHCxS=DF2)8L1|Bcq!j&Q3i1GdDYNKdnOXR!7grb -zsr()B2sON&_m-(!SIB#{h-p)%k;+eaZKq7f^ma30X1FlvD9&T#y%|5L0RVK+zpG<} -zCgSVZ9xd<9#MD73e7|(!$$Oum0Me->L568g-n&LFoblW)q1lu7o*=r5?+RaxbUF~l -z(RA|uuLzl@J=#%w#zk(Q7BrrD-Yk* -z7#B_h9d5RpE|+e$8wG#2vRwlVfUIoS5Y+gx-Sg7k&2}@84^^B -z&S@{OSZEq=jy+7cMG=iK25;*)Wy_^OPeTpBt-+{s6a -zUl!gvpa<~{~xAhw-~cSwc`Q*Z23-MW^`UR<6WE#EVE5yx%o5JtX^8+%dK93SlH4W}eJ`u{8)h-u+@(m@)D07dr?2 -zdiRUnd;wO$1y-2n`Cpt>@}>+iBscI-iKj6F()-1pE2+ofr*tKyklCzwm3{AaefT^3*O9O^>H^PE+pDwvls(-8{aFw~g(Lb!ut>bDiK -z9Pgi*z~^_oT5P^4RhrY(ch~Vdo~a=V5O%T)TkW%e=VhTx!TMLiFhITyd=5F8NXsS; -zJQ*Y>AtIkD426^3F6skHdEPQ)C%-=pBKS>iZyOMra(%$Lmk?ux`@$)1ce@{`3JJd;RGvgbS}fEk_CSfAOa?U$MRRry_6+?N7HLrRh_N -zZs5N({=ybL@!Q%Z|lwASd -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 -zbO7G}vK2|cqo`v?##eqL%yRsb -zPMqQQaOpAX;btT8KGkE_83>rRUAJtg>{^{q=4^ge4DY~nLMYt-NyntLd-sH=)4C_1 -zO2a+(8*(R_X;G|qEzf*IPV7kuU?}mHPBVgNW3ED%WyP|FP0|u{c_rVO8w(XmT -zU(UAAiET0lOh;6YjCjDZZQ;(!1NV}sU%MF|*KBnNcjcWxplL49WP}}Ra5r+e(x8q{ -zyCjRdnfcc9K8;xM>GR)&N-I9S%NyccXX|;ip|m~{gNRVLEUD1T!pLK-gT6i@JG#b!u(n6i1vicu94{HX!?__ZtkMgueJe3lT~6$NbtqD+Bc?+Rs)Zy7nXVb6wnW -z!nRVR9&vB&BI?I?UiZiwCRvqEZZ^OhxpoBV#aHmSBllPi%fM}{Y -zO(T-qh{V;J*3Anjo3VUdzSYYP3NFJnwl>Id-LEDxXUJmn@km;JHJRF?96MOtiDr>{ -zHhaHH_%k@q8~Bu2R(E`Jw_lCavpM_SpY;eh7ke0lk}o}Tz4!Ftt;hqWxJpOZj9y&* -zg^2Abu1enQEv`;Tra~tX{OZUELj8j6kE$sYzMdqL?`Eij0)kD%i!&wI@g8hiut`L+ -zvZL1>v|tOP__qaHZhln3RzX=1Q?Tor(*9KkS0UKMbP;TIuVANN1A#bItL(>&F4#yD -zOfA@>v9ULK1v^%f4g~wQL{d+g-X?N83H|9&kp#tgUg8vh_lj8UIJ}{XHYD#>&%?)c -zptNURQgTW0#yDIP1&b2X|0)jOzfPlP9A1-Q;_$D?6FLsh!ChY*{=xD|9)Tw+ -z4iAyH08w`9+<>A#6rS3F{w|_;b0lcsY=K)Z9D~rY|Aj!hK076_=@=18h~*|%&ZBDA -z={gAgVzf%AGXDt?h*LN&hK`j`@Zx{NlTQvAbTV82${DH8%J^B&}P -zDR}jod=f*c`y(GkubEkS4L*~%|TTfg{hPJM+LiM$}tA#T31S<(NuFc}x4qg_(i -zmY5GeWR$B}`vxgOHBo{{h?FJdB7yYe>Gzy`EFH@t5nWlz`fcWE+3H|bqTO)ci+K&^ -z1Tg*&&`@E4MFUWIz76bfVehCKN<<}qD0NU=HaTQ?bvf6%a{JD!{8M{J81Gz+b{fAD>)9QT)+W( -zh-m3P1ejlpCL{edNJO)gBM!p9pO@|l^bkq`^+i-(p2hH1MI?S78!>{nt4P7X>Us+z -zuij$g=gO;znF$SF^F=-XTn9M~Qnf -zAFISQIVl)7>XGcN54iHeoVn{gltwYa%yMCV!g~rM27q9w4k_dO6N32T#$OSqqktaPhw_N6DGILK?;rCdq~Q#k|ipwRK;@#3`7oj2n&nh&wQ1-V24ey*k=u -z??s4tW_!OqD7N-yj~kn2qMcJ@xkl!(gS6DmdZ!n@dbZ5tzj -zW_Wq)`UB}KNSLo(n7dvIz#OeDbPiK6SLubVkhrv{HWqTYvTHN;o=MD=h}o9zqG1jZ -zju$>n$Q%Oc@xt3#xCFiMdgs2+3r|;bh;c9%Am+)fMM^deZ^7n_GGcon&^SipU|fJ; -z8VWxcz<7SWg;DWO$V!Ano{o1i=z4@pNH0Be1gz8SJ*4s6bK@ -za70&|l6bBbCjtyC%N9y*z;1%zFRftr6=C=C`}twn)VT-)=+q@l=z^{@=E$VSl;Swp -z+-D<4QQ|`Xt&AN#{<_16v1OSW#QB$m32NiS5K^HFAR|={QENvs*!FhSRw&#c<-B*z -z^2d_%eESFUeG05G)|a-DI4lkLaYz -zjw;HzJsW0e&tc3!gu)$L7)!Yaa&xUo>-!@@-AyQ3=3nA!UVVRqsaU_hi(>6XEPZzd -zpIYD5HlV4|cbNlzeSdyRsWq@cx&o?QEr`~yNh|7mKa5et))D#J=zE>Mc^__GUf&Zn -zWC=h9^?intq!3;eKu6!t%Z01&q&*^yt64sLdZ96(in`~|3j>$d_nY9|()Uvs={owZ -z9rEcr-RQf)?K;0$8>Ff4jToba!p}B0`o0fxbM;M_>4a(O!juleq!T95h4~MJ`SA20 -zOg0y0dl04(VRke#^vnsu$fxN;;khnMrUypb=s5@v@Bauz^^_?=i{k_Del6Y309+B2y-^s5V$c2 -zQ;RU0T$t%Wn41YR!-Yu?!kol(1m?d8V+*oPFDjMP+p`Q|!go~gdc%Ezi>Ff&gK3nTxi81_3~a(iQ#nv3drrx;?+M#ktbq5S8|zq=58AVGH} -zS+|dYj?;9UQ5!vh&+T{i`c3xz=+|1MQQMHw4rHXdv+2rCBbcwk`Hu|^1s7FOAe>L& -zR3N3B=WEi{3c^n3yLx^n3IEGD4Bx4e`}Og?T{)TzD{=GYfY|lv!vC!oYP2<6FA0(i -zEG;3_IOnS1u{&cLA8ALbvKknwmQgP>sOwy+K1E7_w4ARFH0TDI;QgTy1PP!!KdvNF3Mdco+yox3~c$WGh{Y!nI+ -zOHr4h@1Fp1(RZJw5cXJo!~9EKoQR6>qRC1k&`JW4tZstPto+~nn~$uNC}br>4r7J^ -z=byS=RR)+^`JZcm)v2%-zB -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 -zD^h2U@}W -zBT`RU<+O7m^-wk|LDcr^_JXJz3=^QsjnwVfBCCw?nKAHlJ5mpmYfq%^r|$$JbspmS -z1h|5cx=V8>Qr{&nz&(+AZ9x%84@E;TQV)ftMUT{@*|0Jj#)&4<=K3OaQw&GJuP;(} -zV!P9c{z%>72}?|j)YS;NS|AbrQI6|Ky(rm&3}pU)F*hCxk5R3B_H=tat0ntbN9dw)KIFBhCUWhur|SAnz@BDf1|Sq}4O~HcdK=!YGXI~KgciyC -zhTB1Gc#|f=)!NHwWZZzVZ%@c0w;A*Afxr%i(&d{3)}kg5O#Wq1pMbYtUMwY^^Eixl6LM -zP}Tcip^DR%PX3LLrT(NLV1prKix?6-u-%d1k@Kb_SAwszr()8R -zM}nUWS6pQ7@%Xj9A)tj!(EDw0IqGBFj4Hv3%=?t!9z6seJ}-&{8)2R#h6D?{W#Z2N -z9L8>N8FLc*6x3d!aN}FZmdN`jho5X7pR(iBvv50aoa#<2mr5w%WZF%2Flq{4GI6Tb -zSkkQ@>9>54A)ym8cnb%l-x|a$Z+__VuRf0Eo&KVq+>7 -zIoBqYB}DFFXX}eQojIew2Wt2^%}>ZL1=3@5+vbwt^vq{ty6rVUhDKhu{aekgL^ZnE -z6Qlu+?gApU2=fMX6L8zLn2aGc;-u%kwf~T>3kYc{C$~K#BC^lC!uOA_kxoM{j*AGNYShA%a>vUgSjcIZ8|Aut%w4s^ -z0L0WL!8WJh!agSFXWo!z+cAaU@3jwmy^g(J&5>Zsn}LeVl5i?~5414^D2T=0&0Cm> -z7sA4wvPl|_UwIsQ&BL+FeOz;ifTr=NjZzwvo| -ztKf0oYO1;A2$Tx_6VKIXqE1uM#Iv$q#?{38m@hV($U*{-u8C4eWFAe#ckyaMzIP*< -zn2cX-GDgbvNa)tWMibu!XVQuhW|j*x{gumW;xMcR>;Kq*ns_b@3jCUA_L!rI0xn^? -z4k;P=k~r$QI7YMw4!$FxYy2|Jc+e0ecguqc%JMMBgBquymF+>*ctgZ7?xYci={1SH -zuDn^qaW#5-qlxJ4Jy{#$>TMCCmeJcj -z#3e~6-InX)FB8=sWP{^3(Xs{Wyv@Mw*U6uK9i6=5c50+kh&ZOWI5rD&u1>Z{7E@7V -zM@NrNrfmSAqmwpSxUh9nk2i#<+);Y{5c3)M{x^HQ8lC*rm^$%BwHC950G&(ffw<^8 -z=^pXvBo_j;eb8YynH~k99r5ee$w>@FvHt%?h}bju=pC3h)4M@I?03ZIKUICufb0uq{v -zB@4J2RYGkjbxJ7rEG407ka9pmPa$;pB;=5L7WFL7Ke)kCsQsFuE{aRftd7%e5!*cy -zt6d&{I~}(%^~{DPRYNm*l7S=1xRobvIf_G!z_alk42GAhoiS&w^wg#juHdyY?5zGA -z80MO5eidBUlNvES8%{M#T`b3&u)s`{wp<5)P7IpyI)(YNIB@#yQh##I2TK}Cg@)+1LfsCLJqS} -zCsYw2#y#K-OyJs`8ajxI0qegCie%XT2VK$D4V6cRDGJ;>MM14D`=-Cnhf3Ivct#Ur -zWra}}^1w}%W0Y@BqPcCMqXM*4)kp_6JsEG*R2Lb_OyTo*qtz=FJrGVQNniL~*^diD -z@6@`;hufGD*X+EyD>xHgqXMMWS%b^?N577!qHnFht<*({g1f{#(T2vA1YAxrl?#)% -zSw(e&v1oum;ppaJ_`WX4j*bLa5z!~9--SzL6izrTK{9a*V@`a@(S)J!$pSIF^V3YU -zi1Ky}qF}>$s^L|5S)R6(qUglqWovtazN_=HjrE0m&kWxOm}J2Dhl&c3-toZ#&SInTZkle@=3|eSHNd6vvNMO2IJ=*E)O>0grr~;7=)6d#D2Y-0 -zN_uvE>dDcH0{6~-yqM8mcJ0r6==HKYiE%}K`t4=BY(5OwL?Pv6r_Kp68Enev)fB^B -zua`Z!Owj|eRm4LPUn95`RvtNCmVn!?mz{1I^s--Xx4i7ndjekeD{g5oJ2*tNp}p*D -z;Bvg|dKAyb%O;?KGlgz$C}Sp`(3XBPJqaQ0l@BBL-TXpJM5stSv@ -zsh+S~-Q1eXdtMoqe$;lF5%7aA2IunnFyQJ_VM%jE_O|p|L-TY -zXuUI`CE*X`5gwT{A1@CNmYoUl7%xOlet;{pOnu@P23J1#PFhk{LfUd!c3vBp)6R-R -zx7#bSFD@Bc4hnz=B}NWm7#|A1&OR9SIyC~G==)L^5cWYA_74OzH(t{t#}THgz<9=u -zn?aNDBh6ng!sc=L`vXy(%katH4IciwmoofSfakdUb*%01*XIupe-hW@BYD}$gxtnZ -zj=(D2#rfZCMQcduCSY-=1~q}JQKN*y-Px83cx(fpjRIu6?ka%qi`8H#Z95(q1^ieG -zS5&};Jstw7fT!3;c9*_qVe?)EII*=3K{w|ztUO-Y5vrLbEJB!>0^^bYY?Kau`5!$Y -z>Ty7r~yKb)PEa*2KxtzG$dMv@cx -zj{%l|{9CZ?pE-qL61e^wKpXl0{XVXY1DpyQ0uN>2fsubLLttAkfs}vbxCkM{KIi~b -zI|7f#0UY@+An1cG=pV32zx@-Ys=#>U|DaJ7usQZm*gP(KRita#hNA4>!`?r48}{;f -z*z0&Nn5B93*%d|pdD+Q?9L8u?V=~i~|7&H?TI?TK0`gytat8L#wv>O;5T -zBme!24S{K&;enC=k2P?m?0=_+KxO~zBfCpqM;S^)m46+AZq9C4dAwvm{zV8gQ(!#u -zzxyr+)Rn({8VvSNd}Qwrl*+FBGsoEM~Tvy)OT(a)l_ -zEC0@7oMQjIsi -z>du$ghki8u5ySOTRMY+(w+BXPq6&K(cSK}b)ulOOpTRIQ0R0T1bGguiduk3Jj>%!A -z2mO7PA(n;zHq5>*w&2Z8zj_PL^=kM)f9X^*X2y -z_~hU9HZ<-r&pN+qoH3Bi3##VM(2HwJGLlaUjut2~mSY$!yEpW$mCaxzGR#U4fUKu* -z#W%`4oLj@ZF;z(}<&3mLV+@L<`l>AD!AyEC}$+`3tSLW+F2~qk~5%%u)(M>)H}uG -z-<1^v&XwAN_=EXR>A({~-kT{6g0py2KeUK+bWO2j5Yz37ANd9ath0XJdzbW+Jwy7s -zWt{arl1TiMN{RJzskJ9*ZE|H5lHBKVQ0MU|-LYGDEStcNr(L8VquJO%lvX|)d*eAs -z&e+(17jYG^u??^zA>FdE=T>SPdjqLK+1UNR#ImvMtzctQB^@|6b|;!E8~c8X@a2q1 -zgEm$lu{jj}{em%$#7`_iP~Ig7GTQ}dFw6llHg*oPme~L5!qj=)fpKkY6M=dWh&I*~ -zF~`_g`klDAjEzaYQ#SU;<`_2CmmS1O2Ob-11JOmZv8LlKBB^W;OPH5|0DmZ_KqSgA#h -zjU8MO%f|9UpOL0_i@tOm+YW}6jkWzv#2DMgcKj(k^*?89EPj40xqnO0<_h$xjZUIb&|enc%yLkzT}{hnSh2+I9poYdcZ{xyD?Ld&qStUyTFH&kEq9N -z@Xo6gW_t5n5Gjs7W)kP>IenB^q&4bM^p=`@gbV7>W2Zoyybf@mK0qfP=l?FnV!2DX -zy59neByLjBlHADX5oF)=zgoV5O%Tt(S@1vgahMv=O%*m0!Vc4{A#(s#b<0$i%9962cB^l -zvYoB>&Hjc@vtbV1FyNi*esUVb@XqpVzvQHFOz->%@yK}Rp0YG3H(UF>Guy9%KDu|V -z+bwc>ikPX(zH@=h^3EsZ+T)#V^__rsrV>|i;-Yx&+YwDX4eHz6D(`H{rhoi>8SkuF -z6v+JE`Nl-K>GjSH+m&p{&d>@$)3m(vH#o1?I~$>{5x

ouM|;r|q2u0&R?UR=)-4 -zuG%}B#4G5l_s&yuKn%UJ1Coij)67K>ukD?o@<9=354#=Xa^s!NFv1IZXWtTNObSKpK-yS -zc+SNZ9}y|dZ#dF`V#xN+nJxWY{Q@%$g}dp70q@M7-``+78&q?9T8I)j*i+$ERzqdy -zkFn*sC?9JHv?^q -zonKt{Ke6*;%l@Z!9``+np`G`ERK?C$Er4`wJ3oi9Rg5gus=H<9i_?K1kcDb#2AKKn -zEYuLRMs^~MxOQ&WPqgQ>ZDK*U9W(a40L~~M)p%DvJ(N3gY?kmFw|GyEv?Yu8=E}Za -z7$}lznFrA{B%19<1r05D8PpcEtNMY&bS)cx#)hm=?nrcSOGaUhS39x~lL4XdtAsKe -z+?Y;UHAO#8vG-0XT1M)UT*xRgXM^a^vd?iux9+?9Tk0|J#{45-~^W2=Zb4MXe -zEBMBr{5l^ab6SU?QDJkf69=Ju_RNKEWrNjaPRUwq`RB07^ -zf#*&aR~jXaW(Sqgfp<{T^<7IV0Z-||R%Z_zPuT~@wmfAiEz0L9?)oApI}|3GZ;6Kb -z>(~`~3WV;{<1Jd~V!IJE@&2C;=_xs3?XFCKTGODh3S -zxr?pV9yFeEZ#|EvjQ>XT;PaH9U$s!u;E!Pth3{Vy4Lzk#59lf2DJ^FD8-CA*t=N#B -z@_PwC$h!oo=;EG@v=_u(5;pF$zK7ZJuLFj;4{cMrQwEyR%IU{SmOf -zEopx1`wd`roGycI?KpiSuA^GtB={B1e+9wZ!yO||f7$4NY<;bW_~4&@>$?tW3RvIi -zCwcR7)>rL*pYZTASZ9r7$2KUo -zuv`+Kjvo{!=SJdvZevUsM5;9qt>C1^0{A98Y$2Dt_uGY9O)sw8h7VVtFCSRWi -zg8OgMk7wbrs`Ez3I3_r1MYeP4tQ{#pIw$X^Avuv+iWU&MPh!;PNbJa{`b86O?Lk4$ -zm|I)`+QF@4y(q)`XsLOfLTGDiT)c|cEdBVEX3WLxw-CSFg_g(yNB4E62zZlMQJufW -zKYSIH_#M0FDP`XF`945h`39n)OyQEQxoEC^&4-uuoW}N}lSk -zh~?5|05i#0#`3i_2ii5X0CSmH6>4a_S -z!hZLnCkiEiQ%0ejf}qJj2Z58QpJ)5LY;TXkUQMC&Xn@uyTk8}2_q~e8K$L1y)Q`Ua -z8%$;c8-Hy|P!A6S*8Tfhkw72a4G5R!K)?I~kuKFXUbtjJrSa+dx^dS`mt-D`sTshV~=SHDk&*_e6jEk7o -z-2#zJ3QH;9wRx_TL6lhckV%epH<=O3y5laK|1UDBg!HGIk3e(9`;7U*yU)6tAa#Vo -zyZ0FD&bLYt>#^?Nz>aO*W%>##k9GfxQ32LJ5)rL?LPH>ej_>`{F&<;x8wlIeg-wQp -ztZMXbaOzsO_?wBC^rUy#z5?6Z)^{v#RO{|a@C&kY_N(AZ2YZ;T95(j -zzVM4k;62?9I3L^v5@1NAb$^OD6Vu!q2O2car -z(=F>(@v9rj`gfPn@bI6dJDruB_;s?TSHsnk1eHg_#fWGY5mCeI&_*=eqn{%dqv7MQ -zB7FbUg$*N*SsH#|qOIX!G$(sfX*%0CWqVr#&mzsiKm74)2*HbJ9s}{~b`xNo_}H2a -zB0EJWHvSziJFGa6WeB-206Ft{Kjej#)IT99pL%dTWmqB?o#B5Y)N?M>y&z6pK68`1 -zik2j4?aTf-JkMwoCpRRsN;7M4z0d}aSyKK-sfAcwSIUbBUpCtS&p>Y~f>rH`$;h8&GStOfWOP_yl1tZu8sv`W}94_Y(3~LXv@u -z>l_fvf^Q(yR2OPMac#jJqg(JKNydH){`C!G!COZEuPpen79IxU!c3sa*g@+&0xR?nkmwdXy`qEFwcurJ -z(}ieh!8NN}7Cb1wWx+ErR*Y@IRdWUTdYZ^{5V@XPvW>pLV2d6yS%VG!AA45ve3^@?%NQIAwe2qJd<_>JZk6mqmC<}goVNxUvLLexixYXiO1Jnp26B#nj -zWZ-P%LS`(IG58{e`tC!;=5v^u$r~$IyIb%#sE#-+*!#G$;Mb6y)BPI8;D6D?&L2|c -z7(5kNtQK5wr?TMNZZa%5#5Dt}1y99%P#$b*a&&wXoo~<U+( -zUjw@~R-~D|$y^!V9k@I#b$0_*UgxWxIrO+$*>d#V5s&po95Mtk>rYsUzaXr)7n1bo -z%mh4;XVodau$t}y@38OEFeBShOThCV?~@?)z;g%J(Bxi-RqxMpmm!WW>A%nfP0^O3 -zg8na$G?lwGoV6F(h+9}q0_-3sYa -z_*gvV2WK|%DUu?be`4gU_c}*u6fhGnGDtduFcTdbXdpuGcQ8yxhOy{9gf;;p4~$CaIa+U#YX6xiGksZa-lHySur1>HYoGo`naFEQ3kOuk$ucc -z-C))YDFlZ8Y>%t7_B^#Bbpw!L7iuFK6x~!6v1uKF7c8EC0%j<^irDQD@T{tcEpS`N -zr1xUtMAaIY>rY-Lt^*tGT(`Lru*NHE$h%=86&`s;nU*h_W!=d*;u!~kNbGOip$W~H -z=)}@DkD(8fBLa41K5+{m5}UE~-2=hs#f=6-387`_>t#eQykjT*oU@FviEf9+w!cIi -zU(elGW8W{r_@>5wz~n>9QyQCH7x$IMI<})NY~g_ -z+!h+U?Qvqos|(hIQO-JL*Ja2B -z49Nlcq(lQmQQAKADJln;|4gW!h>H*mKBaBG&5@G?8O~nCKW8Fg9;hdNoV%{k?W?8bDp@rTJ- -z2O-{=TK%ycv{|*fnCBqY>Z=IN4y}%0%)9<=*Xp(&hRT%w8FC#%GVwoQnlm#nnKB*0 -zQ1_cq;~TPcDk`^`Prd6}{d0`anx&fc$b6;M0YbX5Y4unc99XLt{aqDatJ{!9Xj=W| -zQoB}5yDP1>xyI1ywGX>!waN3O)g^Bzt*$>@)9Oq35k{+@pz?tEk2+elI+5AH9L&DD -z9gbgInDajexH51Cqps)V7HGv;O{N%QtpnT9qKKXj5*xBlGi>-CD0IbB!?vH%!| -z^a6(adXF~nEHdHOd$gB-t?Lm_7w|fMybwc#E;vEa4Tj)SnMz{{)#mRHQMtzRPdp@> -zh4hS8axB7czW-Ekw~+gE<38-nC!HY#&T1ctxyW#1>nbCT@(MAJlW$?93Xe9`3}m$5 -zyso&vZko=0;~Q(p{ptM-?)xrO17lo``z^@Ou>ZwF>fE?K;K%Fr*crLF&E^%DwEvXEP5{7XT<2u8{^|x2U)iW%vZ{h1EE}31Q&&W2vMgn2O -zs)PP?BHPHOA0XtMyKSY2e_J8NtgV!-DQ{i`1%@7DhTzR7I#cP{vqdNLZwaroq|!ej -z2y!aT=`n^JCl;18?M%irCu_@vtCVn+y#PJFF`cKr&c9!TD(L*U+Xp+cM637-zD;N&Skx -zV7btr%M>^`XXpZkK3r1Jqah!dEA<@OtZ_JGQ9;pWs_-N#`(po%r)_PHTr=D`tu3}ZcuPCLq8*+ -zv7Kg>>0EvF4jthACrgOm>jk`3rqli-bZ5%6=ag_V9f9K=Ql<^zW>%Tb;4xaz7PBn5Vv_Nz9~3;0%{o(%u-DyG;f(MRU9l$uZ -ztz@oArbS{dqCayKxB-1CLq9K|9loEj(?D;?^m`;kIR7W$tulRGt~E?MeXe6TnZ5*N -zNjn`%RToPT=0rwefTa*d;JCqByB&7O91GT!Gc -zKj%8&aO;OuyW(B_jQc! -z6V&5jk&x4$j}O;THrJspc)zN8`yT4DF7!3l;xhliXt?mMy3my`$edyT=DE=G>Rxjq -zt*TDoh-p=a1v>2*LnG!wNa9H(N!p`W*}~)0SHzYl0Y?dNY|o~*Tcb-S?t3~mCp -zF4L*Y1=J;8b~y}PBu&e^fe3!_sT{B~dTSphdwsG3z1asmzhg?+9-^Gczvr^i+WO{? -zM@Zkdy+{_-kZ^%$>62%C$nMFp95cA#Rj+f8E4T+@rT)HaX@mXSNcrx=0_wFLnY&N(Jt6z%^o`FGi8%#<7jvuboZ18FBqS@dstWEVU9_sQEbun!4T6B># -zC8gMG@EP>hY_Qiv1=@hfFC{!~HduzzLwWGn6)rY-AN-YEgz{d^277Ujt;=N`)W2II -zZE$lPDSx)X^<9)=3XpKxZLlqG{#i1jFHsP{{E`bFcc|Fj-}T&oKA^0WNK@ -z?k$E5Zn!eK4Sv%=H<+=s62_>FZnN9qsUJ9OFa^NM2JgK{v074BN7+P&>hg|hgXa4% -zdSW!#;J=a93ZsnY3sT>`utOPoQr&Apq}gon3Y6+CHh3QvIl4hT)d4uh0f&l%=WrLz -z2J>xQrcjqI)WxvDs_DwGo`Pa6aj*k=Yc}{wK!MWpD4`#(4r7BqJwW=t={Xl0Jmp}8-^X;RcL`9Jj?~4l!JmOt()4Je -z%?9s4Z_NgmL)#LRo+k-?J0Xk>Zijl2|1Wj1!D+zZVuQ=M$58HpIH-R-QQBbDn<9XU -z?-@>kcSsvN9a^==!Fy3~AGNvoxc-XH8%7D?iPt`Vq(eRNx@m($P|FfF -z_#CYd)`hyO3lH%Hsl??FVyLCMHxu{lHuyfswb)=b2GtGfjI)5_Gl){z-~-%6v%z>< -zmtB~ELQhZ^!v+h{MbdNz%@g{XOu#;AT`_*xn*dvy4RRUvt@vzkziS@?p~V-EolWDxxk^U -z?riR&S=~5Wm#e5tC+cEY-5z8BlBOl+*sQKSdTUlk@AHtL*AE4r@2?DFbw46Rp#J}a -zi`AXH-ZcYU$vrOS9R+w1BnReXT;gWc+${?afbmGk8>&cg&wo^Mg6lCkc3 -z1+J_vg~8u@oI|6ux(cKw!s^ec{QS>2hb -ziq(%XxtJ&y=uoe$F|95eE-9?;4U7h>8>TL-;0sc1Zw`jqI;(pNh%}qkg-~v{Slw9| -zRF8FCS^~$s{(mmshBZVRhG|i=?Rw5<*L?dmg^b?9!g@g#k#)SxDaZFw2f1rs6)wtAc39HwozJnsv+G(rhL&+P7m>-a_UU$vQ -zo<`Fc!43DxT;89MzuTIDLm>17~5ySDOvpv6AJ=DTlw=I -zth?|N-wR<0Hpi?0QW`7S29DtGs>%&L+!`SvA7ng%bLG!pX1Q@6uu-}~Qd%FBYTVLW -z0I$1dwMSul*cIDE8@4Ybw&hrXa(5WkT6}oE9?-#l>g*Ux#$q>z88$2p@gZE&$d$k% -znc0jv2CN>7pVL-%rJEV&ks}fE!-Od7-;b8=^oKLQLipNw9TJ%47p063!U_rquzf8h0q;L)pS}w;0AZS5nV-WEx_eazuW1E&Zx`GFFiB~ -zRnH~Azw03xM;d536VXxsQWZzqVJT&gBfouYk0VbpzJ3B9VMxM)MaGf!4(M`*ZYD=( -z27*|!IO52q4EOWGe;P*~LH->nj;urN68eYREj~MX9O;VvJJKY$9P|cvw8jw~N4Pk$ -z8~arf$766<=iuSu$V;MQ%yC2~CR`jDD{xxl$eMC%9C;8GL@kb_BP-J4$or^Bfr%L6 -z$VkScJpTzy=uYm##gUcRgo+eLE_cNiE{+rdTjV&ROD|j;X$ve;m2xdZ_J;P+&u7TZ|FTPIoE~k(xjTB*MS1WE1~rz%?{$Zw5y8&p^+KQ<<(gu#{DQob -z*`G{-uk!+O6NCygrW*}`U54Hd? -zGw~W*?QQ%&A;A`JN?(r3$~5(LIKjhU?)L4y#I8ZrXFtW -zCiL+6R67p^^3Dl19){z(-Ikty&dNiAfKj$|WfO-U&ShfWy~n{rDynLNhw&5bdhmu0 -z<8Jq$8}lGn9J@&kQ!-TAa^fB3dnh&{Epw_Cqvk~1aot+*4EyXC_JSVHfizx -zqxrgqX5rC!dbvIbBd=cT;Z?woN&Y*N=(02%w;)1TrrNfjiAAZHqW&5<~x*UOI -zMr!RZ9AkFs@;8*igf4Y-;dI$RpmWjXXD6AuTmykPba@G;r}E%Wcj>ykdy9w|S5C3( -za;m)ZXm6`7$KtwOm%W~`>av%BQM#;qoI{syPA6h=K#Wb7%TbUM2KnDohc4%FuMWh5 -zMVBop*D+>ZVY%ZNw629)<9n;qP$#rn?r~j(O}~I;ls-?j{lv-b@TaZZ))z2}+Y{m( -z+EQNc)XW68jV#;>9vk_ -z8$QcZ9#x5DFg=bAwwhkTYz>eNVV8}!ySw6%|Z -zH$x^mATQ+kFX}&BJSc`_ -zC0r+p+{m>7=@k$g$Q7PMh?~uidE=RJF70gnjQVVwJ^X#+oy5&vfOYJoH|yf{5d7jr -zDh8r+PZTxyi@`w334GjU3?dWv-KP`gZ3OoQ@?VL)1)Pw^!_{8R=uf6|(uc&vZhumJ -zEA-C!Pypxjz+AJM1Org?l>j-*8stxS%s_0q$|2aC$)klxk>aXuxF9z -zDyY|x=!0IyL$d3OEpI8&_Bie*C7Mu8f3hSFA43sHNwn{d9!jD|qpv2>og0mxEYa`( -zRyfx9jqo%xAJWXePM4-(u)_YaOIsdXJXZzHJDVG>V%k5F3E000Q>tJh*gtnlmz~_S -zb&N$@)$J|XT8cbb3gkJ!xoC^(DOUU6Fv6~_k+j5g)7EjtHf_bdXKHJA3#F|z%vVxd -z^nE|6tx9;LB(BYc7H#SFe+>F++FFJFn*9#}4$c0*=xJzd^Ek5qYjurLMDd1lk>$Yt -zZ=tu`hRBrKL;p~w3?P3WVF-|Kc0?8<;dWD?8Qx%afA4I(nIEUF=|ghpXw1TEX(`9s -z^RtKIMU@1?y9J9;z?5%mzZK$<*lxg|J6e-X@{Bx@ezKSIu(>2hzHu!0FkRR%I!kLr -zOK<3AWIyG>Gv_GYirer!EO~2*qm3f;@gSAh$&%E}M4}Ukx0x$A0%BMzZ}ICCZx0Vr -z*yiI;jkgN=Y4SD&KLu}zm{08IrQg83RUXWm&2x|Z+6!i2dRsZ^sGbp%JHM^X*cNeU -z&LlKGfl)RBO37^sq7P%^)Umx)U*+^g -zSRLdy8-OT!(R>GJS?6tyD8v&1Q1jIK929O$1b6ey$Kl?oI}Di=&7nSXSXl1h*(ZN@$ic@?!dHc)I}A|!1vLegV6YaoO0oVD~Pi?SC_(>z*J>+IQmM;8($&ySa*gAgTm -zIu@NY$$rjLrr0n`$KRn2la*xQn7r|+9ys@gK0#pu&;QS2yC(MEc?n|pc_!Epw!kJk -z?ih^0e|dn?_Tr$s7)1i3V3;Xq3L9LDeL>|5A`;{?Y<-4}o3^J;pgsPXdN}qCkKN&) -zw&$=w*J*p|1_tc76w!gGc@?==MP*l7RmJV-EidNN)}Qglibgcp;XB&Q{43lWW+^beqismwgIo5=^yORUYMGW)Z4CXz;yxT&o>}^yW -z&%GB@Z%YNri`6pCw7g(e^n8QGKK6fjEH=m^VTdRuP~kSwtQ|Hx7NKKW?oTiRnnkAl -zvRjzLDZE(HAB@jyZSVv0U^BR$hd4zHL1rQ!q5n}VJU|nD7ehSpqCKrOfV*v*PEugX -zijLPX3k+I(+;@a)V!^?x`2ukF9IRo|i`uC%<&B9Clkx03K?y`xT<9;$%LZ6IwN~nY>Ia*L6 -zC6tZi)h?l;p~LD -zl+89I)~Vw*k>=U0WdZ3sm7wk1eBpfb&e?m==V -zC^EdQ2@kQPob{|hp8kN$Kis|TQ-nO!e?>Qv)J0gJD9ko*Tgt#`CUCMizDND?P?V5n -zJGir`l**q)IE$ru+iJ`t#7yNCIE`b}B_}!Rl3S>X#9F@vR%-XQ)=bGO*D<%!mQF%e -zWVfX=V3E?>?z#{D!>KT1orUGD)s~KcjVN1c20dDA=}5jnoL0jM&16A%{~ah!lm|O9 -zJ^Y9%;6`9sZ>Oj7SfZy1p;?3?heppEkUPXe>sn4Av{cepC?vw?~AFo#m?trt%TuhUU3UUx8bqa&c8+&HH@E*v>g0)2+2>`bK$Hh}PhnRk;u@Vz{w2%iB-Z#)7lzqr!rTMIjh^puq&O&h -zk{oUZt`dfOA5>O%fhmm5Hen2u!We>8Eg|685TgD|z$E+)l*iF&BeV^P#o5C{!Z%ea -z(+b%Jubw%itV1F$%Nu9Y9x|H_BW#YJ!gSVPO0riLE`=`3gFjy#%|lyX;O29uaPMW* -z+v1^_Uoymio -zE*O#?`UX~&_3wuig`7DTnsKD^&}Mg9qTx%ZlwurbG;E2<#FY4S46b=-8GZ^eUv_ag -z58a7nb$M{cRV-{$c5x*}M%#v#y=d>pqp+HXULn<)MiJKzZoTKRG@01wV;w*kt9Q_v%%1;i2;wrh^Hy$*t -zoBNx>2RbrVdv&9biEMwsi=HN%hNMB&(c>i*C1>OW|Pv1B4Z_k2!W{x0RiV9 -z1R>ISUxt-v&dcx7T3?@BEROhk>oL+bj*71)=ay#M0FoE=khh1?Ao?4(#_|{*F@`44 -zhq~AVN->3NRW@n0W(2QHP|_NQgqTbO)Oy-J$x&GOljQ!=Ftb4C}*E| -zya0bMa!6|kEz{V1>N6u2Y2BMe((25F7>VB;7`a_q^Xt)AocKM3?181VkqEXXdke9_ -z0gDoHy8~(`n$#*;?GSbf=ZrR)bp@wRb#t|TIS%;HRg1;k|;C8(6rd}aP -zY}GTCzKn&z)=&V#vrTx&3|}+WeS8{&Ha9^Zh4(3$OR7dQ(C;ORsuIH2)u5`LovKoV -zKRZ=TLQNUV(~O0w8VE2@1vU~9n(Tva$3hR!f187T3SF9_xaA0&DCW>i?hwU7#?s9k -z^wHmVP)!sn$DPQqaVG3NbDd-jW1t;ZDp_1i2$d}MpfU@mFg5f$P5d^pnuHoMmWLS& -z%VHzIge+R4Cah$^vHo+U5_tZXfU(DhIZ~GB+W!}j2t$Q12Dm^xRu=STJ^Yymp;O%&UJ#kzUTbQ;2qGqc`d~@MYzy)3+;-wkJdJM8s}`h$B!UXT#sEE#0n1 -ziZ^|AqZ#yyDNr1UmOoV>&tPIZuFuMZ+?9julhnU0r_vSo#XEs^UM>T -zMb6nr#_(d#biGX)Ona=TTn4zUm#-3{DcsR~8J2<`$sj!pdo1W4+-q}ZSoUjWw -zbdLW-VF2s@B0I+ofFYueH=GrngJV3r>!6rRK}m*?*@s~Ck?Rn#M5>&{ffO+s!c -zwua0le-5sRn0geJmfE>hUQ0cIGD3MUg@<8RdyU-2T4%q8VNN6%%j)dACWOzj$Q{O@ -zI|_*E2K<8GhIoyyWsi5G@C4rVTLcVhzm|6lTVqm_`-o2oSt}z$2-$x-AJp(uY`iigBMGpAhB|UWJS1rr|cGnZo|;*ij~-b -zbL^Cj9%y8S%lav)VulgQ8^AcWGBdoV&T)FoGV=c$po`au4+Ziq+?m%gvJUE?4j78f$ -z?j~(tN6P|pd-apepc0F0G2b8?b=UUpUu@d0d!tp`&mxSGpr1f%7tMuC=qGtXG^PVI -z!q^sFhR)fkqF5GIUG^w87}tb6dYi+j+~kwtB#!_O!(R0{Y{?eImNU#yg0V!gj0^)* -zx^H~wW(GY|qNCT8M~q^Pfx#NZdSDSEqgbce#A&!Fb`tIiwhDS9iuJoBd=&c~qagp! -zRgQDsGe)Ea;dZ-zgQ2q+niaf+rUAQMH$dnVcKriv)ULc4jH88#<78-FbI7BxGL=#6 -zf_WCZF7_z9o(B`x%3C+!r(l@AZ)P9ycph=_SmH4jyUx9X>^hzb1*Tmm%>tE%T|aU= -zez+d2`0G!bUB861OpjupU^9X2`aQIELdPK|D-YIXLfPQ{enUpFPN?cYC}tGfHp3#c -z58Cj3GYDu=Ebn9zjwY>3_yQ3z*d)TJQ4S4l!&<&Pc+D8$U4U9YRFK>w8SNT+_*^E# -zw{!y!bf~Z%U8WK+&o+w?xH)x^lQO>_|9JS$?9_K?)IC4(ed1?$Q*>%B%EwJ-58sMk -zO=b^&2TfeX@Fr;J?Gb47y6W~l5TXpJlkZqtmQ);_wdxW|@Fv -z0VwV;a6jA;*3-SG5TmhGBz<>iXd?;^<-t6^l1aw3=!1b8K7v-4$<^n%%H(zgZ--2( -zu@56Pd)EUR%1@luMS -zH%8M-i)5qKo9#Pp+XpfKj5ZE7ZMDBE>_u&rDLl>n`g1=PbQ#lZvFh0j)0$u`R-JN{ -zW*nr3_)r#u{&_`=R=sC3xw~%FeSQ{KAieQhB3bny+!a>c3+51NF*LkYzlF6)d2oy* -z3YcmCC#+T9$Ix9FnytFm)fma1Da;`oV1cb=-!`n8L&YdY@vDz@Oop)f2q@JoQulm- -zV;-s5QU~^iT5`{qxMwV8JP~PXMP(CfBHOYd%+E06R1EEI#+T80N?*3j$Lyw?@pp(h -zMEzH2r5PJ@ZCq#)OsYJ1oS>8pPUOvpV -z4){A}uf{ye6Qh+R`(SxUH2n<`T4t}62oQ|LI-_rfJvnBto{)*0y;@^UMcvr2D+V>i -z!w1c04+^1aI(yJoG)-m?dIwEh#h@l=8deO7Lt_vgdh|t!o+s)T=Bn9i6=qF2qc6l& -z+w3*h1e^yzZT6agJHo8<&vl=@s*$7O{Wq5j7lSBD5z1`y&?gKNFkyyRU_{7#o`Hs# -zK>hIqAnUFiS%!!~QmY$30afN|7TvdF -zRgd|PV1*-o4gIQr?fExNIR$WDS3!27vk}qhtD} -z03J5S2jQM1 -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 -zDgUoN&TOPcU$KcKb{~J#JOBl3|3A$;t -zAyg&*Sq#&XU@Y=)jdG4%{+BcCZx<-`HvOf`zpjP7Gsi3TzI#DuZ{P$&{#hvVYvv{7 -zPoMV0`kx13{uZORDgU>#(HrtV99ZP^p?F!zT`xAfZo=FL5m!`tF-4e@G?EaNeq1}x -z5Q$;66B$dKz+&wxpD-MW^-cZz;ZdZ!LBb*Bt<&yOTqk2e#>cJjx+r=eg@A{a*+)B) -zM|-e4$&^9vU8pd$bU=TCf&k9Hn$SNkk{sfDc40VNaJzlXd5oolz=HQxX~SZDg_x3+-Eb5=i$`01zT)ucQ3^v39a=ik?`?_4xeU)Tm`YuA5^$*Zwg;iLF_-6-i4R{h3lG?u@hDD80}4(Mo{YIUTGW4upSe( -z;xdCpWqG|AW@|UQ7kxo{8OAX)$=^u~yOdx>y#Iuz6BWf)ZqoVdh|Lpe7|Tx5`8!lPV7m;6d1|CZMBqn5WGoOcFSO`!+HO{EnsvrGVxZ0!LGH -z6qb8DQesm9exMc#xEe#-70{T+c;Y-|6wlAJE5Pu_Z!v3@2d^_hj~?lee~@8D5sW2@ -z6=xWr<|KJ1!^Sf{wy*POXeIyiH|p~L5fi9nFPUPwvacJiG}v2kqJ=#n|3n_-%@oDo -zZz$fF^3SF02lDR$EcPh&J4yzyf3xe+#v-b>Wf7%Eu@zXdDm!DZdz!KI7g#DP^{ -zZ^uGi`S^_>2z<(0msTpJ7NUx0k773!+ehogqisD`v3n;RTgq*e1NsDpe$s@VRbU`g -z9`zH}N%;P^3FCLdyu~nMOqiZdn8z6ALKEgxC(I0nX(3>&S)Kf1?s`nnEFOLXXv%Gh -zx%+aQ;u&A$;N}b-;pMJMK95qo5pL5>fx|}0dc2|CSh%D9A;6_hQsZdjo?e==c%=EP -zTez<_pM@KK3rU#@#R>(kY_OQYj}+ii9Iv7b -zCv0%Tfao^35H$=_5ob;oHux6o*lL60UxO5_Uv1ulC5W=Y%Qh-Hci}k+6Xm-))UShp -zWse6**}Bl(e;Q_0jnQynrn>M0Uyw?y^D&f|ukO7|q}gn+1x0<`1~12;`a`k>OMs&d -za3~wx0e$d8=7tTnvvoy*GHV|4uc-(C8 -zDU=7wgZ+|SY;X(wmBeVX!E3n3iQEG=sMqYI4SHZFEPsxJjZvJ!FS4b+NXP9qm_5#6 -zgQxHa%aT+ayv58WlNGqK!JSy)p$)S2Vz6pj%3mgTrkM`mf~-KaQz-5-S|?aOGD0!BUHzmO`W)*bor -zOiVoxgDn*O%V>ALXw*aRMOdE3FO#6$MevZ!-QJ34GnYJ+QNjow1~swsaGAU_4Kt$7 -z!!M;y9!|6I@Q#2{JbaGzppAz|QA8*Y_5d+99u{JODr&l0;8S)Uin-g779KWXz9SxH -zVY0UBVY$5X$|qJHI=b+1S(;T3N85Nf#mU3hs1)G+mmM8EOvTzz@Nj~IhoPax+$|N| -zC``G14PnR{vO?o)AU~}K^}PMJme?GYPG-)3E{D^TZfsuz845wj_hieLiqBas84tl#AVHMaig6n) -zr(BBiGv5Dpj*8%)zCaddd9J1t!@O<6ykLPL9~l~oW1z<*kehDkeUYYaow?w0|dcL;Foq -zH(RjhE{U7-okchLcSX|CSJTZ}VAXUp&&0vc$Mb=Z_y*9*(ajxN38Ds29vszPX{GN9 -zhgR-mn64(w85S6!m8%%&cnRdDl|k@0Q!CYEvZlurBM*{{`zN_-r3FH`RV!Oj@3(r) -zi?@c+%IVu}TG@z0Plm@VLr9iZ|HlXPCtLinedtfN_FgC*O5)n=2&2inUwz;T-D_NHRdHv{sH!6$p0_x$(IaTcUn$wy|v7c|1>Ne?DB8M -zlswyp*_HA?8cDTCG)?)Rv|P!5ac_(K2SG4a`JeZLCjS=yVfmYnDjmZYh|^zSX*TIs -zAQ>qSwi4uM(*LMuWa+1Kzny0(gI@WaI>G4^gs6~>EC{fMf%S@W0C&z -z*g9hC&(NeF;B$1k^$&U0kbZsU*4UsC*1rJLb$PIpphQZ4_Bf~X?|x26e>4e~^}^Qg -zDx~;9mbU1)0za@kd)O2uHxAHJsqwnvYoRm*aUa0 -z@W@knaD<8DT~zTk+Utt75Mf_IS&Dh$nGNIIz#dJQh$wbyJ5Fw=rs(@hCRCwBiWCaEc&-$ -z*n=^=-ORqhY>Dqbm^khxpEI2@MN}n7`9ns5Vbicz->sBc|4WNu|MrE!@K)3(?IV`* -zhz)tfSPXmpMP%5?*7FXP$i0}MMz)Cg2b*Lw&Gv3u8CToY#4$2tys*QY2yV*j6q;ki3Oxs39_7Z_$3 -z!C1VD_RG`+MO4R!<}m145?xg9T8r$!>RrPSxn#z95>_YSz3Y!h47Q5?f_L@DMrOEo -znEiorLV55uuTm&|uTK$f_pUb?I)|azyQX4I@9?f>(+uz0^{3LF3^Lx(jf}%<;u!xe -zaF~XY50YiBlyC_cHofb5xUy8{hcFN=N}Bd^t;>if@Q6>IMm)yiUE>CWg33wOX`^f^ -zs5GXHyGG!Lt9O0&y3M=3$7)fZHa^8lj|}?*wDvHNk0oSzus##Y2Isk6dRG@{h0+oA -zRA*WWv{m&M5i(ZTJl`;&ub^8*- -zW)Q4MBdVc1-n!+-kuxbfQhVpY_mpD0Qqt;pMxcPP9nRR8{inO4hx;yhPlo;YRAsk* -z<(sfHNnUdXdX9nET(2O6wDrp5twG9XlD8Z4xU{>wiEf=da^SeoTUa3B{TJq#R|3x5 -zWIg^q^ui|VC+Q?8YbJObcRkze+8Wb7$IZ)MWvQ5&ZGSG%n3{dd&-ZoBN*`GGvBd{& -z$4?QR -zS@oqBk~r4?bOaG{(+$@LIp*1bGp+veT|ft`|7NJJW-(7M;I5s_uJPAMs~@|Hhc&H!49&!* -z)sIEgw8b-N^`CCBSpD1hDU>=L=3>hf;zG@sf@e=w0y}n_;`cpX7P5ryf+N?4)%SSV -zpys#Tx;SiBKOKv$^5Cf^Rk`RVW6${}RS&|Q4Z?-TTJkM+YD_J@;{5+`?dk{8cFZ!i$+v^ODCR=;_%PF@2u*55nP -zMxL7(4UhuQO#0S2{dj-AFZ%}tn-t^!Pi -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 -zbW$__tjYXgG2pNR|9^9StI+}=AwJ3i -z;J}1yhY`ERk9|~sbu%EgA0!%L?<#vTihcY<2A&*I{)8f2UN#*Z76;9JVjrs;@)JA@ -zkWH(R4CM95@5_p@hvawcgSDYeB~*NjWs0?*5r@Sn7#$^|Zj_f|niL%Yp-9Ji&N3I( -zD*f2mBTDfEijVi#_9fxc685M5DOa!v4>Y*Ok9`wA-G`(h~bHe>-KW@VxAp3D8#ikkY^ANGGung@_`?AM&lHh){FSp_K@%LkVGD$f^ -z?8hY7<^>x4BtOS~F;$SXU1eF;Z{tgyBsLT&v#=HnRa(Lu(7X+c421TBP|M67k42+c -za>^ZO9g&f0MBXn$vBsoH&pq6VWqZe8nk;wHlZ5n`wviddKCU5V;h!v8D&^vdX;+U` -z`#xA&ji9Y8W1nL0=s&3RLoC?S8bdt#{%Q^EFDCs&9M>SgHGb`n^%+qYz3fO(5%y>3 -zws9UH$|6B58?ZDG&&c}N`54sU3b{9y9CYBp -zi9>~sG@u_M5o?8tPF?@`dXww38Q{Mb3xvdG_>f?)-`Au*NSH4VKR@of`k&C;zOVVw -zI8k?S4!Qj^Aw3rdQ$Dd@C40c)qsn-N+dKEoArEtMR))zXfke|)R -z|7X@2ntxaeGwPWE<4hr$MNQThx&Xs2@AdgbtQ_T1)3@)|A39xL|Uua_x{RXS$q3FslqU}T*@L?`QwnwUxn?bIi6QR+Ik=a -ztJ#lfpZjBfQO(J*<)>r~;nPywJ*2Wx*0lTDW&aw%L7#FS68Yu9s7@Il4;BBmgo6m4 -zZh;Hu^CR$*?VkDhY4p|!5&#}yO~dnnnRrDIp&sfl!4cg8`4FPHN$0~i25=Op6i*l` -zc>Ad+{AM^1o&uLfztDd+az!%pxg@S?t#*3pD-jul&*C -z!uz!VN~wk|r_}g2^B-v_dJSv@zm=-Q@%{z8Sp<=Wzp&8FmzvM-^W_pUUcun&BhMNc -zd-_tsSjRJn`FxtzQ7>Q0)W|@i;*EpS10Cs-%se778RfMM$s#Bw0f#TY>+2(u&cRXN -zsKNVcz-+`rm#+485a!nwr;ITF5fq;Ioct+ShmA! -z_mtfsw|=!4O1MfoS;>Kp>>>gFU-mzHenV0BpnG8d;I7ysCM9n{Wk+Of@AH%`fMYPUBxpw}~too}$kNx@E -z1NMHI*cmci$1Z=9zx`1k4@Yr~sgR5E$dw%5FpltwV(oooZvKNuw;aVE)IuEJIF9LI -zZ?YKkGs2pg)y%$X^87_O0c(T90uH(QcR03SH)(E%y28Wn`y+JW#@6;gwfMJx{cms9 -zA7PwM-=`%*m(MDMme0d6aj2P_R)jsMvO3NFt@HoBd;TlDN)L*NV4a}< -z-%0ZF@h(g8v7#_XP_ll) -zYW{7VfA*>T!m3lFO#G?QXU3oXu|5k!V)W&iyBZ?YIovzQEX8T_^4l^lfs($P6)4Hf -z4&W7L^cG@c6WGjs65^x1RyvlVWo=ePY8HQLvi=LBK-+BMYG3=tKVu`v<^its?GO96 -zPj>s!@a;p#V(~OByV-kfY^K+yz1!65Ne?6@`O=GV?z9Z6cm779FR!pTKQr5(HkiMm -zsXo0PFOood6=s^_v(2fg>6vNi_>}g*!RPvXV++fC*^?$EB>DyxW#jv1MfrKzlT#B@ -zQ|-g=?fB`XVnBSrx`qSVDA-H>vtk{7FY!;_$M_?B-Lz(kjGe#4F2a6XljGVmsG8_E -zAwfI$)J41@r_`|b#CS3H;d6<2?Ph^5*PmbPFG~(l<4LiJN{VY -zPm_8=68)<_E}JU&t+{6lMbs93F$<(7`cFcnPbO{+ohKyuB=c96;Vb3r3ek078`APK -zJ&@4J7GKkb4vuViiSEbk(kSTFG}=X!zmxxDga6WEJP79h=K_d0zIA?qi5XvE74NR* -z(Gz2IG>g>DA7TzmrnLoJ7jvC^u{3SMgpq^Oeaa3JecHoPX%mJH#wWScCcqcE8c)xq -z4jX_D35kT+cyKNi6Cllj!}HTS`S3+^D8CDqx&E;wnfaJu@uKR?!a!Qqz^sJS)WPXV -zzC^gZwxuEGd5mJGU(uE9v*ccBxu79N=HfxDgR8`txa#6d@4{Sxw`g3&hv$lfh$!T) -zfeZ1CO$+Bj2C?cdw|4cHn;Kqu@i8k8EZB0Wz0)5vR}1=!%GEzr9t{3migpE=T!bBT5$|$=DH_ -z44LX&y6ZQgGqM@W*UUIM)jP_+-TR-b%z_QUrJr%hy}!zbI;r|3mT0gt2Rf^K5<5G; -zdrn_I$-;+E(vSdRj_vB}UzA7BG-u!w;)SKYo;f)p)l2M@ooRl(-4~$SzS5$yl5D@U -zBuri!1ouzJH${-vunOJ8>lxe$70A*+LTA5``}#zkIUzn9g;_s8&z8oNo$D_t!I#zY -z3da=TpKeucH=^uFhSvU(gRvoVy|wn2ll|pmnkQY3-jB@9ZzMgO|79)hrJCAmxqe#kJcK<0h>+ -zC*U)!Iarp`OJB5p2}!(M&1M??IgpO@uW(Ld+_%ISb+NN_Tot=Of{16GODDsk3K9}U -zD?Qr6x%gp&PZlvQ8&Pv?QORV5FMNE&1mIU-=W3KBbWYD40NHS!AwjL+eUB -zGC$P=uGH#%a*@tXdg8d&LM9odVGi&0<%U&UMeO=D3v9i8}ZAJX_zl~gNmmA -z^q%k!EhorIKbNisu(hdwdXW-?=<|kI6;HJ6RH=7BVMer=i{nQW`^i$X?|~H_O)Mm) -zUUuPK7*2RGO+VqK7VBP^ZeQafQJMc!Y^igdn%4?dVF0qR*%4zEBLQRaX1{K`SW -zT7_n>4R`VP-^Oevb( -z|Mem-ST^<>dlu&4P09KWbZKfu0>zCCKX?&L@ -zd#%$GX?$!z?{fh}8XqC0*7?p?R)`VAyp^{P@OLW2p`wGq;(bYfaT)1% -zKtu)q1NxJJKRY!W)+4oRn``t?ixsLd*Q&jD{XSM07PC`7BKfa~pYA2CeeT$jLgV~H -zVj({7TU0zbGb`WkOGwaug<(wg$NZAu8&nqXPvZUfnrv+{2HKzV7xJibni^A5RNxEb -z=9Q-Hy=j`-u*+ZUf6?YwMp1@!|I4{Qli|bW5av+YpFt&=0PI^q?)dfnHQKq<3ueY9 -z8kSV%{!&)>_+mfA9%cW|)to@MD-F>%@}l#nR;XY!%rG(TZ$(StwDa>3cY1Q6s2c2V -zacO{b8$Oeb{XD&Le8a!2>I=WW6_xpDyB&(_*mgPwt -z__3sLZsT+E>haV$rS5sVCVM>RH}ZJiAO1&m!>c@=(5^vy -z1=?TGPDfks?5gUA&^AW97Hu-xZD{+UtvAKvnU1y<+SO=pzun_$)4r;D(K3%`6xt1F -zv(WBDn~S#Lb9gTh+V*G@ `u1nuU;s_L83o|s%!eckgO&%0tE%ru+r1CQLEElhRkde@$J2FiRdqbtqlQ#fk3zc>?M$?H -z48{F-J)Vq4HXa6k&~8M#3+8edi2b(hD}yRfQyL4!J;mc^h4?GIO0RZlvyj%PzD -z`YyCb&464x*6|ERyBO_@Xg8t_q1}zP{SC0Ic+icu8`^bfm!UoCMvQ}Y0@}aOK7`hr -zfPQFuqs^F!anN3m_GYx}&@M%rI1BPbdj;A(Xdgn`Jh6@^?xw2h9%#Fx%|UxT+L>s7 -zK)V=i^9s;~_6oGS(QZK7G^viK3T-#EDL2F3(O!#oI@<5hE<)RMHsE^H@r**-4effg -zSD^h3ZToV_a}LI>sN?B;3&us8gLWp`*0)0LH-kU4O=g2mv|Z7TsRUnW??QVs+7Q~M -zXivNye4+hl9{gzzZe;@1}?Yn62Lfi8Gs_K`~ -z4n_L~+QtvU4{xpG>5VoS?d@nULAwU+6tvSHg1pf_k9H&4!yksc(I%s9dK={S2<#PY -zn@3^S&(!gZM!Nv*T(rxct>bC2sH%D^+6=Vymeuimg|mp#49>?gy^Us(u{! -z9pa=(lO`@&WVC4F#7T=LEt;q_aiZcxr9}%DPMkDJQE8##q=}0bEn2i_;v}Pq6BkWf -zG;!g?Nk)qnO`J4o;iQQR7j2CDd*A%GufJx#UVFV6=bY!9^Esb$p69a5^&vK}m&07L -z!TSHoxS7rw58HptXEhJ9l?jc`D{f}wX8FxzE_=lOWfRLeXQT16nAOjY3+!X@bH@Fs -zb?6)ynDUtY%DJ25AD8^n_%~1CC~UX)^a0TnX*luv4hcr;{shw=7QhKGrqz4 -z31NXC+j(Jo=-del{ED$BhXocsEl(oD0tGB#BkOtkc6q{QnDD`{z#o{w)1DD`u3;U| -z>k$8mVS$TT$nUa-LAJBuS^aSnqfQA69AYYO-yzP7d(L`tI-9waee7doR9N7?PWzKT -zU=IJxa_0Qb{^Ypl#hE8_l$SH%Lt%lZn9U`>7iSi;jxFru=eoq1dzl{}7MS`6`<`>y -z$ZOff2ROp#+5f4qz{H)#HO+XL$V-{U@3MqjSj)p~=j1<~

Sj8mIM~%$l78dbU -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 -zR`O{!F=4#dC-B$0F9Sfvw!h -zK8`Z{!`|oix^>`UX0Y_2b!RzixRtFOVIQadQ@faPflMZFl$nekwho;BhH)~VZCu5E -z&N*b9AMt%AvVvKxV-ZvSB`*9jTexsUT-e6QDc0}b;=)*F@iG=Oht*uk7H(uO|G>aU -zjrXwrIPr+*6~?fXi&)2Ac5>dR=Z4Vt858R~WeS%vhqWx_Cy&~JZ@n*Ut|NP1nqau;V>65=5+5vWExwU$9*hkT3|HTz$NVDG7fS%BfanOUM6xi -zGug@_9%41)#*GGhxq$u>C}#$L!$J0Y -zonTyy;vh#E`$_L>4A+iVGoQIE=Ur@I3p@E64l?dU?c&Xo>0HA??qU^B96uUt<}CIw -zkE1ML?5D(!Y23m*wy})SCmAQ#vWv+PqrqYRg)!6Q)dxm{shr0=7PFkCtY;lNc$CA8 -zo1onp@|-EmWiIbx8SiBstJubzlg*DWF*ZTGnabIb`eQN6dB+FMkDJ-U0~}?{#L-~f -znd1WUna)xca2qR`bjoP3i3{1yH5}pdjGb;hnZ`L$)`5+z;BGeZ`VU!mu4CXV@n$?H -zPLd~#W&x+Lg1KyBA-lNnRP7S21LJsr>6{d;9Y4!T*07bk*~bZ|jRwQdwyu*$gGu}# -zvpAVW9AYgGv6ZPG){Zwbe1`iq<9R33*~kJ8vXW6T#>tD=&2Mmo-(<`=&U>bEjQLFX -zi1kP^PF8UnJ3nLoQ?z3&W0KupnZgX_@y5FyEx;c@`aya^k+S{FqsRP!%Zyb -zE;euvJ2=1rzQKrDp4VdSZ_Z;D-(V?^vXi$7&Qa4BOyZ+|n5hndg2r#bJqlFjU84=10Y -z9kUph>UokGoSNW#VK%Ec$QB-94^KGLI2p;9FSx%mox7ROK9)0ix;$elyI8?tZeq+F -z>&sOBn|VCzEbW-f1~#yZhdIo$MD5P=e8^O8U@m{hGLAo6JQ>M$&YYnguV#6g>$0AU -z*v?;YfDz|dr}M>~Df~0@d6*Sknr&u(tuFxPzAKD)rV$_&29LY^{H+?c^;E@KbZ -zagrMTaOqt8iyJx24n|+@{oYLGr!UfuUuG#+u#Q{V&UW^5 -z2g9?xpFcysa2m6CGmBZmYTn6a?qnZ#GjN6a7t0&YV+Oy@Lf+3RzRDKH&Xb><%26gT -zcD{3wX>4FVpJN68$OiVZgB_R1QyygOmCnCR?HI>AKF=y1WHV2@RKD>djn9&6isT_OX@WS?0&_SJ+2ajSF1I6xK42>siJI*6~%gbKZRU!ljJ9THKh-s4LBj -zt*qicHgiI@@o^6$uJL^)@BlNo`zm?D_^b89EOxMpgM5-vInD_tbILW=o9QfN0qYo@ -zBQM#;5pHM9m;62oQ~2R8$!F%XoE2=~YIbn?0_}JiV;6YdU>YA}KEu9jUi=K3S;!u) -z;V8E-?#s^4TzSQM7I6cs_&S?8{VUq>QjT&3<8r-zS|}bYVIjZIN*-hrW54QL=Tr{! -zD#muTm#~<3u!g;C=fq-p!W2d>5kDp| -z?NLo1*~QT*Rp{xvXiOb(vEqIUFuw9CbzSY6{YUq -z+{`w1vX8Gb{3g$vjA!~C+HoEWnZ-)}fK5EeUQWK#x)nJm7{{qh<8{nuJF7UrW*%TS -zKXI3Fasgw%Vc#;18=23Ytl;)C>&;nrTQ{aM;%4_XCi2J3Vk?W8yWG05fgK#?5VP(v -zzFYLiG{%<8E6!y#m#~EkzpWpxVN|i_5GHZa3il@#vWzqC6$ciuo9zt0)%~9FJjx7S -zT%jM{!fMvBg`3&K7dXn78GD;^?>_6yWh~_MmDYEfQMPh1FM`jT=6~qa08>hX(d%!l7*E_bq=huFX=HTq#8hdJTL^5;(X -zTV`?QTKkrJ*~ryDaeeM&;4ar;JeSt0&($pEX4WwKr_L1~FRE7L)v|dbOF6&v&y=>sDN5q5q9AY(N?sH#Y8fR@359YC) -zE7`zmc5r}$ocyT%Rywbk!VS#h0Lz)$q#c*AlWRH5F~)vJ`D5b6D)w?K1C^fJe`(&_ -z#B7dlHg6`gmWO`jdQ8|X{;R#-WfiO0%tP#9{NvV*`&yjKKadAch(DLHm<_Dql3$w_ -zYdOeKMprxMTFr}D%;oTt`r(u|{csL@xQL@%!MGpFFQ&7L1srB2W1f;%Ol3DSILvHD -zudy$g%nD|+n#EklYSy!v81p0drFQ2HbDnm-a}le!ip}iZZohFKBWgUa -zJtHpM(qY}Whvl5`taanO9oB`XKd1hW?LQ`RDYLk-Q++P~oq6#gc5^33IO+H5ueI-) -z$qW{;qRW0}HQU+70T%3(7e5i7Kbi-_x~(rKv69nvIXAefN8Grc(Y2m;n8LlxVf0^| -z8_apZxR~ARKESyz%GaN|KQWn;_NdQvma?A>%zw!|xQBk(DlnnXxyf>7v5Cc;^H=+j -zi}tF|{S4eM?_O4)Rm|dH7BjJ5zA=?8tYjazFuczFk_jvykZ*C9Dc5)Mk*u&`cUbnmhSpXZJ{>i1FXzp$ghQdYBp6HYi9>}DwgKlk_Wqka!XUNVP6Ea$=#j|Q9A -z$zIMLe>51;;2dBwPe18sFpq0k$?%Ay!4}@kelGaHQNMR0e}K96#{IB3Fp=3&M}xT>Vg=WH$T%1^$vC)z -zQH{=PrgFupM}q|%V>L^nkNSNQ=LY+E@@dBXh`2F<-(n_LGLQda6~|9L8m#B_?BH$e -z<#vW|bdE8BQ$DOcw@x`4EMq_GIq{>~F@=L%#HdH*Ig`1WIqYL8C&Y>yliALN9AE__ -zo8&E%*vo8=|Jc!B36ogM1#DwE`?--3kI5G%GVFA5XCjMvHEUSLR&HP)yBWSo{FuOm -zkDDLI#~By(`Rj2vBcg_YdK7B;2IckX3W+ql3v -zbL0n8n8$6bW{fWe)4Oob7Dn -z0CzF+8TmKgyf~fN%w`GiWGx%m#+~fvC?h(=>q_~Ti&@VaKF?N;u#Z!-#qnA3 -zV*+nuChJ(l9c<%H_VEzIcldY7tJLQwn8E2R;QXug!%DWYiG5sujd?xi++`A9VK!f9 -zJrA>;r{{W -zuN6;DT4en=mu)O$Kkv<#mpkR_b^2iz^EhR(eptXJ9%3(VzFt3nls8P^E@m=NpdY5N -zhG948hhO3VbC&3*+xfsWF1k_NSiwp@_;u^X{H5x%m=S-nK1^c%P4bxQSjKkNbKf_t -z3ma~BU)Uudi{(AX-zv_W$1+y1firJYpNlxcLdN`A+;6v@OlCeySjEk3VP1)N@$_$6 -z&mQZ;Bo;E48(7XOmx&j@!Y)3*QNG0ZzZl22><_MH5qGhc(WTa(zu^#{VbpHV8+SM_ -zc`@^OkX0OI6VvXrF1(ZBFN_PEahGxN)6C+nEah)l&&6fN#rV68izWA{-)sEL=0TQn -zZn^rrj_rJs1ALYdFM40bx5b$$%;8^I&R1E_b5`hw3pmUZ?sZ?z?)df5;ijI`^Lv=hX2hu!~}LSgRilW -zBdp}|)$*MC*vFV3Xtz(C7|#n>&1LLo3nTunJ`;IywS40;7PE}ie2_^4&T(e5CsfW+ -z_A}>)^7|EWUSm9bkyUK{k#P-rUSt!aYs7(5ILtYW`G=nmGo2kQ;Pb5DK{oQTABzJo -zUTZ!Foac;ZFSB^XPvjF9u!j9?5B2{!s++RTVBe* -zko;sKw=s*kb@GoJS;wtxV+Z><#PHWWZ#-a~n8QpSWC<@^FK_t}J2=EaMn7nL2R&CZ -zg$2xE2}{_)dXBJ@)9b~L`HcOi^8wW$*|G9R<&ReFki+Mc6 -za;7vmXStKz9N`FO|3bSr>}O_hfQ5|QV7+-YTbRcl7IB1aj6Y<)%;eOE|!}b*~GXL!UBI}IzPI@eV!StW)<7m%6`7Yi14t$ -z8P8c)W;2JiEN2HB_$oX3nNItHd5k^L=K(T<-7Mt4SjF>xXFe=sU&!b6GhY8p4EcNK -zF_(AA2d?>p`EZOqoVwF|n8~=4!UDa_5Q5nUQA{`^SGa7ocI@U -zIXNs)&0>zSj&Zx~E6(EpcQe}OGWIc<;V+msSF+RRG4^wa#l7O~a~CUKw4Wx412dSt -z$Mw09HH>@7^*N6Np>jr?8WyNwG7mG45BAv?e1wgBojttrukt(Ec$vhgm(^!7%Q?s< -z4zr7m{l?2K#+?=x_$Sku^f&QiHmg{|X6|4wcXE`YjGOH93HNEoG8V9k6|7+c*Rg}m -zf45#dz}OF)4^tUGV4O^38T;ADh*yl0XK|PXjExBkR5FcC%xBns@!$kDGMQam#bLHE -z<|Fn4Q`p5E?qUfCUo}on8?Z9Vo -zByM3gqYr4uIjrSnY~|JL<(E0i#f**Bo@t!*nt5^oD_G4&=DluzvYg=`bB_Jf{8-Ff -z*07ANtY;rP7(Q%%OkmXM^5G5Z$5n@{AJ?#gPq2}_?Ba+1C7%2wqd#tcF@>efWgW}d -z&Uy~8gOMZpV-lm{jGHN3%{+Fpf_vG(L3Xg^uy}Cx5$E+MoS)2Q7mK-IRQ$P~oqV1{ -ze4Wu#ea`1m@#A9Vb1N%($(Z{Bv)RKv4F9ChSq(bhIFDKUI*a)TYq^_k%ngkB{Q{rU -z$(Z=Cz(J<4bljNV8}NCeOk+aWSg?@4Vhy*lg&8M|1+&kvUMyxUYglli_K9JEBBrvH -zd2DAHqsET~>p7bpT*+Z>X3W`Pfxj@7XPz_`EMPvXxQfl(!#+-k81sJju)x_&;2q3n -z3rkr(Va)s7<Gya&m+IpV6NV3&fr(uAIwU7O{*KtYdAo{RqiP_9%HA~pS -zTE50Meq_p6u%Dk`_-Ex86ZjCb*u`Q_{-}IlIa|4jeTD_?Y+Yi#sFFwJveS#|6yhT`b{qtYtS_+0R}Ma+H%lA)YDb&vXv5fQMMY*;C~e -zo7l$%pVZ&yeEuzySkG*3WHAr2jCr**=$+sZ3!mOIg8#Y-a5=ar=B& -zU>g(I$qYuF;rd*`IwmDp&s5`K3MZU77EJzv>obS*S;|t@@vP}%!FGO)1FU7_9M3Ul -znFr@Go0%-;O{`%9TlolknVhKId7kT-$W_c@2aEaa+4^JH4E?c!18ihunssI(|HLd# -zJV!g8%4)7~rcDC^q_A@h0KF^a+OyL^l@F+`p;`!QfB3rqO1AKuImxKjgW&+1w -zFc!?@bQbYaR4U4kIqs -z9~0Tg%h|=dIm|7L$#SkSl?R#25tcG@o^@n4J6Oj-?q<{#@;cM}xP$rp2P^pTOZCSb -zcJV$Aa~oskoA2fFnbj=dT2}C{Y~++I?Kp?Se1&mWir*E^VRo~S(ev#Cp3Nq%VmDhj -z!mW(S_WZyUo_wYGF`Z>BU_DRG)*mxD%rVAZrT?qUkJm7dEiC6=HgJF)Jiq~d_GqdeJig3wMt|8jIftFh;2`@L`z7ONDuO976m~I(yII1&vxYI(izidr#|s#^ -zHY{)}<5|ZHKEwhxvVyO%k(U)Xm-r2ivYK&=tji7Zi?dnCud|9ZZ00(4v!28JJ7d1) -z+*)G)@dg&Kl9f!n(K*PO?BR7B<@Xqu@4n7-&M$QCvXs?a!DeQBU0iq@Bd&8@Ch#$4 -z@(C95gr(YX23wfI9v)`IVtI6v{lhuTyqx)5 -z%Ss+%E91Ul9hlDW0{!1?-C4w3cCwO(*u*Kfh$AN!tAB&|F_8~2mpv>Geg9VVnaM8R -z#bI_bc8U8LQ<;97xN{yWcn2G~gWc@rFfX{>d~S3-rm=}M6LOXMTdzv=$LR>l^} -zi)HeO6)fatR&gI&IPY8LA1Y_~*PRzk;Dl1~=4=*o9cx47Y-7?L)|U$zvD7)uBpzfA -zlkRlRv7B|>#CGoGAm`p?zucspDePe`$CufkoW%yNWml-2!<>D$ye)FhGnLctF)!w_ -zid)&tLH2Otw~g-`&POKlf)$?cSj1w^tZ=_zK0CObgB)hm&EmCEyg9&p&ijsaVhI~L -z`@8avg$&%{^*ZA@$_#G(p8d}u)-t_H{CG3_nY>yYiapmcgau$b}$LLbe$4p@}bGe6QjM$(*MzNjA9N;yKydx~|RVK24ncVWQaWdi&@naM_ -znam+x!{|G;V=@bv%`F>^lXpBSFZgYC@w*)28b;kEKbp*s)y!ip%UI7kHnNRHkI8p# -zU{sm>Wik&khy9!M$B18w3lrJNFEm?cUc}hD!vf!71~;>iU;UN)9dBR@A7MXx7_r=a -zbhCcAmf76O67FIR53`l0KW@Ew0mJXHPnf`!%;ZKEaVM)8)uKPnVJ{zGpj*=at?4VBUYF<6L~W;Im!}N -z{zjfKVXJlHVh*#KG52~7Vk)bjG(L8;nHOJW3wJyvj*Qr*p9=ZOM6P94=aQdE?WbpIOV;`dF#X} -zzt_)q#z15%h|w* -zd&P|@9AO3H*EnaH!9TN*XS^&9T*Nk3vY)+-`jLInZ+&j>|p$`emH}X>*NhnIKX_ae#3mYna%8D -z533I8hg%qTzjNtd@|smF;96F251Tn{#Q507h&s<Ax!C)=R*~U%mXYmJu!RQ9(E>jpWAsEc%ES7QPFv)KkOViHR%7V -zVO^q)i>sql|sjefp!;hkIDexv}QM -zC2VIk2N?e`>(eCuOy;G`;WaGbPgu_no*oQ#aWhAm`f>U5nEYlYH?xF$S<4gS%!gNT -zkX4M{WPLs%PkBEJ*}zK9oGRa#%U(7z;+LMsn8+i{;w7I921~hu^^Ax&F8+|CT*ugE -z=kce^pYvJB^{nCZY~}0hchSiw#<^MW(=!$C$q?tVU9zVTM(v5w_zX9Ewgli6pP55LFw7XOaOY{n&uGt*hi -zrEFt2hZuFXeei_wF_qV_jQOl)37Z)0qkcpGjaxQ9FwO^Wel#*Xyu#a(<9sjHpSBl9 -zf@y#B#l(oY6C>xHa&mEaN#MLGpPxQ6erl*Z&7Z6D4hK(X;QWaZ-wwOrgC{O{+Ew0c -zpXb}z$|oLMKJU%)INvMt=K|%Q<~!}v?>V91x99(-QmBu5e=b)i;{Vinw~uz;KUevQ -z$Ckg@{6F*P_x)JqUpcm1A7R;Vb`t6%!km*I{r7*JN1XBmy*18IolJG+ -z{*O9E>MT&_{pMS(&h_ei=-9q4eRsai%5#+ex0r_J(*4#rrXJgV;k)g;YMo~k_c*!CswmM1F@^?$tbY~>Tadit?^(SF}ll^6S5iB~F`U<)K*R9@{>2o?P+fVGyd5 -zqs~ck{Jrac{nNjF=WHxhCt983tx2u&Fy;Sk9HE%CDi5vsf15|V@?Pbkee@+?zq96V -z=1%6@xf7=-e7yh9=>HgNf;vgZ8B6FI8Oo+suC-aSj+T!)^w*CDi?m9BU3aqeTG@B^6HmNhF6&GY1AuYb{-{fF|tTX{hF|9{qmUHEpq<5U?{ -zFG0OozJ6z%^6AE7;uZG+Ijc_Qd+LOxzqyg)d_P^CMd}myzV>kNN_CGNSJ=Ea2NvhsE$ZZ}bG&s7^*N}|rRs#9ZNfkE|MhwF?LI>> -z3+4N~MTdho`Z_%6n7X0;wdmb`lPtHBwqs&n -ztIn?f(N~)~BmbkXes#jW_WpfENT$=(dB1rjs*|S9@#YnZd7hk_r%ti2!$*?eyUsVf -z9rHNlrLMPH-9%p>8-uUC6@$?Anp|(KIyd_|yygG9-t})^FI2Zz-M+W$hTeSl_H)Ub -zXU#ixLwkHg-_!DsfA5Kj^#AlzK2_a!uJhJ2WGG)!l%J;j|Llu5`#JyZF@^fcQ*ZWh -z`iWCsraVFUbYH*IkDR;qtr&!^QLoMnbxiM=I&bdxINxelK3Vy+|5JX?32yuUsT8U+ -zpiYcBpL|c91;^BhbR!Pcx$r%8mK`&eBz02M`EO@qsGlt5p|~EepU`}Y->PE?-kr}| -z=U1F>RV$z58U@FehxXxD-yBFN{vC4qYIU-G9o{zc-L($YyX4J!p}zWDYx!};8!8W& -zNRjdnhrWJ0U#@)jERR!OaGds`oXawa&^Z2c#-txJjyH4Roiip*-9p!zdEMdQS-yU! -zFXMgdcnKu>cAe|ZR_E)!4nO6X>%ILfmlw*eH=pI=)M<0g67}Ejtn62(L7f@uAKUM- -z_xlJh7B;DKyc`OREmaORt5fUi@b7&3-I%{Uw(q?=wov^-_2U-5HJ4ldOa1rErP3G{ -zs{ej-X;NpEI`21^ZgpzZIo@32jBP}nwd&mF>tkaQ_VqV&CsZfai<`m!(N~%}ht$b^ -z?{&O731v~}I{E6%xc<#E@&EMo){QolhZXAFsZOZ=J9Tp3-Qx{!mEV4Bc_`Q4dcX{| -z>r`i_Yh=E+j=TQbV;NHCusV0Yw@%5sb)voS&MA2R7^kSSNS){2d!21>UMDoCTy-Y= -zKgP}nuCBWN|99-TaH5joBqcpfRGPR@$!L<|#5om}lqOD6R8pL@P)W&9NpUVi<2z}R -zk&%*-ky0(cWXs6NXpxffGcq!=Ww`hnEt+g2`90s~o^#LVoO?f?Lyw1fyzl3Ez2Ber -z=l%I}{@lwA{5^J+aj!FMK5N3BhJCear%j)YOT>ifg0T&Z_!)#b1BNd3bLU>~%3QG% -z`%3IzRqgTd+2+mFHnxnz_`5rB_o~U}9+K -z>Qm;G9vYJdvz243Y^6We;&Fdbje8KiI@phdeAX*@oP@a>MmP6}PpS9&VSXb%|8`Q? -zCp{a#-nOw9aS@Y$qq#<^U`~V4`4pXIm@{B>>xD4gE~C?t*vE){4LWadY@L)8`yaj7 -zg|(=MSlzz)-^%eZN$d+AD|1)@>=UrRmp$Y`3cFVBQ!M_~A`ga@TC0Y?Xk)xRR!rfk -zBX6yhnr-Cf)A?{LPkzn1_akgR>cC!vU3Wbx%yyUyV5CinIRiiHx<3I^4kK+*8E=ne -z^RdMRb|s8%96I|Q>gQG%=_e~c->(g&U7}Tv*3EDyajg2QQEIUP=5sI~G%y`7n_!IX -zhj|3%U=?gYFp@8Y`^%}E$p%dDvtz9uy-H!G -zVBSfgqvk72m -zX-tE^{i!iF$PEpAi{PrE^WNjkt0j-s@Zs -zS^JOo6qq#dm?KtIR19|13-eOsaWN?Ab^0Tnc-t+H~5FJr8?&z(;() -zD)vh3nb^5Z^V_z@w>M(nM=hoDZ*xiq_DMtSi;wLtlgfu^jAMTpja3{c@=G4PdzjMa -znbd{&xq)Nr>Ery|#^<3cy^gT4=i~Hv+H^U`s$N=oe2@rJjb0VZO&nV{hV|ml6&uj` -zHjJ)+M5hDh8JKY0dvmog+hGP_KFYBgPlGb&Pr$qe6R0tAut8z0_p!df=+-Lnl?Ss2 -zMmJU^msQl%EX-3JTX*G#bNRTM%SQBWzezt|i(W5!%`n5FcTSSt&s4o3^z56>`|c^2 -z0vO%igjB^cd62sbCWGTdPS?ik*5;!E?8jr*&6C1Zz!Vx7@zV&i+Tf=H`%3J(J(6f_ -zhxrK1K^!Myb?>8yeH?qP#xD8I0LsMP$g#EP*l>TbEc)|#-ZAtq>^ZOrU(}I$Z@moW -zP8i*~FEQ1_Y=%iS?#14Q{Z{O{d8f~fLuVhsE_v12r?KZ5?3p&Vgbelq>@(D4Dt%0` -za{ljC?BRY>*S!XqH(+#QNpw2+zsU$@JIpQ^)4Dg|GP-$0#(WlaGKQMG-XE%i -z#SQ8;j?_&l{MuXGarsX>#HR(uW%c`M2du6p#D6<_yJ6nVb8GAIu-@V&Xyxy9;_wRZH*xJ|!qNnHIf6)>i_#$ndM==MCK6C>y<7+vhb -zE}+EQ((BX_xsU($3X1cu`kE| -zZq=^5Co+yb%V3|wzQkb9VUspXn^Ni9_$mM<-b}kFz5q)*T3~GA -zNVVpOy&HQ5cDC_;9+dlNgV-gPg{mDNJZy1_-sba37|BI=&*AOwr4Mtc7l~uJ%ma_V -z&+kKLFSPgwbsiAD4F0gs?wfyB_^&7NPpdrcV|B;Tr?>B$Ka1nUxOB7=mku!-Q#;%< -zaJqe)F#RyYFs9lbhj|&s)ITwdqXu8n&O+*B7t9Z&oxjcr=cPw&r;PO)_>E2b=67*y -zy%grt{_Kr)(Qbpyzk~Y^X|T_P*~RCnbDs_0N4({Ch3;2KJ-N?3gc*fth6&fh2KU_y -zVP;|4U~upE1v=h6Dq(U?h%=`9Zsl}r2Re_yTPKF&Pjj9KND+!&9ePWe&HdU2lLKSw -z*KIJ%VQ4}icJ;p37))*iGY4}#j41~;9U8@yE`X_Z8C|<%oVUW{6Hj`eUGa6x=CfYx -zS=hsSPj#G+z({UB8qm0Bv3gA~15+H)?(7dlGsO`MZesOxlK672uX2tIjh(c_^_A0p -z^lpbu55%stANw`fO*tHasWoU!V=u?9+Yj0J&ceZ!20y|S!PG=BRWKW1Om*4}QwL+J -z!R`exLoV}SVoS`ejA!-zqbZnXe5KlZOPewn=o=$qDTrXC&ujRXi>aaS#XX?7XYTGtJ;6JK;+pl`2M*7qTpT@lO_%(Q`#zO!+%2jL -z-ZSy|{gCIpwadm{%!TyUyUq1o4bu_9w7@(9V;TcJ5sbt>PVAy{qr`3{#qK<9_ST|V -z^j?kdnZrekFz29`$OCovIb|I!ftfQf5?2GYcJw{_=3`QujfaPG>Qtu0C3V+^-fq}b -zb!lVolbEpIz_A)r8m$uz@wXFycFVr`TR65(P4btxxoBgLaiLlZYnl&pVQz&n_0L+D -zG0k;#FpUv9Z3|$wxs1uz7|iVvzUCId*ld_Z$K847DnS1HUP246Bq*1C-D9@b{;OCtRA!bIh7#AQtJ -z&cI0iOyfJd$jq>O#>%7~(K$=*-7L@W$ANpzvAEE=dlSFu32*aHJ-XTVoAcQYb0mx@ -zzJ8ZsNC)P_I%RGdhgpG+X)TC-Bo-@yF|7r;Fl!>1wJ>E7G1s{a%TFL?@BW44w2PWt -zkIrXgZaMIvT!yVgpe^3>S&6HTI$MR#OB`E`NpU^z#U*n|2kdL&Q`&u1m|eUqJg4^Kzwx%c -zN%#1?_Y7ssjl*n)Ie_EDzQldMMC^0eHyZ3Yr^_>jy(!;ukoJ{PU#qci=h%Abz;NE5 -z_Sz@?+6enH?BfJu{a9hoi+@LL@k0j)p6FM}Nw4VNv3I^ia`K*}oSdrWMA|btap6c{MJY`Ni1@OCC+<2Z-e8h7Wh^Gqn_IurUzN4^)c-lDU -zl>7G1|9%PasOQAv`Q?&CcG!~>{s8=|54iEH3D-ngAf74M4G+5UoT{*fcx-BDc^fq^ -z@u=s-$kqOv`(RS)l-e^S_o -zlGv|#tc`u}46ap}|4e)ANthg%@U?^YexQt>3~sO;4RZ*`i5gYjl`N))GqB6NXf0D> -z;u^$zZXh}p=%m9fRdw8Ve{4Q$z`mO~o=Ys>4;tPxa?$93c?X6^!#?AFuioaPe(ZDD -zuTkxC9elZeA7qMnR}se@FxCd89^-v;vzo*767IjlGDZ0Q(EGGd){-Qj$i<)Y3fl^s#{BU$VRxm6=c6qiYh&++y#@ABVSlZ#?p{Nf;S%2Cfzh== -ze8#AQH0B{EzIH_?o|8a)`LN}%PJE3?Y#_c$*q^~V@m;R4ZhX?Gb!TzU@WIsYPKdn~ -z`*MT57kj$FK8*b>V$iL3Q`koh_KekhC(mHd$KGYImto&zu-9R))7WikKlV$ohxc^e -znl4Nq%r!8&dpnZHQP+=d{LNrrhX%_>pw_+b3&?tvR}zm^{8*1H@oSSY@kwP&l$_1` -z-e}SN0jP!!1Ti~ -zJp|&p&D|Hv7?^?i9n5Vi<2@&E?vDEJDcGgViPYRxDl7BM$K!(1zEYUWVbTMPzwcn-@lQz -z+2_P!e}GBVHXC~h_Mc%d<2bQqNPd*>9M!<=g3+x{xt!WT5Hm2xacr%!{2Za>tx-0% -zKD2hjap@KCSEtnED2(-`BjUB_BGg#g;o2(TbISx9KM7(k7Mh# -zw1BTPzP}(*iLWef)YQTqz;Qy$y>5{4BlUg}_6In&9#M4S^?bLwZdIez2g_E>*P>6o -zcW`A-+K%1}F#i(0%M?9tOzsrL_?VRVwxM}nTk2eheH8mm8oT(L!Cr-Z`C|UVy9RK5 -zEk1m)?+ml(<*uc@59$4tVlTp;YK+MFHP~&9-Dy9yn2!BESnJb^{C@G;&v)~@_S-Pq -z(5r^m?Vp4hgQRc)@eTl^S^MZ+9$qBv3FtDty@xijri(w -z$k8|3n#qHSd=h%9fKUC+{V|*;#<&7oD -zO)pwUw(GUV(MrSaXkBL3nnkM`Hq{un@s)i6a|L!?{Yc%GQDed^Pb2n!^GEptu`fQt -zx%;JDOE$q5ZQVEjznp8m73R}=y|#+~4*UikRYhS3wo(ff{GPuN-5@`v}$|AS*o -z{;*&m*0c%LcUBqCnL0w(>M|zIiub$dt)+fWgGpP2-o;6JZ+m*q_(w0}EBg2MTCiK# -zb#tVRzaE$)VODUQh&@!V!!ULPGYxY*jBZU6Us)IO&KnGu906bIJ48h=7r~qqV$|n4 -zRWOwX9hn!JVQz-mq3XnI|EFFKh3kRKdSu`H=aMhBJitWI-(Z-+S&<~Y?KF?r7erJd8XGY6)hW9udUu&38fZ*BRuWY6F4W?szmI{5JZ -z`7`eRS?akEW&mcX>es!#m$6YpjXjC|XX3L?@fq*eZC-zgRx?^>el7K!W@GQdo`>C3 -zuY)kB!I<(n2~!4R8b2B3Tz?rDiMIfz5+_XCiHfIf0nD}tM*33fU3~FaA!facKRB%P -zrFX3)Tqbo<2j^UW{FOgwtZ?e}WZtFRzcl1Pw5re&M%E4Mt3fSw?Px%23!G`ZcEI$& -zn8xdNn5PVkjFD+#+6Hs2#B`7nQ+$l9^9oYxDWf75`vgUiNbkeXpbLh2-PG}C5Hjct}z&{Mz7o&cq@QQdyP+#}4s7gMOsJP&H^p59Qw^h=Tf|S5 -z%Vcw$h)4O}Micf*G{SR+w|28q1~g|q -z%`&~F^idm{KSwiN)l~Kueb{@k>uOWluoHi4c*f_nVejs6dlPLCHj|nd^VnTxwitFp -zv#a|@Gg}Kg=dr_PwjK7t&%3%mF|z}(_T4V~l$n)!|32&kwA1=}65H(ck@RKydhXp* -zBT;=>LcL9S{;x>VOyt%X|7d2=SEcAD>LaZraUIZvy#V`Zs-5wsuDe|@t6@$GG3s^J -zAj}0YA2cwNFzaBh2{GRDvP?eDxPtu{j59y*-?se2XZQ1&Ztj)yO5O9`#j*U)=ATMF -zyDuW9CYUWS&G3o*$X@fd_=F?cT`+IK93~9^lh3yC*%Y6taSrj>>wIR4bILvMP)8}Q -z#UFHz{hjmF*t7WTRX#K2vk2x57*js0U~(S|##zs2NAj5|&UW`aHKrauJA(5}F%82k -zhiR7fd2?JSpVKgR!l?PQKEb|?&(wTo^V!XOW{R`eJx|SNIiKCed1~x6e71ql*ro*I -zTI=tJHp6tl)TvBbZDOqSVBd+I=`W~paa_aZ<6)TW$M?-&9A?(|%rs0X%++CrU-uAa -zqLXzczm)}ZYKZZEGa-l1i(t0Eyjx|I@19m-Z^8Z^)$ab*ugzzT*c-8*tJ>)+_ov33 -zG1Lju38R}IB#r@?r(m2u@cLZ2|2TpDQS3*new63vF&=D*57T;{8^Or@SxH@qj`Xor -z{eS+NBlV~Bb3Ixw!0FbvHtf>Zw0l~ -z?>jW2H3g@ubJ6OA*$oq@V<-OGz3^i;+#uYc-_-Y^Fq1GjFuFPvCgWN&BmG-a9g7`> -z4k+)Tyy@rFyPsGgq5041ssS&8*Nu;6?5ANr5j{1h*Tkn|r+wWpXTa!kWpnBfOeu`a -zKdO#8_e{au45OPXGirFZ0(+{tQpS2d_G;{_R3EoGOO!KC%CO&#J=HjonrxzGYp|Dc -zY<+do&z;k!Jau>PjoH{c&}xF!M^6~%-sHCw -zJ;tbdZ*l~!9=KF}AbFU^z6HDNBNM*d-;|J?+SJJ1*vmP#&Q|=y=MA3x#XCu2DuaCj -z)|oesQdni)5Uv64DL7|Nc>4`M7jWL3AYAKpv=i*bh?AcYilXa*$iYe29I~B64tn5^p>Qd%PUjuqD@X|L|M-eWEZmFt@^# -zaGYotZFjf%&TpJay>EeekNDj6H$O*?&&BEL^B9?jhTw1Q!EYM;i%I;k>a#~1ev%j( -zo;2^DGitdX1*2P^q<#uu9)d~d*l$aG4zT&C9D5UX+$nZylyACw`^yHH0hq!NqrT_W -z0W%U2%XXNZFsbG<8|`uIquBF8et6N@30RmIi`f{=>Ja0-10+l?%pMq7ll?ZcZoAKf -zgjox-^gH@FT5?whlL?c~v9A-)oy6ElUC!c%;S#fs+!?BYw8Xty8+$)m1qOejH-+A5 -zFrYE(mA{7d=n?#CY?VlPLLokm3?X)*)-D(k|k;$>j>LO~KW|oxT|Et=Ikb -zd+$GgAo#9}%{iGj#$um-N`K8EW3RN9ITGeKGFB%P-S}92ULC8VS%aqCr>}R(%VwAY -zm{heP8a>#vvFmax%rMLm5zI8qvIr)t&df->MJ^+L6aA$8UUy}LhMd1boraao`-z}nu&PPxZ153X;a3h*fVQ1#Ga2`VoBvg>}A;B -zc{=rcB=$P&Z(&bW`(kg!KB}?X*n6=*i``TMBQ8@7ueLMovUo$q&kW2SbPiG(=*8YOdM>)3s@6Un0ACv6-<^H<+X-B&U@(1VJeyN_Rdj(tAN#_zz@$B6z83F+v0zMnKkPEcqp9}2`ut)VW{E*Za-BkJ_k85G9|26NET44@>F~#2plL=$W!>G%cbY@`= -zGw4VS<=hl!Qe6*8n~JeZER<%j-Pgu92EtUsRKl2Y(*m;@W@Si6eZJREJ#T^GwnogV -z_>thdmB9Fh1OUoV3-Z -zE>^;jdv&y5IcI=#j<0vmxqM;g%y7<{o85Ch -zwy<;ZsFmv)+;h%b*f~|4v*}j%oU;~oP8;Vu(deG@k?3=zMh7|Ph1>Ve-yv(^$;vtL -zweaTfTDbEwtY6RSYsk8ly2q}opkNubwad>%^njeSB -zhY9RYygeK*=BazQ^xI>x8)0>QV5650a}$iNUE;GGrXJ>F94Gq0^GTjnpG~k|hSlX# -z^3VnI7>q7Y1K2lf>=Mre_KnypQpIy_FrJLhao-O%5W9>W_xYWTMghzq%!gDx81LDW -zFcmPbz^n=}-n|Kls}W`jrd(ybJn`KzHBa5JnLp9rZ?@4Gg2{%_^^Gu73t%#v;yR|- -z3t?8`D=K!m2CRm?1om`}6ZPQC&xzO8oo5G|;XVnMu5!wIKRwtl#J(wDr*HWA0GZcv -z_ggsGZsRi}fO*PEx -zFuHybpDi$dS)k88*#E+w6!KZ4%(m5%b4yNSHhH|Qv|QJ$Gc}Nu{6Qd7-H$fUWWaWkcRsAjt5|Fhxtf| -z@xIF}`^A|i_5?7)vS0kxZ~cCZ?-zfj?iX$NtY-RtKtB&k>_sq_!|3u@iG4M8UF@RK -z1XHikkhpuP(Ms(1acmu-#O=+Kq3;C_qt^$oo4agureR)yG4*fO=go|ajkVO#FVOiY -z$JTu#eom=b@7|WQp&ss4IOo3AjS3gfec-;8@LllD&+nVhlD?`-;@_qAmGDyUH9wEv -zU$8!|@LrC1_s3gHgpW}#_rW{&u0N#k@pzsO>leW1{=$vtm?SHm=PG=Ixca}!n^~cn7fC -zA9HNAzv$PZ)2C^DQUTuHe;U0_^v{{FiTo0mw`Z5y&T5Ipz5!FFGI6c5JT1vVG29Dq -zy1uN!{vGUrzEu7`OB4338oP~tC-%Fsm#T3PE9CGNx9oU;whz9Iei7Trm7UxRUUhZm-s!9ufnhhA5F -z7r;CNb2Z0m&eD|kCo5oPV01MjV|Fuj`3}rW99x$t@x{m4pf}EJ?A_=+_G^7#N_qu5RBYdOp|7*pLfz&s1HM)gD8xm$T> -zp6`GekMOk}W;cv3&o=rKFmo_xgnZqi?3b-CaQ|W0%;dooz?j-z2D1i67mxH)Jxn=F -zdLW+o`j*FMUDS3F_6Clv3xDO0hj?8izRw~xJ`CFo%g&s?`Kqwq*m)s&>`dd|e$m{H -ztowOy0LIjZMKHxMx;54&zABgvFvoJ7s3-c_dmliU<_IPiW*fD813J!L>+?f?PSEo9 -zTB0?K)}3&=J-0B^Fk4`BYp(QB))%=a3$v8tMBK{SUWmO7`wG=gELSV*QYFk*m{k2N -zJ{qx0tOuwX@ny}q9`3+iqp?d)`mvvn{Ver-r$$)Gjwax)g)_C+YUN!bjW4Om -zLTcs;?ALN^9sEl_|M8mS&Z57+C`U{3d%hYMx$%BGz~=J?n0^>tT}bneQowpL$w_rag?BNPaT;4Uf -z#9s@y2ksQ%{`HGM{OUVz%?|*)6uN$M{0857>w!BAPWR5+5cYKJOOZ=evy<3&yKyJ% -zO3adn9BSnqnEf1EXDKnq^WZ%7_4biP5AydP@TZ&W^3kY6Zw$t{_DK)xEe>4!$e3tF -z^UmL<-fPHww;jE%PwtJc>2D7DIrZkd&|X0_C(vAlW~y;0nwiwcitG2ruZ@44Lh~od -zb7^E}b< -z(U9VtQ0#I}j5_GM(e?Am6z7C;DCZP%&iYTee%7TpCxxF{sW+bOIs313Q=F5+PbcSe -z@@&s(Pf?0#dw0`ycuV`;n@BUEFT-nTmQx+GtO} -z?1QOP{SbfJMgBVq))uZ6Xk+-AQ2ougJec!fxFzW4!L7|SZhm|B7;MZHupO}1sI2&` -z^nEtMyaH1aV!YqYv-!LeW;e{qA;x>gA3EQ{txs#`>M!Pe1lI -z@e|IC_bgB}#$oor9Hz$NzUyuC*&Oys?7H>}W4H7DzzC)k<_#F#GZBfU7Dkshv2VsM -zc}q1EWGaCy|ljz -z=8(~S^WWn*(WmkK*c0l$dkC%rPFH6V{}jwNnD?q$?(f#ve3sD>i+vaS)v8_Q$jkjX -zvH)fmjIQ5BrvhdgW_3tMeW$(==8*qquKCUgMshwvJs*tDwH#ZY*`Azp<@;DR%ru%M -z@I@Ra@<|)jTFUwgZGcHN$4edyv9HqDZR{1;ZS1;rSu`49R%kTD-hus4?5XxG;-eq? -zK0`mqzGRA;kD=l0!9Mxpq}+t>t%={vM;Irsr1mTJ0_^SB18d4f@qLT}xbpLb|y*c<*oU8V+_x#=F<5`%) -z{$Q@ZoUg`W?}qtENXOgf%lIs(o{on(kz?yBB{phGeGXiU)(W_ikd`+$OKw|X*1+iI -z%U=DMaCKbEPDIp#8J0aCD>(RM4#H6`D -zaAWg%3(SvU!ei2VRw_&n%m~bfIad2reO59IvlGTNH%-IrieR$7#ykP@v5+tCJ&+te -zFM>JxRejCYQeVrkJ2iVjzp-XTZ!>yx@VdV5!M+o_siucv_C+w$FqwZe=P2t@Vvk^o -zU~*ud4(EtfNoE6SQx!}POt#9nzyBlSTI#(EyOX2S|JRr!8@?C4P2=VqjKFllm}+1K -z<}nyu?BXl?>x{KOna4;mOaY8;j7ScuT_#ly#7{H!JT#c%0(G7CU_6h)bi;HS{75dx -zI@yoGIKRia_!&Q!-rhs``=6pYi{{4HQmpmLbBvrWat>n}2PH7C!YoBIF)o#RrPbI6 -zvFqk6$x#c;%La{Z?Ar|*HX1`PJ79EuAiHS -z`ytqMdm_naCpDQ36djohtoH={sq11nT6J)`KB>oEf!#Dex5KQ5S&uI@ -zN9wy^{V;6?9jT9Tn5{5}syfPdC+4tk!k#KtIX~x{%#ql2HD8SVQtY}tdKLCFu$$W2 -z3{wiDt3R7Kx?vRe!mIWg*O4ih;s{@vPw>8Ggs(!F>Ih$zFoo#o_Ri9-CYbXg -ze09OJM)(?piB+51J_*wh!DM`k`(Y7G0Zi4^W?vOBBL+t1y3N#H={0-jf5Nf#%cuPD -z>&Vr9n*Ug=aM4QhWU=EL9I$)N;TprR%EBE)8+hHz%Ne?iN8|NA7 -zIQCODcIkr*Y9a^w6vx(O-%aj=Kl|&q4O0w12LB=9FHrcK;y#5b|2EebFuM6&`k}#P -zQuTvqv|}GJXb95}^Ae11e2JfNn4K`G{5b8W9)5-WT3G9@-sJWx_fB$Q@}J}y1^#@F -z6ZPY)gNdK%j|o?U?$L~E=bHFbMK^R!+=Sk8xDr(l#=9oA`Me88=1|?ea$yExWFFD& -zF@>3gSqHO%<3#NEQtwx0u)tTrq^c*;$j2^oby-NmyI(0eFNcx!FICRPUXNYo*HrdA -z>}}YKuve%)yg4ECeTD6?)v))fENxP+ttVifhj}E-{Exo}vU>6P`o8&ZhM7*E$%FY3 -zjOiM^4CX}`(=~cM%tJRLaf_cen73h4wO#Ce*#E4tOS>ni -z^C9d*99zHc3Ag(v-hMS7yVQFPZMsj`pDL_ZZ=wBm{!`qifln2ijYb*vZtSN0c0J6? -zFuMJY#MMn)lQ0J^BCbfWoMi;*@ -z6);QwX4Ywh$$(h{pQtCsuKEsKC(KHijUgt@{bIPy=L0Z}Fe^ihi^PQ433E4$Y3!!= -zu~&vMM{+bx-M6FjFOIFFzL}h(*Zr|1dYRv6o&39go-4p!g59*{ -zRKPq2qnn>?{4_=|5_>Oo`weuQ{mHG}$+0W@6VV(-a}<6x$BCRVrqt(7(=fYXJ{V%W -zcei8?&81G>f!WWowN&vNUpuC~IaKmh@`G6HHyum64A -zZ)4ooi>j|)w94L0T~jva4`V+C`#Bt|?Qc@{-qSD@FtUeL8Sndx5_8rzzWc86Blbe< -zrZ_6FOB|*-sS&0arUX4T4t4L>2~!DUs-ppyF^%b+FgK#3o42G*=|AMVtuVT^Ef4$U -z*vmrkdV4<^vsKjA=V4^-unv06?@MY>oj)4T+G2>u=KKzr+dt0VDdt$s&+STIZijgU -z=Ee|{=013``FsNAbr@4$SkG{67~v}qCS#r1R~bwNjLw&g>1OJ0fO@az*!p*upCfP1 -zcJ500b9NV+v4~s^!YswFDOZy)D(-6N+C}#>_#D1*mi+NAIuU)qQrVZw= -z=$sPL@t!G5ySBmn3+5`7@!I8F+4=Lw1Z*ztI$33jOMOqy`Z4PjjBc-%i~R^qZftZ* -zvCkXYE-}}_yaQ9A#^J>rx~^}Bm3^%)m(m~oE|aQ1#6E`o5Hyws{Q39BX0gu_&%vr) -zd2cOydo1=h?7F{+} -z)c0*_VJ?Ev)wJ|qCpCE?%;!0_4pm~0_g~_|$Hv}|-eU$mVa6B0#D2;(20FU=Ms#vv -zo`(4d$7&9|_ke_13o{5~8ZUJ)FGs}O7Qsj#4^q3oMdwJ(TXc -zNXAzB0QX{HQq31O_B`wv*mZR-8f7rcU{cK~(!WjAuf*{#xvz7n5_i0Rox3_RLy1-g -zT7QO3=h)A=f1kY{`w;f)19t9x@~gH&NuH+gchD|(EbQBwoTt!O$oLuW^1|zU=3_q} -zyJ;+x!!*L^#)8DvLR~)S#kDayu5L8{W{7JL`->5AO~T9>; -zmhxb_IkukrvY%7d)U;0jIZ!29-Eg{k5r0iEPr>NMjQHz<*$&geaiR|5_40svZ9D{* -zKc#=xJBj@$?5XWMgpIJSP>?zcO%wun{*TAR_*?I#+rZ`9bu -zS3C9!>`{9K@ihS3q>0 -zruzT%?U%kNbD0BF9ryXF&1ZGk*BCT}X@fZjMz_|8pKUPfVN&^#`DG`yUV{DjMfB~N -zTSB$E_$cQaZSkozCO)kf_`dI3`nCy^2Qyn{zK$w`$-dBh9aRrg4WpYEqoQUMTpP9l -z_C`a#MX!gt-2l_YvGvuqP#>m!*{gBM#~^yI!KQQUw>RFwV&94V1&v+mC5w7`3i}kt -z*13u=FCU@j;DtlP_D_92Y;-CYz%;?!fR1S{=z_ToMmHYB*C0$QjBdUVW)kL+h?p~e -zWo9H-CDhGV(7Bdl>&!3t{o>^+wD+n;a~OU#yx%weJ!$Em7MNWy=>aC*f8ui+K3~S} -z+%xQ*!O5+&BH!`eH{Bj*2*bZi+EDy*+whl*Nk(t$~acr?X8s(PXSC8 -z8i%Wl`?p7IJ}bw5Aa-3|q(57z#iL=I??}Ao0lz<;^=on9yTPK_jpnoe(&tf_p$JC& -z&f)h*=s30e^H$%lrgn3N$p^fycExWA%+lTF*lHpeiLHa0JP;ixwo{{H>qoN~UKg9x -z#uS?CVK#7V{o{*%d*k~AzV6`vK5RC%(c!T#=~)}C!r$;L8TLaQt97D2L#c%MJ4~ut -zlR9d|{*uNnvG)*9KlVRxY+albPvW_djeQWU>;7%-gUJOj887l1jOdu=;{uplV085@ -z@l?QUhSAN((!NHRtuWu=IFUoI4ny~ax?z{iq|T+y>4VtcL2HGo#U9stw?~*s7z>RL -zhZyhsBhn`sFR_1t(alBq*u_sOyZ9)>z7zY|As^~9n|c_DLpLYpa&9}!Vwf^jC$zVf -zc(=oy0H>?5aqNd`?9vAr)Wj_D4smQ9^o8*FNZcUyJ>E*hJ09wTyesFB&5-tuRYfW{tm=#;Ai^v9m?yo%qduo4wlm -zq09>L`^PdbNxi54$K4wpk%ABHjmm#ZJ;I-)`X@&3`Le{=0P`Y@ZVhR7HI55uRJqUo -zM57<(7igsFd#Rx@?BB(HzN+EWkpHfpEw-1*8Jwb+@qgEBnR7Jj)u|Iz@3PuIjMx$D9H7O^g5pEC-(46RhPA#Iw${tjA!`9--WAn|68@(cnE-8foH -zeM$eweHrW6dy~h}7yWT0@z}pTKBlotUuC_*yGz(B)b@Duqw=gua#I5P2CObO)!1LeZmP8wm_3?! -z#78&wagAN#9mM`T_Jzbd4Z90g7jNe8nG&(<;;d`59AQuG(PiT -zUW75lUG6fvd9#`N>qq0e64x;);&Q%G=0CsgLhrP_dY?8rg9~6LVLpV8uGT~+NR1`ADKsCqxLH@PS?U7Hy4_howg*tlIeUWr5>&j -zPB#YIupgab%|5E$NyT*_HT5iBTA~12HR>BF10(`;{D+ -z>_0Kq;dS#*5%y;^cJWtBEk26fnSZ|3l$;Y~{*n6GjNbZp%=>lW2GDJSJCS4S7Dbo+ -zhWdLGW9T)*mB6WWqTa)sgXx6%V2JUqRct=DUyH@Q1!EfTr7+uIOmk-~%(D?pE6f0l -zt{=Et!w5GwJX2KjRx#H!kzAKcTVPoWB-(EA|UGR`Z>m=D8T#c?86-dquS_R(Ok1=zqYQLvFB^-Ha@zrABNqu=Ng3h5R9??Fz3VQ+9tj- -zUgvvs1|6y40+=gdzQ=K*@8UHa_&ushxJkG(RgO7Iz3ys)vC{UZyza6&uM_)!(YQLK -zp|DHGyOy?KZ_(Jr-!}Z!VV~mI`sHVm+o`OjlDARx -z@+^IS&tN|UyRN@&G_wB|i@guVl&fNxTo_%hM5lTIObg7h=$Pir9+;D1qUuU~j>6W! -zn&!+|n41i-OCEFH;QOjD=^XpD;6GO`#$JhCSHD%*S7Sd|JzsgpvbE -z<#-V0bQsu-sy!AkVTHF^?HBlba!UHtXn -zuh;W;RJ6Y#^lA@C-4~)ai{2&Jo$Jnj-kcnN=(;m|lKaB&#`=eO1xD95;a`xXEoUGiqO~$b0^FJs)q9JP!IMR?4~(u80Hoj(>R!h*$k6v%u0XR -z)X~k@oqgkEeR7>B`^H@Ol3o1%6a4vV+|GW$f6gGB)cYLVi5y#BQ*=YuEp6z<-nHL& -z-LefP2gY>WG6r)3jA?F}gDHerp~g-;-g85V+x`dp3z#yM3GLY>ZRp%_j;+cRe*Yfak4~fcY`VVAGN;&cVmH-UAw)_A$(S#KSqhVC -zyo$XN`!s%1*`@7`*k8eJnx{Hp{hFfA}IMa13%^QQ&IJ_?(;)ExUP%+WBWF`P5a{uV}8Q&KPG)RZuPm3n#Cjp2G3 -z^X{k0n5aW<99B0bTCqQm-8A>~!Tc6R7q|Esg&Bic%5h>3pu7WMQ3vA3nX9kg;K%IU -zg9y#lx&Pvx_Cfk})yBD(lWLrb-P+CCjL%g05_>N8H?SYfaU!3}KE4$D@35b&+F3`vXHPbt*TPJ|nA+Y+ -zO$u`_ytTVFx$VmLHKg{2;ZLLO{}%p5g^$lwlWOfv;{P33UG1eKvJ<S^wetHfW?8FH#4E*nflld{x7#1Aose -zu~flL!|D3C3HvJ=yUqEX*tcUh_3;4AA7K{K$5XI}9HQ@Ii8*smoYBQxfPKagb2;`` -zBVulV*}K4)yI}JpVjgsvR542)cVa&bjZ-;R$BK78 -zc2mxZVNQoJ<)a$rEEru|Wgc&*E=yp#q^*};>$f$u=ajM6hu$_=(;O_^7~EI{CwY^4 -zpM!Jew0~aX`}Xz%p*gK!FZ=9F{hU@UwT9i9)4r2JFEpn$qt^{@%3(LmlQ6m*I{lAd -zVVrtdox-nDFOr{GG&jC`fABpbC*Q&6)%HH_OTaDVoW$5s_EJ*swb-5ZzIJtT{*?C0 -z{8EqJK7(EtdOJP6ubK61^ajwo^)UUomE6pr*$U(Iab*h4P#^U!~GV{*#9uUhcT^tLogFChohP3CuQB6#QqBQ<5YWS-OHGZ`_Zj? -z`PhGo#`&s7Xx)>xSHS%R&eV44msV*vGt_F -z$L9%WhLgK)Huf=M7=ktBbq?l57}K~apuU80#?>0dr#C++<0=Qg<^SdRV3xji>ajOs -zH`Pu%%zZGX{E4saaJ_J;#-`+89Q#)6rX0lHVV?nG%7N6oFisBEU76fZN)E(t1)9}| -zoBcMzTnA(F+lyae9KX9iVe~8YG!DOFnS1Z@l@z>k?^5ENBZe*Tx)_A9=go}NrPRCV -zJjk(iqvAJSm-l$rAu=}V(VKxa^{up}2hHpw+&L>>(e&z0nX^Q92;H;cKg@Ar{D= -zG37_v+YfhewwaTdCg4ti)5R29v?!L1-4s(U%n1wdRR&jP@KuLhVlnw@gE=e0mo4pw -zyAIAYw#Q-WV085@dCa74ggK96YjV9`53CK|-yM*;DS~?t?rGr$70#=*w|EQU_;ioM0;Y&D9%#q|meJ3vSfJLz#FuL4Jn@Xu8VVpU!Q1KgT -zlMP#q-m>@U^@M4OV8mxXK1Ijrqv6ZKc}(2-;Z!%V`g3^D5O*!IHghPgDvq@5qHWt-1OV3r?k -z)|r9HhcW47ziUyfDnh3i=J|}h^K2sm?MnNPA5S&R>Ih#gFgF`~$yn~EcAH=dIJVyU -zxZnTO@Ab-iN)vD`a5cj12y$sx_;JnRa{%rPIJHkc<7(M_oRiLa4P(kv3Cz-C^!b+9 -z8>sIr7$^2s!I;$8JK=KRoYs`Fiz~7 -zDztg8gxdz^#C}bXQ)92^N3EyfOtH7aEVa$C_rt7$F~vSbOr
@Q!cjXjH6D1&oi -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 -zow@Teg-};T?nq+qQRmLhu*`9dhj -zSf5~Z_vfAQU%<6E%%`M}FIDus-14H0x8`NS<7(`<|pE>`*!7}Iq_-O0T74dYxloS^t~+nVZm -zPaC?Y)#>}sCZugJMKFQ)r-;wJq;~pe4CagoW)7w_g0Ttv{0OELraXeFg;^KDw8B(H -zFnuuBL@=W;wGqrL%*F^Nhq7*nU`k+ak6>zGnj@IaFq7fXw2%Hu)2QsENqt`PtJAWF-363$%Lg3s)micQtde6d~%&~QVq6g>w){OYw -z3AgG~uHQGA^fZ1&Gsd=Z3Rc#v5SLi5ge#(EF4?%>`I}$Xfm98i|J_{@!H6rO96fdKGX{`D;b*Sx@hqdcAJ+h8CbVj^4^WZhTkk^=8m3 -zhKq_XpSpU?(|ey@uaw(KeGAZQLT}mIZhU`WQ?AKhJ9@crQSl9!mhkv*4p!F})!1LhZt9B`mkF%>H^=Ks`l=iIEE)%M -zoQOsF{kcKxZ(zSlwUe7P{uZyONSkJ9)BEf9JKxo`e!~sHV4MD>wkhi@z83+jYf~Zi -zSF!8bWaCdBUkhWZjV74!2%WA4FoP~*s*OpQ-S{%qM#gILY+xjhCDhM5Fivee&W+|^ -z9uu`8Y!!OlH}TFC#|h56&Rs1Tk3Vj(F>i()f;Hu<7iI^HDeof-U}jv#l&|cwnY;02 -z%2zSW8wN&lP)}`6!Tf<^>x(>~2AP@3C?pVF-4~E&J!M -zTLgPWm|c9ib4M~hgq*)SG)b(*4f;7eoBGJb?#$tZVZF4(9B$*gu#|T>U`>5h3DW|j -z>#G8ETJb5&|H=CvFY$oN%Z+z`;I-iU9^$(X-7{|6KX2;0QJ4xCQ{TqKkio%`n{w+W6u;s&!*+2U^i<}{e}0242K8B^2vI~u#=uS4%o -zv@*`+9SVb1F*Q@;X;qrFD$#o0ptTvTCq1ofvsO1+>38YdDD^(=X^rJ-b1HkyX|ygv -z>o01);<UW?D>_&xJP?&DnIe!1kV1g;8Bm;d^6xW|Uw$^Tk?Y*NFWu#dq` -z%Y1O6!g@9Qm*n|i0RLCsW3J&Dbn9T88a`IhO;N*AGr82%{Vn_FpX1od4)bZ>Q}ZPC -zo^$X1`L~5VP+?{N@y}oUob3m{C&O=k!A-$kE!@6i{XP=T{hoqwU2w;5+CTq4GUvP& -z}!*>`V9Q^FE1ABX%e6zfyEU<4m-y^Lch)&?=;6p7XT6VAd)}D`&Gl -zu4c3>>`q+gnYB96y2hY2jMn*{)`5C0nLlP>dtm=1?R|5(pMP&Z^1AeDd_N*N$-aQ^ -zq<+?H- -zRv~sLzr{&ff%$a~tu3%C&`peS>QTLqZkKVdG=eFGc{GBlh3Sr9T4A1yVESPCBA8K_ -zXCjzcnC%fv4im=n5ljipPy|y0^I`4kYUf*FCCh+t-5-iTnbFJiumV2WXO -zM=;eevk^=S%sUZG4~+FibFB`;ERA5MVKO6_tc$r%6~Pq2%1 -ze=u*Nlgf|SE3yApW0(0@>it>ld9u#+y)V?J#qU%1))G?>df%sArhWe~%n*#OZIa6v -z{V$BO4y+6NO?$(em&Iq!$9PAqRj(&ZNdzOgsDXI^om9D!T(lF@hQH3vXG$(!%?an? -z05un)w++2>G(hlCME@H!>dbMfcA~h4b}(HD98+6U|2qwIi`+Q#)(^=EnMz -zqN#~h;wa;s)8267ct|-XzOM|#AwHVmPx-s+W0S%geDrb7@=4dnjmkM19~1CLzv=q8 -zQsE6gvZ#eacDX*zR?bP`L;Ah2g6nq8*tW4(V6Vfj8;8O)E`aHD8QqwdJ{TePyYa<# -zm)`_FGF%I%tF<6}j9TcR799R-W?tHAf1GDrni{vUmtfzDT^FNh)WGz@Eaf;cC$I6Z -zQQL`0G)ggB`Qey8>rF{98+)G{kLmjvQtv-R@7tm``QA`Y(jN5$Wj@Tjl$w0Ny)QbN -z#3t^Gitqe&ticcNpD*M%(GK>DH!9cTR<{gf$yRyT5707=tdK=sH`IopxVD5woznAlg_@!t}#(+f) -zHNzYw*V!Kk`&^vqTxG}0(|NvA2!G=izI!g`=7#ySZC>uA*2^myhz}Y1ANwR)k^K*M -zKRS{9Pi%c~PXB-Xh;aUb{g38h?F;Dt%XvNzXY7BNCKzM?!`y9Pq|TdRHp2wIJ9dtI -zSMO8a<*0N2pa-r4E-G&$aI3z&fBrJG6JsaJl~IB$u%6Sfex -zc&nS^>yp?&j?33GZegRwSR>qSI8&WUz0bfnb-MrXP>jiSIu8Hm4!2JCg!y2d&f>q} -zE2*#FrC;)>l^X1uIJSPSXvzH=zA+}lLpZ7T=izP;t~bQ-O)!sZgtH!rf3M7vA9(TZ -zd!pxkx6DSP?Fz0v;7oZLL@OI+xs2ZmMJv8u9}ynEGw@40-Mm~J=KZ|L9>u19x?n3r -zdzHd^`-gKJ^~9b{#(ZfN-&=fCzrHn~`6TvISSv%(bmH~bH_2xkTF=778f)ls -z+wzwrHqaLPN}e-)L!Xy&w5HK=+VcIdR189EL -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 -z_T@0I7tmf8+y`*F*n_jE%>sOt!43 -zVa68VYXe*roG$Ohw@|Y%y4Xj0)0E(+H!BeIv|W -z1+-VvK)u81VlRhTR)DX`aP4rq*k{3X!02LM0`qzS?X7|P0M0LVnVVF-!>GAw&ZbNa -z`pm_$O*!>bvdTH8UEj+#S;sUv51TZb&rScb_jB$D_Im7(VfX8|oX;$RX@R+#<@CPd -z#A)&4YN?mRBbeJ^KY;an)+GKm!EAx?+-FGntH}5hcGw)#*t4y$`%jgyN5bmHc^b@k -z7+rto!5mj$n=4>1fb|<|bv_6)r9gkh-{ZUqR@aBoFmqsZeV70%(H0 -zmID2)fn5!&>%(T4H88q947ru};|grE0`>z~T_2{xY%b7WBkX{e^?g_lGXzH0hjlQ! -z!BkSq+51lR{nPMmocqA)`cMWlu0VeiVJE`s#-Sc&GK{Vdi(oD;u+4VZ8({tVAm=Ft -zV?PVVkaP1lKgi@ouEVw@@5e{LhRo&Kb+vzN;;RZ@!YE&N^zKWz>2PCz<^1N-)mhy8 -znfF>2!hHc(BC(z9;?%i8ppW~0l@bA9DZ(Xq*9G%T4XGggzieTSBfA;#de}9B2 -z{(h42JCBz($5T@y@pA{u!S?qv`Ac3qr#}m$=70Rnf%SXtRFC}{O-$lr5zJR%db<{s -zc-9clx!5Zto~rD4GVcuv+XH(otoj^zSvG5NDVzBXiBZ(jQ?TmY#sN8O`tudycLMB~ -z_RqH7A~E#*H9IHi?_!T&uf3gf8CcJEy-|Cq?|Bub5#~V{zx_g(sy@$= -zc}Yf>=Lyv45d5e-SLL+n$#X6K>S6u%iFw#B)x;$G#4?yue!j(bpIA>khhbM^)y}Ux -zcWU=eS!5GvkL5sH8IJU -zO@;Ylx&N3gAf64_)tJr5j>kJ@t6+`Pm`%)Py<@fsHkKN*@*LJPX2Yl}gMO$n8=1qV -z$4vTDeiz@bkKZDe)Ai;0yx3HH-Gp8BXTzT}jM}%o{b_`~7xpGx1y^UY7O$mc=H->J -zAEo-UB!^A+CxWka#Mnv=p3ibRMmf%ZC3#~?)jzee5oR7pur|kE`a7`YdC@r7YVxCw -z&l9p)@9|l3G^vsELQRh5;_r=Aj`qy<=grY_*biaVe){?POn;JdrRUhS9`>+joc;8z -z95$UJiP5;5&kw`;jpJzQ_CD-t9DkDS%Nye)*e7AtIDRji^^W5l*gnrXFm?!O*yP5#*M_d=X3rs4x?WCU{^7op6$yU -zVjyqhxNob?;g%+H8HNlS9>bP-@ltRCf*n~!mfu^dHi`c -z>&@d3YV648ofz-UVbd{2*k#5p;Jlx6L*2YG5oSKj*JK|{9e-2z87|G-XApn0VAtmH -zw*+P<&c6!r*8w{L*6;Wy`~4P}^I`n)HUHr&Bym)8}Zc*7lzC9FZtXs!m8qhJU7Gc -zx8Dde8m0rrZ{HVY0!+~we?KyAGhhb5?96gH7U%bD#l8T$fxWj_#l9T-2I8>Y+b3V? -zQQvVQ^)7uGEOj}Jx9w7MkgDN8Kli3( -zdcDNeCjEEUYuSU$iFw+q&cjH1vuIEJsCxZ;U8aw6Zt8m1Zy~;}f$OaXRR6KpVE4a#*d8KD3}E>e)U?3eGc~CVwLTuVz0&SSFcj<(ic^)AO10u6Q6or -zj=yoQ>FaeJ%vmsg_1c5|SnPiJlei;`7%P~aSWfRluHSVZk9`bw-JCfk4O%ae8hqdnnZ9M!VC0948(eSW8o|$a>=Uv3arlM`u#)ze{Kfzj2>0*CRNkL8(MJN4UzpLUt!-&&h#FZCSnIW^0t -z-!qZ6H{o|ihkx7RcO>;AjPmCJ+2JYg~CQEw*S&Ggj3oyi)ITAKm0*V^7|RdTfedkDL(MpnSsd6+JkAk5+T -zbjLEybzBeri0`q48R%x5cgiBH8;QM7o^~o>BwoLE#LqOCA$k1FD}Y&60JF9LrY8?0 -z^W3CVZIahLb*bwPVJl&a -z{@{EkTK^o@bN_V8k9ijawzqj%d^O^00`^;_-B&v@{Y|!;{%nh|OY!w2Y$eO-yf}Tz -zex|t&_Ep#e-7Ir4m*487H6rVm@Vo%VZ$FbZN5Z^OV4Kyje}~mQgPacYDa^UjzURE$ -z`z)h{`aIx|PL5xEJ)8C9cr`w6gAKcVx;`tu1z*##s~q2)<13wGsrizhn8s_c90&J4oG!nUVLpcO%dfOI3+C?ywATXHcb$K3Wvsf`F9yP>8vgNX**Wvna542U -z754jV7rZTp_2hTdBc|~ySik&El)A*O@>`YT%ah;f_^NB!qRp=yBNoEl4z~x(={h+# -zbG@|!`>oh@x$T1aUY@ohxDP+dXG!7w>Qtzm^3%d+f<$r7r>&gET+8*?lfBx6v>x)$W|G6f+T~Gcu{Q&H`xQ9H(v)MdtN!;V% -zj)(KB8;NHM%trR_-u4~wF$;SK_9~X$b!DBHoT%k^wwyZdfoYd>-QmB@a6ZQ~$=5pk -zzLqEV5?}Cf<}uAUkHp@cXPhfx{+y?+2yNBEeGccBFNwPmCX^@l688$Yz2N-Dc^&ql -z*mdJEL?`NbXl -zDfjKL>*5{-^HiR;B<^as-@xhOo(|KQ$Ct#t5bh&5zqnUme;>Op?k9}?>_m?<#2vnh>VSVUA$g?T1fM -zr>{3_VZM(azj~IOH^STn6ZZJYocAxoegk&Dc}8k(19ko|OgYQJhub{yT -zbvRGV&UZ^i*nT9;Y8YL=Dq+^a`1MQtOoMq>!${xf!EAu>tGAWxOI_Giy}kL%Ouu~U -zeG~kucb$5BHiyrtw*kxf9AUd^--`$1_e>yyJ?vwbHpXNBi2mrtdkV}J -znDOxLKD)iLlFHmEWJ_upYm&U_Vaz{az01@w*iE -z!M`|uugzgSex=^m!K!%A%wf}hBlKs>3XZEA^f@2)9G}C6(dB$R%w`zBoJ(6%V7`Fa -zmt}YT^I~uMxHt!9D~w;w$-deGv)^BPuUoOVV;_Ls@A=?H?1sg$EsF?svi2-^s&`g%+@>+S1G*tcQT -zxbB(5diuJK7;k()-&fkIP=o1x+x2`wYI7+}2W{!{+yQejVvwVGvr8-d|gER4f~~OL_X~OcpJe!4tp5;SuDHr -zY@L$H&t#Y=jNf}Ka;$5l4y#~H4$r}_y5dTnlXSf%f;&090^kXs?X3Qr2m@IXe -z-f|V8yKAry(fAN%Gt6!vS(ncsd9W)4iz-}UF(Eie;cbm!V@U@n5uwY3>$W}dc&{EF+OJZ+7G>B!U8WSB&r -zwr0VM|Jc7@G8Zj@ITgmQrdMMhgI(9}jW82nbk{QjUg3I66N~JR71YlXm^jNp>#59` -zruN74GV^EzW(q#vhS%M5o&(bj<2N6PpB9JlJ3dNmUBtFA6hfYJ52(P4CbmU<6vcE;n?C-e4s13r&}&)4S& -zHFkQ+Z-d^i^m+VmOyg#FU7x4G+zO-X^BjlK^?3!c%}d4h=}+_ac^y96;B|eLJ_KJi -zjX%KY=8jP?JutetqY5VWPycyL+Ny=AhS9av2y-2buC3)TD>QA%oVgCB4W_p_Q|vw1 -zANR4#F|Lf7X~Mpm<>38GGx<&)-=9kzCd7UMe46Flo2%ILxpyVZ -z8Jhl0#U90eMV1e_<0wufM{{Am<>N!_E!Z#dvCDW#y`PF*jn{6je)Te5TkzEl+uQk# -zv^C^+rtxc^wj$WevHuLaZoDSJJeh}?nTL__T1K7z6hCUbE`B^S20r7}fzS2uy7Afq -zWBtp&9*4Zfbsau*<24TEARix+!%5f&`PgN==1Q&7h8nNC9?SHrm+@MHulw-jH(sl; -zf5)e-2yJb^eg$^F@sfCpU+12q#zz_UGqC&RMB1r_nXhR_nCS&D3kqOX6u@*9zyv$; -z$2{i=fb0gT^ug)p@+%U}*=+3jblYc6Soc@f5Mte0V5;$xS( -z>cD16}ur7lALF`o?JD+E9-pv!H0;Ubduivr{ -z&!GO+!Ei`1f-gUk>AR}+zzgp86vXEOe9rj9zg~q|Q2^5g^G*Ed#x2;%Z{))G#V>7* -zg1HYyH*QrhOJMxQZ5sC5ee7yJz&;&&A>+0jb|I|axUI!L3%hRIdSF^${Q529Hd<;C -zMvdDM+;vSID}BbT`c1AsKhuxf^a7X#Fc;!SH*PCnu7>f8U&gHqW+sf^xCs+n%R3nw -zKaz)X>gXXDm4|beX!9WZ)kJ(A`?-HD%)ma<$1X7~z+Qy?WR}x8=bYn4*L<@A<{%ht -z|6xvm@tgOh?t;HhGLO33O3fGQj(YN*US1=`lfyi#=(@q6cK-Vj&h!1%bY3oJ{bD~mV>7~>|$mI8iF_5)@|N%k-7N0 -z5x%!$n(U)3*yBESX>T3voq>I$wD-Y7x$V7^X-{(AgTErH$NSy>YMx4eT*MG=tkff% -z+~Wv7?efb!bE#`Su6mp6M7Z&A>3qPr-}9-3se(Bqi%ET!Fv9vqm~&xt$E@WrQ($y+ -z+B%r4VEo3Xm^zq%U5(FsKg`6On)|cHr|cc(CV0Q`slvY4$1dYjPkVE*tMR$Hm-e#8 -zXCeM71Np~C>isG>H9lv${AP{MM*Lj^H=bDh#%Dkm_o`rY<1-fKZW!J8OoVv|MmIk7 -zFiT+k#z*RXK6W)eH!RA;+{^e#ownoeQ}|Qe{p+QkgVe>app&oBF27m%8ulmCh`^0^ -z`^&25@i60HborVBb25xBUvpq4!1(1WLJTc1=jUP8z)Xhmn~$XqgVcdA9kM+32f2BD -zIWtd4yCdJ_UaRfzQ<%yEm}xKp{P>;I%DLD)m|b8lW;tD>sqsF`8`lch3RqoUyI{Ve -ziCyN^;CmeZVf^;%k=VoK{@6byCg1VLz8<^p_+$SacJ27Xyba?Qry75U(T=|pi=Q7g{?v%X -ztHyuQ{rShgoA*HSj>XCv)Wrn4@6|*;h8eUIXh_7ZLmwZ{WM8HH@@5p8A>wvxw#35%*?dOJ3jJEi-iL -ze*PrnOUpWuKuFLf(n3rJ+ -z$@K)-PhoYro&ocThLK#iP^(*D7DHkFc-pv -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 -zt6Ov0^wiaW!JM<5vY&kmeYAs -zocFtr*W>f6aHYqR?59ix@_TL9}fMqSu%)WjrX6dY<9--huUqp{T071-4n -z4aklsv%gCJs`2$5*dtj^j}dvg*2$CXr&8~YFlv0-ugP%9V{3XpmGN1Gzk#RrsPElN -z`%7}?rS^T<=hou08m>g{_07xn>D@;o@LTXZ_B8!i4ckM{NMEX{N%3`!z6Q)zD|f>UyrXbRsPSV -zq#xm7JS&2!W;xwn>K)S)CDWPjz!(cV308NmI1y$FjNiT>ZPvqFRzRCl2TNdQ!yfI9 -zPxaONdr52H?t|0qUz=eT70_;kwjz64#wu7{Un^kRVRU_+3iIm%+LXRF!u}05Utd?i -zS*Pp!x`{du!>Iav=IYGYChNpgpHlA^!K(UvFo*TjXZc>-kB0TD&#CxYf?d_;#W}t_ -z^*IY)p)>UTSOQZFQ%HSwz>bF1joB8Mav0s14cpr?jwql_8M8{*3t)9)HX3dwwRa6% -zyUbH(UzHh;)O$Bszi}noEMuEcwX;n{{%s_lwZ!w_SMCygX!$z1XFh%g`nsZ(64x>iS -zz+QnlIMLOvs>{rIj`X<_HV(^OBqLa!&3b>cVLI$mSarTLB!^9(??mu5Zy(DzxW+%< -z!YnI*S?e&R@aeu%#}_)+6zcjPW;AX2<)e)H7>ZrxV@5pVrQC~q%3%)3>TBxWiZB~sjB}HpqjBfM{kt{A`|{ihM(1ZV -z%=|olCcx}9QD2KQU?MPnxnDx97GYPpFT30~_cFJw!q*5`&pxll$a`JXgU=J-RNmK5 -z$?}=GE|Po=DYcB1u)4gDa~NHXO@?_9KYsm`dT+t5`Z+Z_rp!Jk{cOS4D%f7G)%a9V -z=03oBeEtJY^)r&~)7wvDKg*~+Pv6gx4x_7!N|-wQJVBhj)t6kO)Ki1z`N?aU;G)Yi -zT=X5`Ank7UiQX<9c}A`HuLl -z#qal1e%mk2+vj=seFI_8D$v8Yf6r|pOasipSxo9PW)aq}gqfG8t@SWZ=4mT@0QZ+P -zZOK@UqmDw8ocfJil8M`=ekb8`9K3EUXTns#=*Duf!|29xEwP=Nimh?7HZ~c{E%=-X -zpRayLQ%85D{8s7xM(|sGpk@3DUf1X8Fl%6ReO}-&x<0oPTW2b^l^5sj^G19YU#Rc1 -z^r57TV-uXNe#>D_fYH_OB$&A{y84|7(*&c-#o_{()desc3t$Eul#GY!&g7HxCd>6% -zxUn!DntsW?GL`yz8%BMO<%o+izSMC!_p@+w@L7AY|L0gD_-ui>5k?o=8kiL@emR%e -zg4979jEe0q7v_y^N|-o|F1Befi(z!JEh4tZVN`7QtW7-xt-@yPo%#Bk=Y3+!)ulyC@GM?RLP4&OtmU{pA3g>$J -zj~8U}oU9qo^>#IEHNNKKH~4H0J3Dn=8o@s8Q0^PR9?EjM4jDW5yLIzmR>An)&tHoD -z5$t~RrSz`@<|i;=Pdk~5b{!)}6|C+sKZXW~xgBK=-g1bfvO -z-bcSu-@jUzOJV%_HxGLyc3uCL!JG`^*T40|JQ};|-&r{^d-^wkTDTon^>0iLo9>_F -zwd^qJ0=9_d^!T~%A56m6I_wpgga0@$!>C+ku4Ux@!5rAlu)EXL`SLQ@qpotU -zXP(Ys)7Q)5w+nVTEO#0B-SZsQ^L)97{%nTz%XI`Fk+Dg}?>t1>oIt&Oik~~A&7*VL -z^xQ+N#ot9&YsMdY1$MufWE_^koCxDL4(o~MAna-!o}H*2hXK^mNw8`h?$2hu<1h~P -zHdu9Cc|#8C8HcH`;c3qEd!5&WRYRvY@VLf9ujJkRf_7>s|?wrG>$4qiuegx;z*ZAKnl5w2` -zGZ3bl<#c{i*GgH>)aJlOVRhFHEilKz_>H}^xd!H#0@{@Gm>$?mV0G6(;&UwZG#&0H -zmVO-dVlYe;#kaR|)o8rQMbsU+H-~f_*i< -zu7lOp{6?4=FolfAkRv(Qg4K=3IGDvSy78C{^Kb!e%6QC$eHk|2c&uVy`U9LAk3|!* -zbL<(9O|YYDo$;8J!+OS}_$bS`6E;jN>3VfNa~?;%T#sFi$4NQ9JmWDDUu$7?<53Uu -zHcTPou>{uontnXmVTxdMVhFuHrCb74-v -zPZ4}N|E}|k71VDTb~Q)-?yL;c%lX9y*a}#6KmMoLtoMF=33YcntePY5%wf}Wr1WF- -zIOe_U{BtbK1c%Y}bq35%`0?xO5@Ont>g%BFn7qe>4%h+sQhojBSF-Zr?W@7~pAW10 -z`bG}x>Fcm#s9{ZC<=Uefe{aIXSq?tn@|T+Dv+n8E;y3`Qv%~x$CBga4&%3f -zNo*U5Z76cmTMV!UA>E6srSoLet*TDlsb3t>GKr)-V3jrOXt8Wg3cKVdOlh7N+m;En8(dowtd}YqJ5Y -znuqFsV -zn1Mf=_D0j*Z1(3<^M>(lK4j?pM+3zJaaCzwXiQGJERON_D|U@B)%kY?f6ufh81df! -z9p2lH8K)#|gCaKHPEuj>m8CbEHecY~BXLSRyO`mqeN12?5zzX#Q_Zu!@0s=`f!PvT -z#?UKItbNb1uQG0R`mVB5hX3>ImHhO9X|Li(Ax(QVUrXx{C5K?W%zlwCS~TsSn#Ln$ -zMCEk&@%E1c#$3~G3K+i>_6L@|GGM%6jeH_tJQCPTL8-wg-UDD?`%q&%e~Cdv|^Xq?Nx`A;?xH)VE}anc^@-{Ir!O5;KYKb*hk -z*ykJ5lK&pKJAY5M=kdj_gKv}(S6d8;@VDH4oUf-IypZp-7<{W~taNPQ<1$+huCd?d -z(VS^N&k2lWKf)t5E9rr8ILRD+DE~O#zRR-Dzn5aTU2GdH`(1t&F<^g}^OJzhH*S5V -zmS+Yr1`O-lW^%-;TbVZz{VCb~Oh(N9Jzth&TCea`u&GGSv9B<`m27X&mG*MJRKtFR -zZ@4gJ@fCq2ANTKX4m`j<$(EeHYuaOtyCn=)OT_dP*Tjgn1{`2L8Za*1YTg$x9uJ7` -z`wunuJI?w+z&Pu;+XKc+roGrQ8TGp@^KHxivt`T**sOm@So)~`!_Ut3{QEZ3ewJUd -zGn1oy=mGZ3pwVF3e+wA@FnQAaeaoH`G=6Te*kRc}2pY2k5gybA?AD-hbMRCZPyZ44 -zskXl+Wu;bxkF-xq4Q5G&{hUcnw(zwx_5+zADk&Y>#J8Z>zcY<1rC>jHwk_G+ewuGz -z+pU?eaF+e}nUv3%eY$aR(*J%^5c|m(9d55NjT7zX<+l-N;bQwfekIPH!`F~Gn+-^! -z=NRKCzblfP_m_1S+i~fqig(a4_GkS1l>H}u8ql;~V|bhj@iiPVlr7J(8-wgm-whhy -zH|@W2%hj|y0>&Rrds#p#ZFazT(z3VkF?P#d6fl-a@sRb%a2b)PeTPL|{EC-!O#2DT -z_?>AlvZU}7v#adK$I4uGt>geit={=4*$HaxAM!Pe&Z@{!lEHKBnHFgzA#{nwpPKgH -z`I^F%x9A|5!YJ>nY<7}IWm9Tqj%nU-jD1Vrz*qPDFdSe9`F%L>vU&C|!-2=FJ)R8* -z)?0f#5f0oRsD3ycxGA{*hkXLS4%#et2lu}v9B8)pWcl~D{XjVIH+xUWheGyG!hsh< -z2eR$Wee9>gfk*r7inmpLnGH7gwU_rb9xOU!abM%TB71&cHS-cj_-CqX`;M?%cmdV^ -zBj0#q-_L8$_N|ujJyXWzM>1O*PdJ?^9!2ygF>$2kn&dQa934!iu9wcr{!zN0{f-$p -z!+zNeT)F?x%)o;dQN3!}^Eo}U4&lpDo(o7bay&4mKdD?bnfuyL6d6a@&-O7+w;wDr -zF17C{V*mX|A7i0u|EZ4*_;35LpUCRlEW0IaJZ9PVg^gdb(}ZQGWBtN_{chNJHejy_ -z8*2jg3t>JjFY6Zv?FD^}mx6XfUt?|1{#V%eiETg9*LcIWKksX7vh5H08jC{qn|+NH -zA$v7U$o_d>csem>lve%?*=rhRjf^z-k1 -zrJt;(pRX24KUWkz}vnL_gy#+g{(#_}I4J=x010lJ#vNyQSFpbI880nD3sqZ!0!_-N$~u -z*!Wi;`_BHx{II>X*myB)e^6|^9k$oOgzeuH8*Tl!XI`c+Re5=wynND+ytIeO%Z7gB -z<@f!_%dEbVmyg4em#(nnh1KNcxxSK@NBc@%?(HjiVLf?C^p(7AR_Z1m`3fi|784uX9{wdpjx5((Q?KMTlUv2w^BIB8my}8Kf4%sjFGj3wP>Sz44 -zkNv}b#&7!A^ZOZp?PK5E&*?0ZKGw2@D%&%lyCWWN`0@kt~G8-^<#h9J6#T2oZrx+-^fXx -zY!<*YbXQ?{!y@!_=05F=hY11dP9# -zH<@1q_|+!6Cty6r(LZQ3ITLu_BV{T*m)pa%>G{Xb2ioiSHHx -z&>o*UKbG}Ao9@25oOv81!JjGv^$l4{9a^-;k`v_MIzbNKar^en!6!V<{t5>`74P1= -z+wYskfpP|PjJ=faypttP!hc~JA3FWkw()<+SezWXtBlK%Cso?6$$+W-WQ={JaauB$ -zp26M6K7c`^ib?bRyPLbn9(bA^H!tDucg>=6oHIJyq&5qmY@d-j9EK0J59cgd4N*z? -zetd_KJztFrCrWqARR-G?!lZns{_cFd{ju!ps*t%J#to%Di|28sT<*+vj@HAzF6WGm -zrkq6H893nfps^uf&kY(6Is1~kbi);yv&Qhgc9|iUEBK9-+Yi`Ao!uNVW^&qW%V{Rd -zi#Wdx8BdyaL&$j9wA*asbJKpqHhyZ^>usam>M}Rl#+yNVgKhjIl=O5^)b6slko$ty -zIXK0Yv#ve3#Nn#!`vK!;>MV^jf`tL&1$9=P%qUl%$pIjggO0T~@Op#Y5Rg9o%QAj% -z?(uZMm}S{_2aIPedr83Pv~0eL@>h<7Q9~<#!HKeIzaKEV*%^X_H}LVGu|}OsFALbW -z1dSJ+Tx<(FwA_B%WDacQ$2(++#BjN{$=T7Ic{hDd~|~%>p6?7p2vA%#@vH{|HZW1sc=hdKep^YTE^d<-EmvSLlx1%_F2Z1 -zWMS-duuT0k?C%&4yUR>Vs5xt2bLfFX`M`*II-uaV>76HXd>+oMKYc!(i$6LZOG^Lysc14e=~!vMcFX|w!mXLcxz+F53NPBD^@bC*cZvN1;Z)29V%9vCC%vBY$Y(VDM -zXC!o~7w+j5SXaX{gYhG)%x5g}H%f*6ul3ZA^E~c9GBYIW$F+B5&YIclTxSm3udluB -zAW~Vqt?zB!F5J|h>h5M*UocOvO?4hR$*ms-O7%1 -zj8)BbT+&7Qdciy2i2I%5FgM7ZmitWZP{Q9o+#Gz2{Tp>Fx7jpbGK)AJR;T&yIZTD- -z%A)++dpN#-PqSp4oQY4iZ#KMo8c-&;kdIqva#F>4io~&}xywj< -zvU#|DeBc6BaOgiXdD}w5l=gPrlhxs`%*X%~q -z{Ha-Vn_OL`gOk|Ym2(p3nU^^+72K!$2bsmA?F-BrHmof=)!lDb-gX^>`DD35I?Lu) -z(cW-o9CvEm%gNaD#IVPK_C1zy?GX)@+&=r4Y499?Wu|{MzJtvE!;ib(lzY~9m_=7Q -zffYFJ?&O9uc`0~~@@((QgQ}e|_Q{N=8e8wbsRiwL<*&7VTvXp>8c)d}7h2D -z*=st*7yjJ|>aDqg>Z6dkqY#Gs4e31g8Vo>sZ~%Jmz;aV=5R+DQI8bBgQ~RX%410+w -z2jizRPucROglXb@ZpF-SGRWwq8Y8CgXfAZm@Jp^YHo;RnlRnOE^qSR$tbe+l6#nfxXf804gbf*oOFtL_~hLT;{lVWA@-}1PIaXI -zOqP~f@(A=jOD+u51D8eIoHdQ5a$=czs~$+kG4l#jrf_n -zoqSc|XZ&{Z)w6&HMreEVaVdV5Y$sn+@H1&U`5J*#laDyLNwrBP+J_{u$#$#k| -zKG0qrFfKo|C1^C8_B#RNEwh5<<(B<|78%k3BWWE8FOe!wey7qDsH6fnLptxcBk -zkY)eL;>i;4%n^3vXz0mum*Wo8zE>V1TXWPyWG)sqn@NvF)8stnCbQ~4xJ4mxY+KKW -z`YDO}G!=Ef<9`zPkkmT&EBZ}(C-8jGc)_{rIOgcH4TD#Do(dR0mziB|d=mYQmwB#Q)&F4L`kQKh -zTN12R6iXG1+2cYU$!Gpuw#T{LXX^dm!+EXgxIL~i~u# -zKl%LaJeO~ITP%@0OtSLN3NTyYq$^N(IR)Gp* -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 -zN>LQWPz{QsI@ExgP%~;pZKxA!LPSlMOD0C9r -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 -z7f0>z_Z%gC*DQZr>8u}W -z|4ja1zQnY{-*uAu)DixcU#P!l>+s%Fl#j*!^mtH~_uOA`#vcdm@TE>uzGvw2whS+P -zhUXyUAGv?AGhFX{?w9S8adD?#P_1RQpCvtB<#~whQ}9B@GgJ%d?d5(Wzclv?s+F|A -zj2F)Gi&3`!hcDrLN8qx2ynBxAt^8t;z1>a4;-8a~F8^}-hj{h5Iid#VFFksm^SjkA -z9=G@Z84tabBkJ1Q&;KFBhQW-<X;N -zNqY+K`WnAGXZxwk%-7&*d*6SV4_&0UkEh}xn75aFMX~^c`>Uc?fKdz4Vc)m+?T&a&&&CfGm(oe;|9CxN~lQJ&x2m7n**@OR! -ztN4fT@TbkH95K;8|4QXtVk@q$X9r$zn_u*?@82NVP&f69zPA64Hza?k<4?S%X#V*R -ze{8ir{)!4NF&bCL?^4kvKE&1aoyKokqmRF$l1p?Wf2sHzRxX|aTX7Zt)EiymDO{a@ZY`HMgRA)8$1hOcRQz>n7cGCQ@z}dM -z{#)y~#1dS^{~3M)SNW^oO)fEDy^h~QMO;ApGubXL593uI@QYS<{yHhQ-^cvF?LBYC -z+f%;n{oluzbmX@+Y%g7p9hpyi!uEdBX`i04eY13)KSXV>QQsvd+^*;IhvUBg>G_>f -z4P2r#UYY&V?FrtV@t(XNa(=B4AI$a}?CsYybcq>`@N4id@tf`Kts1$+CCB#5c=Pvk -z{0keqL>EW=f8z$*Rs5rxxWrhzz>cr(EtDTz#eWP>Ikqnhx_EC>$KT{um+0<@e>&cl -z?J9m33r+^$D*pfB%W)Ndzh*A6*Rj1;bDkO|bo^i9y&ds4Y~d31*skJVkKc={_=mT2 -zi8;86zb*;C$+7)c{0gq_|1>hfKu7#1@k$@)`1{@F60L9*f8_#~cp6vne~qtpY@gnS -z`WRR7-`LhAhCAY)h~HSK?zF@n6Qz -zvt8YvAt9G2_o0rz@|`YmKd$2c9G~Ra{$zXVYh0awi4NpvNBjnUi0vx=t+?wW9sgq; -zssC{mzyB_m80y%*5nqR^_(PpsVyYwlS@=%2tN8!K&p5)*znl8!V;z69&Mwh=fM0AE -znfCDuyr2jDecOB8;}V6GZ&e@c#zkkp*kNz)(}nusE?r*t;5~?69l!RyF7b@RjC -zU)R;e`>}feCHN_aUw0qnf1}x!*?||{>=(D%?lHJO_(SS?ae?1&`-iyvogEeax(A3KSNlJO%irC3z~28`yf=QY -z?X|lTAKuCKF}VCao{;TZ@Cn`g;#GGheGWg!`O-iC*7h4-@}Ae%7&O -z_J8{k;^TT3+wNmc+7j-^6SfcO&Hml}Vi%_&#}7~U;ryTUi)-!eulHqp2i+gOz8~R9 -z@3r>%y^a_3^rxTq%JAp#s)PKZm%Y7Bf3|n^r`Hq7?Mv{&d3t`L(g2+Bbo0~4AB&6r -z++X{Aiig?W%g_4W%=V}73B-TQ-v0pJdnnJ3?d{=5**=)(-?ksbdq3?LGTX}I4;;w( -zjP(n$Y1$9r6YlV*+grK4&LGa8_Di)_5xkJ`(>VKhTk$31{Ng?P{`@qU?T`7zJlj2w -z6TT1QGux{TaixFL`dY%v_Np~rmFEk^((#q$9P~%7-x$XBbM|@|7c0M>misdwEI)F6 -z$qV?2ZYq2Qu}1Fi@Xzs+4*v&N>s?&LpFfoR7)K4~r{~k8hlbPttCyP|&q_ar=atA8vc8et>j~1kxi38)k$x8UznGg|^CkWM -z5!~^&{Ni=?uSR-b#7~#W%zswnD$0y>iQ{kPrR!h0|3~iynVb` -z_`-g5}SDE&RWN(Wzh{e<+KvGh+r%TLcwO8*WYJ}p=Dx8v(O -zj{fm8x!L1S!&77Q`Q$z25+%#$isJVEv+!dg^L$Lk_aR=v%uDyTq$lyz5q*EEjdzI= -zg+5VWhmYgNo_sOG_OJ1(<@Nq4d~pfw4?gV@O>=Y8>yl*ryYSg;_u1k9!cVN!*W2+K -zmzcjbKi!{|`;Wr6TRDPhsC0hVgx3oAL`~Zd;b;HI5x3cX=d-l;eRI?ORT(~x7hcIv -zKkt?P7e0QOFTMUr`b`t)f6mj#UxKGX`RVyVxxMj3+OL9q(b10o4SbX1e(%7qjMex5 -zwn;A0qHL~cX769^Ir>kx<_e~D(&v8=cb;F1$u7R{J3n1t%HtiwANTA0TYL)T!I6HG -z@lG%6^L0nbKaTwa_>rnQy`RTRa{Z6m$NvRy&?z^)en=kg;pge!l+ovZ0yjR&%jW-X -zQ^~(Ged299{Cd3WJHB*#Cd2z)aES+UaG^)S-NgHM$roGg^O-ZlB|dssUvH_Iq}M_6 -z3)O<${|Vd~{{{T|Rr%Tc{>&`$YaJc_D?G86_Xh0vf5*>|p8af}G@JWFepL0t$9T`h -zKJl%6yyA0Q;;Lpo(Zt@r0B_$$$3GPxexFY7`g0kde43w)Zy8?bxSlF6xx{OvmmI&! -z>)C>TdRKn7Jhzy~`Bv277vmGY%B-i7^ic3T)wg7ru_;H~WuNc=@WP=we^q-#rgA^pK0eA)Z41m81Pr{^(z -zdn;f1`G*YO^EJ-zS6v^?!t3<)iI?p7|G=-@tn0ryi@1N4boqN=G3m*AX*nL1_s_)h -zdgN!zL$}w9ruQs-W?rti(~iIV63+k2%=2b>K0WY#9$miP!51{u`Mtv%jEDa6iTZZ< -z7xAX0a?|~J8NS6*-NTTrau^?XB=bB&ZeNejb);vpHyMwzNKDoLJ@6G~etJEj+&{R? -zCGK9O+l$fo;HkQO{THv4(D|e7a_(0Xeg5CzZ8^T|U(5LZ#(O`UpKYIe#|b|vH(P$c -z!=HUWFWo~h__b%CxqV -zmlze*{h2NJ)*<@%4HMMwoZnD8zD6G~fBSb{HowiqFFlc)P2VGU>5jVp)^r2&5uaq{ -z*W~qf!z*{pPmgD$kNA-Ly-L@2CVuZ8U$*_u|A^!5&Po4%p4`79p14QnhY#@XAL#O% -z`!V~IAM4rYI|Vmd>ix@Y#Q)R#cf&hv(&hab{KZ+iKKmZ8PkX1@o0*?5KXg1#Otj7{&KG^`_gR`~8idEzEJ{9$}+Lig`Fd`ka}`d!tZgYe3ubp8GZ9&qHZr#>UU&(i(dwYd7^ -z@yBs|+V8qP>1c93BXh-*_VHiGXWyHb%`X@5#q=*#dOh+v@lif1u)l0S9@$R&*HxGQ -zWq8jHdi?X~4({i7nddDsza7HWN1o5$xU)T2wUhehSYEb2ei-l1qGMHGxPtD#%*W?ZpLDg)XZrU% -zzo5O5GXnB_H{!mkJ~7(fejZmJncu1%;C|HerRPiJ{#)>eE9?By>Ia@5?a=3U62I2W -zNv}_l`&T*W5^uH6OF!?BE*Ban2Kut&+0J;&(Rw_x2|v+9r%#7Nl=l@n{&9G>U3&a| -z9A8~LKbv2!;On;Q`f~PR<~R2H((9Au@sHv=8K0~2QRxW%J=*)y@>)s%R``;$K5?~u -zKNjI#sUI4$U54*;l=`4_UN%1u#*>G1f9m>UwAb|4Rr@;-Z@DEu{XVJ;-}yN8)nuKY -z-^c&>QQyzoPPjzXAN2JM#G_oFI^UD{fm*rg_mX6MO@5;PxI*_|7T_B{%T2FWm)nov -ztLaa7v(G=8qW(Id`y*9i(VECQ573`i{gE55Q2+1I<>hJoV6psc{nzk6`kRcu)czJ;?9-g={AgunS+`T) -zsq)YauX{O1w6X8cdw8endOm5Q%PpGc>-~SnH@-v7O)|*zyUpzu3le$R`IkZXl0G`W -zEW-Exs{3R8J-oxt{Z_}ns+e1>o~Ya7ad@ZO_5J!CFL^XCJ3shNakuC_U2p#mclLM7 -z^KNTT#skgm>uHG>dqDT^pTNDP_3?M%oy+*dTzmfuxO2YdjuLL+ACjA$KRb<2qQ76o -z-rvJQzL~VwYW&p~-}z>)@Y>tA;qAk^KKmX2oc{R;d;6+?T`j|uAW=7*)+V)w56^m;IvK2~YBn9BT_n(z2B$1R#(%)Fl| -zw_m|~)844`xYp+umxk){`#!$W(cW9RZoXqIKmER)48JDN&3B6Brk{UEKY;(VUx#mz -z@8_>n#S^!%E<|G(qcK9`s6|CFxc7W10rX4|)|_{`6Af9S63-J;`b -zdVF~qU-rDdpLMFr{Hp8sN%+tX`PunmcQv?O?9`p -zo%u|ap6(mm)J;0QAHaW}qwC{E_|j&&z1xR(JFMpu{+8iA`Puw1v4&fm<9WI2zgu{d -zCBAHb>&u#MQSedbd8WKy%>vXn3w8b*gOA#mpS}MTZ*+?)KV{a_$nr24&vUfjFW@7t -z)9F{GmRnTkd4L)Zj>Kn2azzI_z4qZro{y;UOr6?p@qQ&epS%k%e}_Jw4t3l`=HtJ{ -zw=c>Sz3upXH@U^WF1o)w6JL<0%k#H*tMBu8!jq~0tJHOiD=+Bu-iTMIs^=5?-Ru_c -ze3O^0kB-!HiwTsE0y})G`jn3XU-tRO6Zq~OI=?K$-NW_$sL+7&b!R?zI&=K~_`bcm -zJ>G^_8mGgb#~;5_w`c1by2a_XI)9wRdpn+QlxpM_k;*!JTfFOSx;>qXTYu^Dx(Rna -zZ|l{V`lOAX@7RDpPI{^GTd|3o->>zh-~W~AzXTt{{H1!{R_zw@_dwlVmI!jbCw)1XRFMT>E`+Q|=k@)H;cXe8w6o)@)0*}_rPHrJ-ua+U -z{AzE16%Ss~@z>=$S-Sn>%RbM09(U7!YijRbyny?2g!gxCzY8z;mG@(9AB?wdk)M73 -zRxE_hd-zV;+sE|t@@4Jm-%Qu- -zOQ{aDAD!~W68n5+;p>?1Qu+1uj@%FWCk@yx)9)L+qhr49w!65$^K-N9-9o(cFFJqq -z?c^3^h+nS%kmobuZtkC>{$GO^bJUNY;*&e+`KY7#q2Kg;?~cyYcOUEes?0s)Kl-1l -zywvPM{n|A*{eGT2-YVQYtn*jRdnvy>KUeo}7=DiVtm-ria{pKHs>?I$J>>QJy1MzD -zseG}`KK~B)QJ*;02aLd9xvcvqu5NB|;;>H7=kay(^Rx56Nqq57y1#nxez&Oa7!N#b -zxW&RZe1d7Q^!b!~fc(t!oPX@&562VNK4ouTgO8&BTiW(N@w^ZG>Hf03U)Mb3 -z7XJ(B=L_@kYUFQqex8TvUwxG;YTDt);e+4S`F$TAVScHfyz<=d_DhAHBA58$j{Cnj>J3n*5$3lqulTHx_%1b4VVv6&wqB{<4F(I -zzT7;J``c6J$1Zr`Y(0On5kJd(;TgMp4jM#x|JtAKPssfC0p9vCUv|ExzkdoJ)l#Ql^Wj|IaNS+l`$7~@xUe&_I$ -z6ZG}mHFi -z@%*Tweg3QQj~wf7e#I|3o_F>bPkQ~U>&J8WvH|*eNSUYc`*ePO0U!FH9&dbyx2624 -z@qM3X++zNIU7t+CPdes9#j|d4yoY|i^$h-Ap`OoQj~`g$OMjn-OuroyxSzClDnFgV -zb05pi_UAiJWW2%nO5M-L@FV;EVk_4#)4Sm$$}9I@m7fjxvcL6st2ulh}wkGhkK_Rpu_&i3H?Ddd00`WX|STT+jI>qfaB -zj`SLW|I7S!7yJAye2-ht*HwL<^l+SC5B%{5bb9Q-PdVEE3R6k1fAg}>tFC*2>)Dnk -z`r7eN!>@JRpF+IJE}b9$!QZETEotxn_B7_l%K5VM1K;4GaeDu5loO -zhOmW4*|*81*gB3p(2Iox$sV -zqn}sgzTy^tJNgfu@mfiJek1Xv$;|gV$n*IG@BKf&xSRN7dGyV9iy!Oj`Nz%pdd6R} -zyvqHjy-Imq?-y`8pY2%SD};!C>u((kX!_$+*7DZSpQ -z{%dYx&U|Ej+8wXb(U)!?n@Ck-akK_3HR{HtbHA_ez+M620FWZ}e_@S?T+4krRzVB0C -zcD?9rZ_pkvpO>wl@SVqXefTl%qkPEwFVFWl?k4@!`T}Dq?H~PBmA@wAQ+Mm}^HIFf -zf4=Pctub%9#SL%k_P*UR`cs>Ac^!_As+A}1w)1z1<{m>%pdKu -z&u -zHR=6`p5NV%59_b<^SCv%7kn3K+4TNp#R_~n`B9E{WPVt&mj1+LonK14rO!v^=f?PY -z$9kbI_h_|VKuhspv -zC-D7_^=Y@iLw-G(n_Um~0^V-4F0X}nHQHNs|E_!2EiTYMRqgRz_>zzH^RX59z^3~A -z593AFi>zmUuySs?{*dQ49&h}Uj{jRc@^yZ;zdG-K?7uWGTb|p!$M}%-Qa=0oM&nuFtXl{uR6} -z^N*^1J%_(adaL=OHXF$Q2Xz0Y#D|PGs1H?r-UMN8h7Q2E)!o$IH{eZu+7(&No(cmch2)qXy`sc8P3 -zhr3z-rt+hAGwEsOX8SjF@Q&mUb-Yn{^7~vd#y+1-_@@u*=MA+B-Qv!*dcF1^xU+wA -zaSQG3qq=`ybsNw7*6I2FKKM$n?oVvMhco}Fj(@|al;4uMV!nO+J$QHK57hbpi9bVq -zqUL`Ze8&71^MfiqCgO=PI=wgJ(|hD)=V#ZN)X&T(QOkE~yoeuz(S -ztdBU04|nuOT7SuWL!MrL{}tYi`b?FFYP%^vj89el(HcKHMb}63@S*SN{?&2(0R7{w -z_VGXeiuvcVI(^)G2v7fBrGGQL*E*fQ%6wh4KAnO)*IS&%+h4Ey--GwM#l1Ckf2aR9 -zwC`PYd;1dp+ge>8_1Z`MJv%SE{&WL=lKNJa=jPwK#Vnpjsr&yMKDI`Fwm&o>NqO<> -z{$`8sXzv{T-?sb7A5-=EwXt{;)(3>_`*GxZo`;pz>w~V~ue8(S_dy59uQPT2KZ|8Vdh;XrktE+Q!}-Yea?OuL^WSm2 -zPE|dBdE!vf{??SkZqbJRpgP_Gd_kT*-qlCwPwv+DzY0F@Pu;)Tjt{;yKRbRddzAKQ -zsjd&Ac;a2%o^Hl_j@Rq=Iv=AvQC>f`@8`>STb_U1VSA0^JYV5?sG851kMAzw&(4>1 -zIKg=7Io*Ct#On~B%HNCesYb3iZpYW^C;FE=GT)CY@7GAY6XQ#De~;kxcIo*}BgOTT -ze{Q$KAHbJ2(e>NJpWWh`H}kXeu}ARIpXmCy{zkI0fbBiwD -z=;xU|@qvsF)cUDPzcU`%sPEScxO2UWah~+NQD6UO_&&$`2=D$;biTaS1@0g9gF62Y -z@N!;`NiZNgM`wZm$TZ&hilSfX;)bF_#=~Y5Me;$c<&)3i2 -zoB!n&9@<+qUf70rbgZwxgsYECueKLikMp@tylcn50AELcM%7o}<8jtstM;+n->kP_ -z{g0Y2kKsPn$4#`u@4`pCq@PcYxWxSTNqv7m!}l22Y~C+O!R_q#pf%3z-;u@l1-~>*x5wWV^N0}rdsSc7EzY;plfJ6H8H+EiSQxf7aV? -z^m@dFL;Cqf58PRQ&BaSj*XcjHgr~@S?lSy~M|FEV{3=h8`K!ZtZ~A}geUh42d&E0^ -z^m@fbxO08a-6cI@HL2MceXz>@;&^PsqTMo#tV60WQm=AxBER} -z|1cfjMEt52I=+SY+;X~pJ&nJ-*_VC(Hl&P4w50s0^I3(vSudoXuiR9Y{J2S{_lx)q -zj`r?fya)5m>iRpE<9GXe~V$t|V;K3^T{C~nn(0{LL$A5h#ezn3; -zf4_z|?V6u`o|M8<`}KU&_1AjD$GpF$u4fazkp77(Uw2*S5!*}a{_R1$G|z9;{cTjm -zBlbAf2d%)Z?)v)v#D}sTLOlJ_=+_=qWY`4 -z|F{FMaYB#hEWE74uTB3z0)hF+^lyVdG+58?UKQ|&DC;xS{hW?hnV{SI!?^n7@yFk| -zbN+qFjnub1Z&v63Cq9nxzDlpLwWz;%A5_(kb8zSTN?Y+759;UJ_t*A_S{L>F*mk^YBj -zKc1}X5d%;0I}3LBxwvz^eBGNp!vBbV{hyfDzDGppKdSIY@yqltRDZB`1L{-9_X!NeThbn={a?n1zOVCN@rJZF9v$Ckyvpyi -zk90HS{aK4U*UR45$Rj>-l*g}d=lYzh89K)F;Js|L-rn -zUuxJE9GQK@Prsk^11=8v#k2PH_bg!l -z5_*1QGVWZz*|-h)*Rg(JA?|#?*WH$1`QiDuT7UT@-uG)g{#t?;jMMeQZhSN8tNNE` -zZZDc2=e6_j{-mzI|H7}-(D`A~9n^n(UxG@H-|+eL$NJd!|F4iojG;g9w(Y+5^pC#K -z@9S5`Yi-r(*8nfg^K{kzJ%U$inx7p{pT{?{KDwkG-;@p>acYuIuOINaef50Q_Ku`C -z>zmd2%)5)@zpBe;`A+mFPU!wvJG`6Y{hQ7BImWwce&#YBWRemhi*(1ty(EZb4xO4nI8SlNpFM4x*vOJu`o$CRI-Qy9*%IM>*!ha&a -zd|}^@+%B~DZT0-h9DKyG+-!OM18;sqe)jptw0k{b0sW)lcKDsR??s*7uXUxq<^3_$ -z-`k8k->;c=AN3v2KYq8vuf{jM=F6^^c6X!wbmZ4TctLYL9;#xpD+l2f$_NN -z@84{A#0JOn+VOak_xS!K`~JL!JHM~v_6KOsm`_||pHF^wj>q$rs_Fg9ioWf8s%pSaVu$--$mnUcb+GV-Jt03qthEMxb_YeNW_aD*oKh`6ZU&r+}>`8mW`$DR{{ubZK`u2hL`C7QM{aDnC@k~Gc -z{WuMKdy0HN$7Osf^Z6>iYJEK7>{Yrv?Zv~4PgVb+d|&dyLWGgLmluc7uV`|G3(J9PWEs -zw^tPgc|?Ww`g(`r$LKGr`e_e7@sfU?apPd>FUNY>vAFYn^Q#}@{G9XKxO4vgRs6(U -zJ^yXuC#UQ2Tc5`nFK*NQvEBINj`Z>m@rWm>zZ%*3V;vrTQTM0H4W+*2`yJHtu1E2` -z@96ozCAjl_z>E0qYP!CuK8*a$cwF`8e!!pMd9-Q|?;Y+DgXs^d^>4&J&bq1P*S7+rLHIu#FY(e+pBh)4X*dRDcbV>PZmGXA}|^Z9z^C%K=bj~Xv7!p&cN -zVgdWg{J(Jw?e!VGezMhAnI8K6`vv%$++S569mmf*?sv{O`j?~i^WdlPY1CiY^u?Fn -zqsMC(@qg&wtNAehQy$Tl=hv#dZ^Rq3os1?uzdc6uzwo$p(8nnZt__Z@Grw?B_pW&Msy -zzxB`2|8dL@c_-t(%>DI~zE$vFZ}w&1H(83i9qYMI;Li0p#uUbDj{fx5cwu?n{yZ8b -zKT#gl^(OE_$9l$3o+mx2fBV|!TWl)%xv_pf=wW;a$5;8|7koeU>+SabLtfy12Xy({ -zgsYEC-(u6Kujs$jvirlk@#(p`y*Q4~rvI+auiA^uKQZ1^`S&@zQB2o2EvGYIv{1h< -zbp(%H(e*{!8SMX&zW;CIW@Y{UwlS0ZQeNke8Mu%3M5Wgk_|Q`R?E9P(X3;*B)bW>` -z?Gev0K2zt{5#P=HY*+h!EX8a5slTrzi7(mbPxqH(|Lf{Gl&|J`z3M#t>_nYEPUFt? -z$K~c0tv`q0KVPTkQ!Bqj{^Nd*w2$8azv@Z-eRAFK*GWIsAAe{b;|0g_uDf5RKg|4v -zy8iii+0nXweKW@S->UmBm+_AKanB -zuAsj%O_#UjxbyqT?paBF&hsi&U(Lr?_txX%)~h_i`F)aK;w2ol^9%W(_`*{=#1Se9qz(sL$2?YqOUAyrVsR4v#I;_2bC5C_k*%SM|Xz>3wwjQ)eCH -z4f-dlJ^BPcajU-G>)-Z>IO|i?_Exy_`(H-l154`lPci%w>lsygyp3PJIxkyae~#~c -zQrAbN-|=u|nUAcW4cz%WGL9FS55fQ8`$^ifuk3%k`!4BC{#NzhP3t)yNBZaekNSPO -zZvR{0k(=~Qc>^UBtd>`tKaAC -zgqL-^Up)yQ$oq_K?eqT;cRsJJ`+(_g=$#{)0n&h>F?@q#CGd26xJBU-G{ -z{pI4Hklugk^lyjP`bPKnU&C9n9-)DK{Z%&6K2o15UxG)OUz6VuE7SK!T$Iw~_o~ev -zaSijAs{IHQdWx){IEp{a`Vdtp+@|@%SL_9iI&rkn^ -zcl<@K*Q&pr_QUc0D^qdj`mm>V(B82AL*37{cpmE$)OfM-PV&E_Klku1o<}X#*IWJz -zkEl(5RfX@3ujKxy=lAX}IiFYc{alEvPj&v-jQ7mb9tI+r@0^R#r(Lszl-rN -zO6&D-6~FR`L6ol%#3l3B7X18gdD-=}NxbQFJ%3(r596Wt^z)wXc+V-i{hNneVv8KEM7y(4VKjb(`%I@nXewdgmUb|Ld5a8;O6qUB7R$8NYCY&QHM~ -zJz`P|oj)JNo%6X*;b&;S)&2YuztlnR-~ABRyIa36w^O?Pk=I}2F!$T>eH5?bdtS@S -z&M&PzLVLk@OO0<2d1Vj#{Qkz9bkgZ}`ziLXsmFr@@%_x-7TEiLi*Iu2 -z^`6GB%&#z>Q}yjy+npgpt4w-2AAeQB=mM*??#KgN^4d&EKdfB%Q8vkZ^w -zXdCbVYYB1OgS(}H;skds4yD1hxYOb3q@^xYT2be+Ina{X@jwEC9DoDe>jnZ?Ol6uju#r -z6OQ&5c~I*e`C{ymly-l%fu|Yqk$Lb~^oNf3RDO^DJ67atE7**mCiuX3G4%IvIG~-_ -zPX#{`kD&kb^Ynlt>d5omhjTE#wLez!6XS*YSN;7-@CU|&j&Hd?CsI>hNdD{=Jk_w@ -zl7GS8`6tM`e(5Ic#9!0-ouZr^a3Pb#ljgw}$?xcTu8avBs>u&B-WtN@`rK)-S|`m8puX{~id3r!d|JeolRf?%&PuZKMA1BfJaN`mALl2WRJrz8v6i`0O8- -z!0AwX{wMW1?cr4=LR3Y2{HJy~RN53`FIR`xpdI!7OS>H^R}y)?A@Bx=*qbxpn2EtE -zr#)U$c^vBFTZzASf@7&~)z|Cn=TOn)Kear10Gst(3H==^3;QLEwXfID;$*U3Ics8v -zk31O&H$uN?`LY?-f0n%c8*X?c#JitDw -z^*3{15Bs@j{dy37YS?opf*dN+CFd=?hvymNFHf*Tjb9++y8>MOm8@_28P-bau3tf3AyV5{i=0dU}H@&6*i9LjMjP|fCAmj0^;$F39qWHOv8zu3?D -zlkk4*e^Ax_{v7yZHHjZ)OzQAiKeY`$_*&{2p1|h*8;g=TROU(|&s1`U%8vb~`+p9c -ze4l*&4?OXm*q^_oaQN(}{uFLYeo*&M-;@s3lKQba_VezC&HZh%rgHeipD)4TM`XXO -zqp2NgbQ{SJFHhs}+26#G)}bD={!Gh3m!rKNI%a*>vPr`CB6c{bQ^*?gE?j{yX9K#Mkxxp1{wS1bg>mYafn0Kp*Sz -zd>Fn{M&^ejBjc6)oPM9YaNPO-&cn6*rHD)p6-Inn+e?e#?ZkU)+s|Jrv%|-~4$k6G -zV~JPj=cxz}Q!*Z}zzGhByeyQ};j{nGIrzm2sqb8n&7mHUkJZnA8~%y-h4$y8vO84H -z8RAd>1NXfq@zvQm9IECovj1<2oDTI8|3b@$-tao&JDPXEYEPI-WXA{h=5nax+a*4f -zJhwxY&l2KYf8P$ii9ezJ=Tq?9tddV}p9gts>u>*l3)~0&tNSBar0;x+feR2%vg{G7{bCAnJ!3uLdibXz -z!Cw0_pfLJ-j`(L?;m%Fu`L4p1@n7}*3w`VGS--UuHuvL6QpBN-az2LEwAhfi@g;dQ03 -zUtn466J!74a_~IAuM<;yu#*6)J8p1*79 -z$7%5GJ0d?_<eY1rE`|NRmw4j7YP?U3*oO_O^Zv&E?N{O3ePw(_)>fp -zdSNo(Q`AJ?lmFD?Wf8myd8X%Q?OML$p*L*izv5uC{^&Zq4*yx(>pf~aRG#wU{~m-V -z(4X4=$XSQ+V8kmI!j+>$J{7LZ{f3MDoC{Yr^5coVbEw(%LcRI!AK{Al*JbSX`~a)N -z|D9K7>DMOp_}tLnv*6oZWc^~f`q-bGm!R9@671+9~G@nJ?!iEZis$CK3eZ% -z&4;^i>Uh~NYjq>!kzsG%f=}#`c-9Y%vG+oyzed6_#`w(9gy*Hc@1=de6Y%)<(mySl -zI(*gxHf@GIZPXX{g#V#FLCdSX@KK|^OMcJz!Jo=yU%v%x&c}^#QtTz&9%0RS|1Kh5 -z;^AyY{@^vdC#Tf^{rZDL)n)z3a{KzlqaAAGAX$&y0d8_v@~6F9@O>ly;cDqnQ!mT? -zhr_e*2ep5G4L0}R{Z;t348|qqkrG1i?pAmFXq6Vr^x=*`(g9Er=YIPhf1>F -z#8$Yvv0vU3xT4|zH|XY2pRn(BKBZZAhZ@3q&PLqJn$O$d0;eSYa2!tW6921C55_0{ -zowgsA!S9O(shaltWbTRoX4K~|g_9ccykReg&;I0fdShR+KZSn(iSYOXvY*Tu`0wQs -zk1EuM{)(3MMXOvpC-F5!Rn -zaUZxg?W5cOI2>)r-&{kmPq63p_!tTI%M|L(2i$}py^-5Zwryh$wzb)reb%zf!e)V`d1Q(|L^!^0( -z#^L{-lKPKRF%ESD`#@iR=YkhYCn4<9#Z;>yr4NIVRu_8T*$M -zfIAxUuLAtCve+Zb;2!S-)pk2RrzZN^Gm~NSd^-0e>|^AomM_iVs$n7C^EJ{kst%te=CukVek)_yj-hEbZHIF7_<;t8VXr-xy!mcbW&lHOq*<^9Y`6*w4SrL!Oig -z_1fe2;3DXMU2j`_zC(3q{e+H(bb!tMYTv+T#)y5Bb%C$HSs%WD{?_tsJ-o_@*LW5p -zpKb+v}d`H*ypL!Eyq_0gSRvtH~LZ0=8; -ze<}0dh<7f6&3y3TWyFWD&#T(~Q)D^vko_U%*}MZrfU9WO($C>5kS~Tku@N3l{Z0$} -z``K1ve`XF*H*6jR$F3z>V~?-Bu>P~`i%YOsulfWw;}A4*<+iV1aW(Ig -zfb)@UPO%346er`gG<+NRpzX1SaLR~4wSwhTr> -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 -zY{&*`lZgWdEVx7xDWP)wnx@~=T!4* -zhp3VE_5ABO)taCn@AV_$BE)mF{um37ZzS=-Pq2C3dHedl<7)=|lJi5fJV@KXsj|lf -zs%G~6=EJqwk4W1?@vxaM+SL$w&i-I}zVvJ)C-!`~rcTwgz1Uax;5cLaTxo`V -zYSjM>{+{vsO4jT7HOIb=mETW?^Hmf7J=YJ+fAXjL{y)QOvx_}mI2!x1vBV1&!gu<~ -zc+A;o&ncv|pX%Fh(bp2#UxEuQJqW%5VaIeT9l_}AG_Qf%{^E0VG -zd;woZ{%U=hy%qkGQ|yWD@XavU&$e)Dr_cJ2t#J8~;-BPbga1)W?6C&$X!Mirug!2; -z+F$c0*gUT_dt2TQe^`&t&Tuj6ef9fahBJ+o^@Of=eEw4WrxtM7EQ$X#Z;yV!ztrPr -zBODMR`XX}&r_Xw;HE{b@l8-Fa5&Mz&n>9+U`FjX%zfjKao!bffD3!>URGpnZ^<5p{ -ze8`u{_V0)M$d!yG`;{smfomVjfBXS#j+!urpej}zdMx5XaH-2?wH -zsl+R*!QHM(zAj-;<_qg%toO6p>sz=%E6Ly0hcE7s{VeXmKe2vNx38-g@`ZSl=B#j9 -z@+}ee^}53A0>ocT&>R1i{JMVrAK`wRLcIGi?1CSk2vk4XzrO^V=NDz^)9v3Ta0-76L=!}q=o(aHv^q&Zbo_D -z%0FRmrIzv59-c@3OSk7Pc!M#2lKkvc1FFjN&Voz{|s{pJ=AVtkhsdu$h+ -z!`P3!`e6JA@{6_X-}i(|WfFPx7;ew{sJiy&6^CFCkss6R?JmQ+^U3@uJe2s8N8&Se -z;H1QFbo<9EN{r#G^XHqYeLcJZ#pR9fSLB^|@A*-s$6=phziW9h5;o(vf5X{WPtwlr|NJr7KgNE_ac~#% -z4LR-h_!m~3$7K1BmOu5wFSOqWd7s_zBi^T^eZ2zX@s|b!d*dy!@c8&(HQN6C8XSv! -z)$y3x6NraRmiW-0u({ty`iaQrWO6=Hf7m=vcrP6FyPW@9WD@#}dNh4L`!BG0zI;6F -zCf}&rKf`3^KlxPcKi7fH>(7D}`B-hAI;S8nn+1KXzq90VPT1TpVgURed!nNKzLTdS -zzlm3d!&W@*A$+cp=<{N~B9GZmFqi%P!SE*X$75~&2VQ36$AhL}e|{t1{|yfLL*)B8 -zcY@8~&<2iC`E -z`I&RBul?KvHurbP_Z#w=c(m@{8Sq%n*R$fG*7a_|HK&SxZ!{18VqvIv{H}-1c=A>F -za7U@{+&Uk9L;hP|KY9W7;ChiCOW@h -zcm(!~wvS%I=6UD=%bn~=C-KzQ@FMC(bbqgaZ=(OSeVB3uU4pJB5esqQMi-$?ZFba)Z{YUyyRx@^d3RzJ~a# -zmtaR<8J}g=aXsuWOaEH(VJ5uOs0aLRJ@+^2)BC}njq^Z`!ixA|u>Jh?HZY!YNPKb& -z>_ETk`BY{j{_$ejpI{4oGl87%(ry#-Y@g)ot8XTrZq$1u+k!lP7f24_zxmV$HqTr9 -z0H?n#_GkE3-+1gwxcc27Z@x9vHlC-L=#zo4{me$DhEtiO(js-)G=n-}q+wc;u6zPoBX|!$lr-+Q)oh -zyy^Gb4*!@%@|AJ>iH~KL_+Rz|*dqmH|CBcHz5Y@!ItA`x%%{ijgEJzJD;>nYV7<7m -z7hVUO>reL|qP=&8sHFDz+kF`OEJu(UV836ABeY~xjyG?F?<2po{SxyR?Th}={%Mah$d{dAU+n?Qeye#F -z{eVB1-+td^u$hl9e9oy>dqjT3!}0&hdfex5q_N*+-SbX0n0UU{N4MazL*)HxTyUzo -zSwqy*g#XEl_po{X^@xj3pYu|jmwf%Ftnkm|({#RdKip@x+%M{H^hF!-$I@M9K6I1# -z{Q%fSK27)k0gHEvy_Dz*{m*{=x<87;=Kil+;5h6vJ^r7<7jlby^IS#Vvp=eSzTL3G -zzbIn2?{&D@GZ`;`UZcMUh<;0Z-Pc|ld&8;fvHxQvzqjgf=fFd-=TqC)yJLNB#M4^e -zB;Jqz5oLe=C!8{|>~Ed>7V*x?(w~#yoW^{84eLKk-bUQUUcM&daX%b4S>|`Pf0)mA -zq<*p*Y@XNby2E@!-s7ZL*G2mG1-xdD==%(h -z@ZX}v-e?YwJt_9^960f6(LWvkMZOsIA3r~Ks?EqVJwDPuAs#_}m(|vmJvs#5S5E33 -zM?S?qHthe0@Scjn-uTkD&tS%rKHql;T7rbuvg!F|B~x>5PdNceuTa)U_WolS59?_c;ri)|Ac$A4fz_Mw%#Z4Yv1@` -zTUe1#wDxbY`hN;+p2rvQhWT1k;-j13>i7?OJY;)|{KFp6ycQ0hC;6-I-{G${mG$k( -z-(&w9=l=|VAF=*ZzwfVb`Z8jFyFV~KsmHP8rS*J8;r&x&eolqW`k@RTiJz>L{(cTm -zUY+F&?Qhgqmxs;uy{F;kH)TA&g`0Rn -z)D`=B5z6J0A2|e@`*(bRmra%WfC>p*DsHRn2k|q!>%7c|TnSyu(_Hk&B-mWfb_s66 -z`r$M7{revot^2Djyf&-Ydne$VPh|Z1IbEtO_N$)Xtz0fO^Qy?p -z$MA6@|6Jeg@)@rlk4p{Vep)^^gqs=l7|UVvJj7FQ-4`PNGyA!G>T$}#m;RRc%t&}h -zt`POce&6G8dg>SaZEoT3Qkiavyx9bALjLLXz>N~S)NcH3{e08mA;x~K+bzy0{#@w* -zm(O|RP2o5rzHt&xTvy_mnFC#F!CN^GxDssUZ=>NfH6?x)562kwHFx3hpJYA^405Sl -zuSMUlfv=a7{Q(Zcd$8Z5?Dx+a>{91`4f5unUcy(7%X)UR!A<^>{MG?D -zhV@IjJ(GpHR4nJ84o=6;G#VY43M?=Y9z{)_kv-z9OW9n`y7 -z`qh$Gi{WvGJ#!b>8^6?`*T&)g^l!ctE_H_d%WhkqBuVK~)v0IH?bQ^{pH%eA -zR@mI{y+$g=OA}ciyA4hlDDjKzsa-znMccv&jrH!+;ExIAyn)BC{rx%}azFd|d%~~Z%KY00`|pwbOF%l8D$f4vy8d(nY})sp^e)ww -z`Yj#5{|$~$BkScJ!KH}D==Ld{!R50b&qz2M^*q{tdy40^(#XkBCevCb-^}!*y0QRSjKV;5?d`%`TUG0?Ek8E`)+_we-!=u25z)cuGgV} -zZ~IJygG)+1vwuPKcVW?|1!2?v{2AUoRO%z6Bba|@<@?9r-uuP>N&k&Y{j^^E`-bpA -z;>$^SUMt=;05;=&f5BZx$oVA&BGLaD<@uYyM~Uxfd-?+$a3IvXzP(f-m%5r$?%xc4 -zkU;9+Y87^=4)|wUKD32z5108k81Bh>aDDym-}1ahzUD2w?k~v)}0k6EB3@{IjI^>`Z(FX=7%`VDNZH)>vr_ciJXcfjU;!2iJAu||f7iB!3g!P}*zxUvT8Du?N -zmP#%adO-FA+6wDGOP`#FpHr`(pYIhM%lCEvtf`FsX!v_cs<_m{QL_HMH=Mbqtmpg! -zM;wuQ#Uxd+cUH-MAa~#$)HCS#PUC7WRoRF)eS$w$7JsWjb@T)EDmuP>172gu$4oV_ -zxA#bYZG$p@{Qu#aOXr>W=isSgweoIP#JBTcaD& -zpX|@5<AK`b4X+6C-DW{9s}X7tVhuC -z!jesp57>hd_V6G`p#ZWU8+GY>RV_AD;~81zRr5Mk9^;{4x5Y4XppH_8tbu?Gu0TCfuNo^k0o1 -z7~dboewhfH^Q%fU&u7#tPlcoXC4aLDE|2`v^Ya$m+ -zc+FaQ|AcL6ANC{Y&i$*1RP#s9krr$@i)_Q>3x -z_kS(z(GtGH`jdk8`}KhrU@z$Q@bAF*Bfb!BKTkfmtp8lI|jL*`tf94$6%-2MA$KDwx -z`N$Y}HTIJ3k89TFtz~|0=z+h7eXi$k9Ngn~S&w`P{Q03*D83s -zk#G7J?&p;2`}IN|m6!7m;$idrKTmJk8~dz|-M-OqH=~|sFkHKp*#E`)U@z~N_(XGf -zF7@Dr?B8eVi~VcV2Nj1$5HHo^>l!@rA@-JS50&YMebPFJUb`# -zBb!F>JcfS~@IU06u|Bgrd>sE&|Gqc8JxJ#7N4T0155GE+`4}Si3mhfm)sp`W;aw9Y -zzSaSr)k@@5^3lkjr<@OHkB_HtlwX+lJd^*8Vg6*2@mzN-@djf*?&+|(Ug8eikotBl -zZ{x?w^H?(FDx7q-*o$3bXg?!=vwW#l<3F*U -zM9b3?@MP*ibbB_OK>Hf&nODOlh==I!--lDQ7kgpeMC_qh`F)N_yk9YqH%H(GCuM)P -z*Kqj%g1z=dyU8xKh4$3(%rsM&FT=(E84kw?foC^m};waj9<~3YYbh{cPUB|Afo$>&D{GRtiyvc^=E&>j<0s=`MrY -z?3DFCHD=I$%=ak!`_tiWYveqUqwtp^(jR$eGXLMod_D|&jOS@F3;pMmdbk~MiN$h# -z&urQ=iP#4tU~_%oaX2nk&PyCL2mKZ;_UCKZTpy5mF89N})axn6!<(AR{x>(^9)AX_ -zDfav2`OW21PgDUu$NK7Q_UALQ&hP#(q7iS0it! -zPuKo@DL8sVkowDRzoGD|9nyXq;3~)yov%-{hVewau!4R6aM;|xqY3;zk&NfH@CNFm -zwS10;P5qd5E$_20*jw+@0&Yit>*otthkbKO{O{RttPyXGgL{yV)b?___1Lr2!Mms**Vpd|o9Ce}hjVn3 -z`o?FQX|LDv{*hbgpXtJrVDtRJ}C -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 -z@)ug3Wp9i=AReH3DLj9b8Vr -z%GQkMGwM6H!Z~hA|8M)=tzK@E`4`#Tt=cCLdwewdDPX2kHC$1kYO>_BB6mUGFyB -z3w@yN!O^YUKKr-TYwcDKQU>ikL;tUae_tZ!PX%;j{u=qkk#M~z -zSwHb7oWs~}F`|=OeKhn%2l!I&Aa%^PPd37){5%g&CO)C9=RkIctS!Rjyjea6H3&+>2ogw1$vP#5GE`RwoQ?`MO}`8FCpLw>BT -z{rM%>tlzED)vfm2m;CcUxaDZ}Z?V^7ZH42g_YUXx*7*AyE{uJqpTAuM;BcdT-@}#Xi+xkI2l0u?V$W}aQ_hk4>q0%Tmx$Ns -zc;jj~*K(0>$$Qa$Mt-One7dvL=dOZt8S&qL;a+3pefsw1eVd1R>k00`cZ~etH+_&_ -znI%3x6^_g;^EYi@=3gm^-#&s1k>AzxH)TKK8^-=)k+A-=^jAZ;V^Pu1li^GKWIfGE -zc>8hbkHr1a7wk7t!S0XTuxX#qgomsN`x-B``tuxYo(CN|z&GCY1rEXf$z)%z%s~7r -z=ChW+Tj7(~Ki%xl1Ak&XHkS3G^WZJU`pVmI0rC<5v%jDIXSdIJrmNrqIYhtz3;&6} -z*YWQKgJ_=4& -znqWWQGI+aDKbC12_VE}QZwujN%#RfI^X!5a;4tF9x_w%WqW_Kd -zT?CJ2{OEZ2DY!%-$+wOijeT$UoA2QE#(wi%$MC-6C0_arZuv;+1>TOOe~f(i%yGzD -z)+bc5-?wrM`VD(0zsc*E8;KKu%B-WT!MVOj^{juZ?hgs -z$JZ-QqQ6-WsO`IL@Rg$y&rUX(_9TCW?1$4Gt~o>U3)kUasc+Z* -z$+YRj6Dr91CjVGzUrT?bg`?9*Ja!*!?uT$>2J-#7#JAtU0mM^uzNh_6gS~)0(Cs}5jyfgrz3XtaTk4l%=b|r- -z`p#qU-1@SA&nx&*jMS@@`OU3rf06n5BW%`d%zy`B&uaVY4BXc#`}@wGNBis%eUWND -z@w5TrKa7IS^&o5D+DWDUA;|*d*Y;rV`SGpcUF`3m^B<4kk-y6Nqn!(}$3jG2yn)Sp -zWx++*Z`42N{+{iW(Bj^3%}X*~m%;<7KTBhOz7q~XzeQdp<$jiZ+8rKGy@8IuorOy? -zzV!H*wjBL!;Wk*v!v|t;Rn2J6PSa+p9MGocx}ahfClu$Wtv}lC6>Vx9o?i@Bm}~ -zv!7tsO*zkDJv`4T{#lB(*c<(%J)Xk)&zip(*I~a^6Mfcby>I^F7;M&4rrdzMV>}P# -zx7K(l3s-+9`uq)i)fjILHX^U7&(ibZ1)MUAjECl%kbjkAeC~u_Cl+}cwwdu%R_0S~ -zxJ-VLPZ!`G_=8$MC)z?h1N%9>{d}om{b#*zUD%92kAj2nM;qGTpAVOxCHa90ThTw% -z$LRjO0M}!@>3C7GZNw9KKWz_0{m%UGm+yPFqi<`AKmI*z?w@u94q-p6iT3@|{Xu^k -z^)@5nOHOIu)H~3Zj5jUc=EH~Z=k)!z?eu-$&|SovX+J%`bHXFoZ`9wu-vD?}V(}NB -z!sdD3W#Zf_JN;eT{(j=!#9I%Dy*?LiPJOtR=jr#*e{W=dRD}mT;{bS(v)Gs`;x#2$gpZuC`k85zQ4>Dc~??-;!68X6f -zu4vQ;+=1Uuk>7uT_Zae``vL5i0b*~=gG=E5>-$}YJ5o=i*XL(A=vIp&<$Q(xaF%1T -z-_m=y?T>r?f7xCoo;1Nxjm-?AQE -z&-WB3(a-P1f35-RKWjdAfO8o6h2?N(!#@4?6!Rgs$glqJF#Inq@4r1w`~`bi&&Lb! -zXySFceRBQ9{4(+_F|fH`Zn`tPANHJ%*N=fK-jLtFhUYyEy67MQ-4tcpZ&@12j!e+d*-g)N#ZjsMJ;hDzxmF~%FB9Ghr?N$ws$olcq@XHf&{j8UzzrN}p -zc;3>muj@fAf6aLXdzkvH@pk)MgGZeVK{Ncoa%ovb-0B;cwX$C*>Jzcl0WKw+wHUe$|m^rNwLQh{e!<&BSa0f@1FtgctP~r -z1bCId$g4~6LGl5*|MT2oeElr;(gJu7?a{@)-YNL4vH#R7IM;T`-&DKnR`n~2eS9AN -zO#VQ}V+-8leW)MT_v;G(!Fd#I?d#{gPdtwNs{VW?yxrJeelL9T3+E@>@ulzwZq*ol -zuI0lxI9Hgw-#OUaUm)fo{zW&bk1Y4dtu~`?wLWX{FZM9;wUzesB!A5Bjs4z_z-E2x -zoG0}EUWwOUed<odPaX3^$N+KGym8xM8EGb*sPy_3D*t{^48y{eZhRVCi`iR -zhjaWT_S+peiu|YLFIw{>#Y^%hyq|8rsj%WaYF+X4va5b3^o!(HdlT!BYTMV1$!TtkxTOQ(F?-2Rct(wM4 -zJ?c$38TwS)r~Ti#)&6*?H`)iA=S9?ikA5yM>rZ}yZyNGA_yh7MK%QPk2?3w6EVM;s?fjiiFR%ka$~DIK4;W1!+HHZxAoi_RDNI -z(^YBD6kqU%9!Pt4hV`GNzb3&0Qb<1NFIvW2AAUT6N8L>=@~nA6kDAy-_N)B_oBM^g -zO5{4vY|e_rT#%OR!h9|2N+0@mU{`#pO|*D~bNU4tFEpr0v~Q -zZjaA-K2u=NUb(-Yhv&&4_CkI?kNVNb9}kAJEfxK~7v7aX>eI^mdsHbypG|=S+sk~c -zlGvk4_{n+0kKx(mpLF~vU4Tc8z9IR`3hQO-IFABjGjrr0C -z_WU68bq4$Z{jKLu(jbqIeR&Nw<mJYk#O`r*?%EnQjfaqFXJ&MZ2E7} -z$vi&ifu4iwp)d9Ns2s^XYV{`ZC!WD4D~h}+oWi3nRFV64gGZp>wSP4vCH+BsQ`;L4 -zVRJv>XQ@0s^%g;?8DC*y&$fpB@E^4Nh_e`bOY5VOX*?>&TZz{nfP;x|YWr?^T940q -z>NDv)>MiqG$CF2<_xPM=cN8AU?{)sPWd_FUdD)+49sH=LtY3A8d(;5pu{wTR2~Ivj -z-oIf+k1FtXXemt(NGUZ!DIcgk!YwTSvwJ^q`+ -zTe1YHj`nz*3}5am{dFI%ZR8JIW%sD+`GVDI`}<#D*9%!c+&70uUBcef*Z%~Y`HXZq -z=}+nhTG+pT3Y+ -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 -zus5{_IX`n4|{i+`!@-`|gu{~+F@?aLx3h}V*j -z)c5NO-(>x`j&IICNqnfd^mn>b=zBx{$HMy0(ueEdr1hm=`26<`Zi?+ehtT+BI-yO)>W7?nfdpci}<1Fvzk@({8@Q}n3 -zf4d2r`Q5qau!pJl*Yfrh9J@v2ZT0i`bJ+X(^MB#kb)uiLUGS*+Rpk47;SFV_{nB1U -zK2Xo4{h^ugCi0a@?D?PJ68%R$Mqj@)5PfnE4&NH$t@p`!h4xzzrux%gmOZru?sY@* -z+efdW4}K5w`t#|p5kH}xRolm1VKcvV7gpE9zV5$iU9a4A;&a`l-e%ej@>e|1bbEZ< -zg=3BN7AbFXzn6jD^U35qt8*sqCXe8=3z-YO&Uy!mjEwi17;_7C=G -zb!m@Yu>P}buvymU$S3`NsqZk~S-;rJe%^d=0pxK%o1Jdgb%qU`5C41YA{=QY?|Z{Fe&*N>I@kzD_J)WfE7 -zKG#@S|5@^6KYYP>{_>Bpx3`NuvcQS>L!8KKd}o -zyB_fZ9CR7^V$b(tFKHj%U&os#!h@y}Z?```@e292EKEJ)`quo2f6euYKWKlr-y7^z -z@_Q5P`yYbWB^UXg;Vt;E*MIi42gksfkf-|o@v#20#?N(wt@)bpi*G!x9-Q@~#KZlRpDGX$tPiM01j*gRh)9_}zr{OL#N2k3g6BrZSInRtTMFJoYH{rD~T -z(Ii>Vl+Ep@Ml6u$nGC02F6*n$IHL*^HXh&c*AP= -zD(f+<@np5{Iruv32d(-TYrH>!&HeNH`1|?TTj>(}sg8y}v>P_-f71u}si?A&AGr_5 -zP`{MQzMo$p?{iz?H~C=me9R$mSz|nJfzM#?ma>0eH^|TDJoUg}KUJIkxvjBgy-yMN -zf7RqXj0N!XI61GTSP0_{e_zk9NpRZ$Y41I7yiqSZE0o`N6#2X`jQ6`C^)F#b{8YdN -z(Qnm~`l;mjb6WoY3U@>PzqFsPL^3~hg8cz?{Phobdsq2>#pHe}c9Y1bt#Bju&uV7> -z{v{k@oIjB!1<%_^?2(>uBd6H^zr#;2%Jr+I^ixL-eVr(kpK6&;)?@q*rzBplpTA0K -zKc&`7z4>N%G~+SYex86de(DwSTF=+ca6IE#|Nb|4$P783V_8~1)sy+D{o^0f`KdGq -z#UD8(+Zva))^9drD;VQ~U4Bd6Z2vG2W>k)%Cp@GyD0}-#voO^Va5PK^~9~)X#Sk -zKIf78*@y5$>UWmg?Kvka^TntiN|KH7!1~J;_UCD``}v$ldmL72z&X{)#J)pSs&cdQrgdoCp3bC$X`a-?YRmz>lYJ$!~7s0q3w;I;iB!t-pLe6{~|xM -zJZ}Owcr5D)Di!imtC4S6?dvasUlX5Q03 -z>jl_>wA1%5{;i*i2$K2T8E&aURR{Zisf#ea>&g6>44eAw20Y?ZsMnrNTon0&y{Yrj -z<>8Y?zM@Jou1A0Be8Eom&Th%Ko`uc)+SuasC;CYD=fCi}mC~N`O8CCtWw>5hv7eii -z^iz2QMV`mQ+t17XeD_NE{@zgaDMGt|4Ekh`p(YDoT3zh7I})PDub`KjoBQm--rzJE*Xf$OmT -zv-;On-cQXVKK7&iyxCxLKg(sXxqc*~f}fB7djfuoe^cB3{Tp~G_C%D;^C~i4@h|oJ -zKZh42lJU{968&S?i+{qY$uGv*zpqdk{cP^X1phus`ZpdPok{XV_uGw~txgTevYV=njnGZ>-`>8P27wLL{@$fzB -zOZ0qs3{T7zq~_S~Q@w_tDsn~iLw~pd^GU~RuE8mTCI9&nHuoEuRnt$c!Jp9f-YfVm -z`+xPZuRpdH?fX{jvo-K4`aXOTeXoCCwF&)oN$SIo!|~%p{+Diw -zeMo#rkKeiQBJxSvfBYA&oI&D!j_;8t)W@B%pMN@haI(yg^KeIpjPFNq<$bcgD`#^* -zpZG{A`2X1Z5;!@kI{y|G%_!lJMa5NF#A8`EPWRlNB$H0)WHK3NCV;F`^iea@lb-IO -zyJwQY3l$YvPrQ#sR6GzwQB-7=6;uRu6GEI9l!f5j>&lLP4xSs>~C?a1^)IU$uB3)T$kE1BJbOl^%A#d(~MC!H9@4p9F&0j3d;Q7cW6Y;cH0ao*$KMD9mg&*Am_`H)OKYq+C -z=<^DBJ}(6P+Be94%~t?E0r{-Lz8IQYm-@G+jJN+0@V&2)^8Fv?!OxKYCh{FV2KX4n -zgM|Kc17Nkj=|Q`p?`)U&_71>z!v4L)*>AqGE;V?T?6>|$z)wOxiQs=nE(IAQk0|zcNCWr?dKLQ_1^gZ0zj)ru0ITx$ -z#3uAp_#cJ8>wLiT&ye=~qnFmDUNkQ6=RwQsQit?Q{(lAF-y;7{@SBM}>r(e1Uq$fS -zPXRvn7qT9FXz#kz9}bc9`8>d?{(jU7^y&9Y`{hw*179ze^7KZ)(-+D7=i{HhF7>i6 -zNd9~t;L~bS|GO6Oub?lBc;DZ>0QB^2iJ$KWd@Sx)@TYqKtNkF3d?D<0#Xjf-EdCIG -z&jCL7Lvmj0b6x~|M?TNv9eg_n@FMCF#eF>T#W>Fw$oT3q;H!`?AU=OB;62}$_y3G@ -zK;MdfU<1Bnm&BLnzhqtNOVB5Te*Mswu1mdAnQ!Kee0 -z*&v@c_*&o}>~TS_{|ESL#22d0dQ-2*`=H+nd`SZ?Abu$Hop%9N`|Dp0_*)y~`47GU -z`U31vqGz(dehv6GrQd4t0?@m%|BC^OKco-;9Pkl$AD%h~|0ezK$!}bjdNTY=LO(eh -zusUDsQov8UO77=%Zvub$UpXJ(es9KoK2`2#81PfjUq$fGUjY6&^yh~-?>pu#uqToK -zA@+X;V0B*o%K>kL|4_(-6W$7a3i9H+&iBs%{4u5e_)5U4ez5gz&^O`F5dP)Y0=^IY -zSHQ==9sUFOGfs7$_jJJ3C260%4DdCm#~15;FJQGl{5|yhPfL9+{|@Ny@E;5Q@>ReO -zfIcDo3m3c-=dbib{xslAe=PI09`-KyZy=8Z|84?S^B*q-{PQc;yYZM4{tf(J$)|lK -z;B87g`8L46I#TKo6m9z -z;0I&9LcV++@IPEH<=b%=uS@-Ti}VL<1^iRcx1gT}{r+p~-FZXre?Rmw#XdUz1Hh-_ -z4o}_S-2aV$PrRR$ch(1?AI_|I>Gz*M1pfSd>92e?V0HfED*)ewdG2-RdG7}NdC0G# -z1OEi@p|-S_`Y&0RdUUVc&&L2)E|mJk?*Tss`unu={r(TbKd>n4XMP4)&Ch!LrMQ2@ -z>$1-0w*h`B@@>TZyc_WE-YfaXk(U9ValVfcp9j1F_K2X5djZ$69zmbuAHnkwj}`QM -zCE$zhl=%%;UJif%X)@pOaUWfmIv)L##P_!Wz7F^(?xzm;OvtY%;{9Z={2Sm~j*|7s -zr+p0iDg0H!KX5+a)OY24huZ+F`BBSPfL_j&_-T;AU?p8&s8 -z@&PUY{7?ly4!sik&ta0EF9CiH>SM%yZUTJFBP6~4AK3L7zTU -z^1oexx4_=t=-l@Y0bc|ATkL1#GwZbZMy~>V#fsDy>Q`fZ;D_s-?_Ub|%QwpS-^ -zUFx$hm-^V -z|Iqo(M!;Xe`sSSV6#!3y{|Ncggym( -zRp9#=;ClW@*M9mQ;AO?%{gf|(pS?`h2RsMxB>1QBFP;bZLyCX;*MQHrWWUqK_3KhY -zO1|n*UxvMWr^J^s;477UfDZ$%KtCq=MEb_vfPWAEB;pNkzhPbKjIT@naLA4DccZ@l -z66bur3RvwAwf!qNPuSlAzuyFS822Ig%RPWMDE8e8zY2cw7@0r2`D?oW>??qanCE~ -zl@jlMC*YT$pTvx_-|aU;|M;WK|GE|MuaKX()%ktp+rTHqe*GNaF~q~getu6d`oD_v -zAG-zoU8z@k0pJ4kT_KO(4_LK#pL8qu<*4+J%mTgv{iB6`dI8|~ApRxjvG+FkTl4Ev -zPj=Qf0r&;bZ-jpSD!?Vg2L%31-j4Mn|6Ab8TLHfh_Da$D{sZm+ej)xY;(txRwUYe( -zF?V8rh`)&M&jG#{{nLfM^(DZKCrEkspzrAM*~!-uF#_*F)bI@rkE>5BknJ>EHPl;P2ib>*2HChkrCD^RF%h -ztoHMKKi~~Y{37=Q=)d2W{Q2Q`!(K=HQ{4A%z~}tta5rD{TEH_68L!L#5d8FkvR?9C -zfVVwTe*ap)YX6=+KSI3X8`A&vL%?;+YZm&%L;f4|)-Uag3jrUUm-PQvz}KfGzFzR- -zbvQZxhxEzI0IT(acLJUOz6pQe89!N<`a1Np$K$hP&)f|7N8pcQzrO%{^Zn&K>C=A- -z`S{y)%Tk9^*BfbT&6B=P)zxkrz$zX9-L(SK0j -z+dBZ?1oHDaU -z6Y_ulH?SujCD(H+;On734>-^NE#Ozfo)`Sd{54&`4(Vxp6*lr1bzsAv)JDP;I|`wE8hRGKZ8Fb-YN8> -zKEP_cegg2Hp^uI`=k-;hY@%(z6g90`4q1Qe8TJH`z`^j&I9`zV70&d^!<8LM=AQ~`G9`} -ze}}-&djMYy|G1Ecn-1wooridh;0GT8tj?qVGT@&o{^y?qR{KkyasQswL!T}ENv{C> -zCHQxRJi7_7>d&5iKu>BI_U_5f`MwzNIaeRy=Fi;)`0f|W^-Mev>rwFSXMk^diR5R` -zJhUhE2)UO(VLJ(~aV*a!Edu2lS^TLFIy@>QJwC4irV`c-k?ed~HsrSoO|)V~6L -z=q++Re**ke=y#*e`rp#iqxGMD;6r+}`C8`zR^tsn0WAIyejM^pobR{g^A`c%27O%I -z$F+bj_%GRS{n*2B{z`t?$$-^-KMU~H;NJp&Rsdi0ougR&8u80p0jvEJ-@hK`i~MEr -zzP|vzK&f}J5AV_D*L@Q3NgqEdwF_&f=dC}YC-uW~r2qEMfRBErv@a))>`A@lsWN{4 -z2f$6#M~U}sI11;1{HiLRNAj--_(|8v-=78eQ}EZE?)?6Gz^Z-q+=l_bkC2~#AK;In -z{^Mx2zN1su1O6o9kHY^ydvs6g6yzTX`uzsri*R0aEA;-K5v;`9AM$tDFXlO4%AR*v -z>T1BBg1!8;`|-~|?ik>UGS6%e;GN%-__hAwJ*j(?{wWiHKQ}Dbv+faiGxAT?JMaG& -z!1F(l`?(tM&yg=7*83;Gn@*SY%qKk(^bCDP#GB3nd>!KNUvQpx*|9yT%wuH#{Ieeg -z{&FwoX*j?CCE%xnKb_>jPyPEIE&uX2fPZ=15iUR7@@SktWy!Z_SnsU)&49akL^jl3H>l8o%36NTu*8m`D6Xg`?mtV4fSE-JnDeY{GiOoea}B& -zKmWJh^?wZ?5BLzN@6`dT{=aJhtMlb=2mGO%<^B8t@F9rTZgJkc##)DdpX#0jv3qcL7%G?JrFCq{gP@ -z=l=xwz8A{(k7a;Ah*t=GqXc;I^M|J{!rp1UmjK?fOXg!v^nu=fD)IZrfS(Efg5VER -z{XK{`N_u?o0OaQvBtAU_u!_H@1HJ+DEBM`K0IT>rG1!y(D)Ohq`o07B1xo(bw1a<79PUYd7V&`_ob`Vk@O`icg*<=YNKa}4_Jqjy`A5KKLw*SV&a(ik_2Z9x -zD){qHWc;ZN_@juI3jOh+PlG%-X}z0|T>-4}qe}rFdbHHf{{mR8Cm(t`!3Gk}l3pQPU>Z3cfteaLH^^%eo2qv$iQ -zAQ<}HNzU(o2w06T|9!S6^|ZIj`~5Ot@rUUDcEGQ|ys9&t?>}w}`sIag00KVu0N2P3hpZMqZ -z0pA0EhtO9~+K%)1z0@bZ3;0~f7op$$!&pzM{zgf!Hvqm1{Ib_s&$b;ssh=T#Owhw+ -zfUoU^$i0Do;()+3yMI`p6aUhnqfKjmMb-#tR&!|MRQ>nAeb^GkrQf18xoPkC;S)?eaE -zz~6!X`B1En{LPPe9_)vz%#VE~;1u$w1%4cJMo;Q(ZKMwfR>fNw|q -zT*Qn1X%_PHOzB@41N>q5yM(=PHehu=(j(`fe?uM;?hw754EUx~rT^}SfK$+ig}k|_ -zjPv`EJFi0IbH-r>Z?#Jo#+EH=H2t -z+3x|qV6VjIf2sk0?>;Owk7v>Q@__Gyz9H6g8Q?=v?|8oR`@u!%zxLs7|DuZkUxa!( -zVL#sncpUnV@Mj%*7WBb}-0u)zHDB>Yz~?_y_AB{sz-oWM<$6!*+Cz_WpPy>z_Q+L$ -z)%neL16K3P-`dpa=Xp!OPvl#E!P(E-mLX4+`pfG9zXkChL67&_gZ(M-gEZiCzJ65d -zMfg6+r%wR>=@So6UEw_MA$vjZh(`;5_yFL)AfGVj{QiZ2)qZ2Y1N`z&Oa1Elm7dh! -z*QI{{;Wa|3mWgHvzu>dr}@B -z@j{$8^mQSRzD+RdS%iKx^CIv^)K3e3{e8e!qra`l??3#-J*g-EMA{#B0zTyg$)6v1 -zPLJk)z64rs?TvudeAy4b6!)pj)7bGc>}-=<|1SYwf28C`m2*LV -z*GYMK1>nnnEcwF^0ju*4KKt^X)Hd{=5&Z49fFB9}xWMNpz5@2eIr4p91+2>Rt*-=s -zRqE%i1w0Oau{i%Hod6>w%N`1>00E<6#-oH@b -zBLM%?TXcWZ8v(2N&({LJ;O&xrPJb)(eaH*pufGTIJ3b)kx$kX|cS?Nc(6<9$lz7ss -z0N?asiEod12mGH(eODduA2IJ+#4G;?@G-M8f8)Y;LO*=6^v8S~@Llk43;dmU7yJoT -z`TW}e-wS^o?VZkl@ZWGg50jt&INe*PPP)%n3Y-V1-mbESQ74d6M&e%=*XTwT}KYa54Bf{PV&dz7=p4pBMGXL+=L+eku6lrvX3rVbb0_`2&zIh|dcCaw*`i -zzX0~iA^f~1J_!Dy$mfdze@m(7_$=Vx!JjVp@tuGRA3ZYl8|OTa_z=$f`Lh4J4fqDc -zcTaSF|6agPx5A;&(ApfwLgmc2LBZ6dn4f2eo*!!{4rp)U&v!W){}a)CHcWQfbV#zoOgCB -z;G^%5_`dfF+|M4_59D)z)&5hr06qi$h37fzIp*V_=k>h5H1!MlN5I3wl7F8A_~oF# -zOPtSd`~>{*pON{ER{&oBgTqogoZsIL_@XP0O1%~^=_9+Z1bxFkzQFnY1)r4si1^Pp -z03Ql}q&Sbpr*Iw*kmqwA;Cq$(z60>NeNsMO_Gx?{_3 -zbB}fQ|8Bsi!TuEf{;L4b)z_zbG@MBf4ay!mUuUx&!Lqy8_*r39?jTYMAn>Dy#{f8jrH9;o;GC_Yd8@qYoU^Dxi+ -zJnr{b(*AfI;IAq4|3Se25BBCs&iBW!h5m_nprE$~;Pc)j{Tth_!+l&X-~W2Rk5TyL -zZvm_N{R_VUeFgpb&cyQxpMC&11N~Rv%U=Pj^A6{}2>B2BAnxlLz&{;1(yiz3`4aB$ -zM*01Iz<1v&^@9%sKJIHrv3|1jzUK8kspmmno$Tyy>z84Vz+WZae=*=WB_HgeH-LVX -z`*|zi3$ec&obPYA5&TEVC!GTPA;`NEo!`F>u-d=qV!$8&{o!tZm|Fm!26-an@61== -zFG7B)SkJA1-*UI~Kb`Vb-T!zxwcivI=vxFG$1yKe@6 -zRQyH11w8Q;>Hj_A+j{(OE8zO0<@tUGuu4CBZ_)YLzX4Y9>0!5mp0`T=JqK9LU%d`+ -zZAtoL&%LcD_247r`Ckh71mr(toc;YC@C^Kk;`~N#$Nj%t`qM4~T(3!a@XvR^eo^rA -zy@1CDCI1}0vnTbOdyYs6|HxMWtMdfT{|@|v;K$!;(K`CFQq=4D%P8g=F-f}hGNRHwvA3& -zW4Wnm%Sx5(x;m^ZSghDh -zyR>0&uy+Jc4)~BYQ?8b+e7&AuvFvKIzLJ`$=ND|Nw6w6Wg0Co$g-;PHV3+pf%gu>&zj!+T -zh5vOE+lT4njYS)Ga{BlP9#vhkihK96o!EPebNTA5ZRPRUe5sV3IHg?neh!PxH){*! -zV%R4#1D54|lGP|zXDfDg!v8$1K|U}1bD5!lr7Q -zt83JLp{$hsJe{$&j_usEam=#DEdc4jpJoDo+86lK{=lCO1pag|@TWt8KOGMI=?MMw -z^zr`1#me5HlHJUgD~)uoy$njW%HSFOL?hYxY#JChF`1p7evY+e*ZAmkZs$0dlK-n| -zYto(>tu0l-s5Ymw%Za|2?xm-I;Z=)v!bc3_2^BlvNc#QJbhZ+A?R~x0XdX+gRDfl* -z>U3?lU7cjiy3T&k$~iH>Ga~qeMwOqAQuG-nj?NiO+8T_1%Ew^QPIh&=o -zr-!WRd}BBJ5IEqDTFDN=(gF4F(#`S_NuP8^@IHbJ345isOfK8x!?f@npzs2-q;B -z3&rv%lCLb;8yhRtA})S>`>x7(-yXZrKi6z7ru*o>RvoGs^hq2T^x*7NhRdPYk7Kf~ -zzeya1KYG4Vs}3yFYqR*%%N{yF4;|m``)uGc`kQlhH5YG3yDC$CRu(h@W+ZNqIF^Dd -z(<_VibR7($k(;*Y)9Ey0bvtM1H^enJhOAEANsEi>x3KdLtV%nD%oG$w+r8C^TBTep -z+l}l*5p16SjdjI+zAKLXWZw;{XC!WWFyuVr-nL;i5P2wjgRMWPYIuQI!_Esht9i>4EZg{dtha<7PrCwW@$irar=*ZCH -zEx0%sGPk8!$h~rb(jlSEHJwbFE!6QAVzCzU1mxzjP+Xabn~P;&WDC<4*&S(TGE=li#&4ws4P{NP;x3&7eb#rZrE8s*gZB%Vr(P -zAB%akNPp_P$S)FK_X*~68^idV*T09alLAKp5lGa`u(hRJ%~#52+Z(GTkE5@Vg<23A -zEQwOH;G1;xEDE6D9nsED)sq!?p50bb_5&>fn%S@w9v5IrMrOd#eWlZu!q$jFH-mIG -z_QWv#k$xEx#Rxd9wW7JK?NbWG?X{sT;owF(j$U|TIC_nA9=%pmLtEPi)+(m8tWR}9 -z3t8Jo7?Y*7d~zMpf7bTVwTgW$XpeuxJD#JKY2nNcIE;&_%NOs^kRL(2%pv=2M}DQiQeF@M -zH7{m)5_5fW^(RO~7{7E5VdgInxkTEl-fRd^ -z6i<>N=kqx7i~1GqLgf>Y&gf7w>(vtMJsV&DoCWgV~IJBWSXM|_PJ)S*iW#h=5errz{)%XA=qa{` -zZJR^R5r{TEb+UqOj(5w9ZFpMTlT3(hh7%JZZaT5
O8t0|U;D6OB@c42Xw}VTxFq -zj|h)eHE#3NKy^6%sfJT?WsbJRm4xH -zuv%6Gf8A7Lb>HVVQ@S4XQcN^Mu+*rP8x_salz1nxCN5%z+cKGbZp*kPXTLQuF-8`Y -zW9a$r)3wgWk?tQ{3t%{EFxP&Kr5G(mSZfhv-^)TXis_@6h%k`wYjd5)XyDPqWuTdn -zP(rd)$}xS4-}39Qa@locV;U5!M+G*cnAe9^>0w&_fg^)R@MNPyRbqOtlDK4SViP(bR79I9H -z2NKo+Bz_`J)sGklsvwFui0+_QFoASfB$<5W%KiS$+UbNh%yig_Bsxef9@FV`0~Lem -zE1>`~EnZ;{f3tkl{wvZEjXWRn4^hm -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 -z*%4K7{~k43i -zN*qPPTypHIS*uvd!lW}e81!)Js;x6D -zzC6|JU#KnHxydkNJ^Zj>!)JGnBY+Oi2R*~8+X!qU2yWAX^*8Cfc0v`UfRJV%oBalv -zxPAk?x!>C2cq8~N_gR~8+15h7nx93CJ=vbnaA${Atu-xsVX?Vlx&97z!$=tro{;Xm -zJw1T8Qx|3a;#xgBIn^AoHda?Gc(d|5u?l{m=^?rKIhNB>H@jrQP6Ng(UF8US?{aN7 -zVY&KB{N8zESB@K`xkKETzE|dh!YvP5JNSj7$%_+nC7L($u)bn^3ZZeUwc|mYrQ;B`#!Y%+3p6V1E9f0`!J69GJrXq?Rw!{I -zmu@wP)3mlovK%y#W#Su+O|Bk}OSfsDR-sR|qJ6YNt;UlyiE6N%Fgg{odZ=V039{0_ -zjkr=bOg&c|>`d`mV_JDz%WFv)kMd*+4TGy1@fdEj+TIa8Bf`n4Abuybjfl4?QYp4z -z3T12U=p0>GXC#a3pym;=e4%-86{KtWN5m?UTy|%*kcb8Psn*1Jqv^G)x=6%c6m_Hn -z8cD><{5NYlxKILaM=$B<3L{B(6||Fx4f*+WH*}PUMYMMBMp`y#D!~?oA*vwgcumP& -z!+OPCx{TS)Flf7GOd?<(%TB`%gxsV{ZO4W;yh6P@(;P(f -z@aniXYoy1PC7~f^7~v?1=ic7vcd5ll*z&l}42x{fpKW+>jNOOQ*l-&@vi6n~NnXON -z2njZ|;;}ZYl;29HMVjG-F>cF9H=z44UstdOX4j%368j2CC5CZyDb -zQIn~lgi2I~tu5thzJj_76fyWJ{PBq}S8Ho7=|Ukgg9O;wbu;a5jS;EIs*03H -zgZq#?jSKH0VH)1s4U#mxF1rfEXnK7(88Uy_J|aWYidT&QTMp8#MOoR6O|(jw5o-_< -zlZ(#I%FT#ZE26XO(z6Ro2`Ao;%g`>Ye(e&nk^Mx~EOcC+wtV!)<#(NU4R4PvTRXbt -zq!PBHiwGyxj?3AOu6xypG-mj3Ey~!=ExlFZG`v|z)y~RO!wZEhjrGFBYH!CD5KfRC -zmz^D3^I9WD1FMhrgLYg_#yn=@qPs+ZhIhu6i5=KpQc2i>SBH~Z$K_uKR=aA1W{NR( -zK-6{oY};IKtK`+z>ta(@TW?7$$=Z8sI6bj^jZXS)+FR(FASDC;jTTe`opz9#4%E2P -zPLhw|MI9j=!}GgBGN$*16AMenSS?~PEio~fhz8`Dbd$P(c%%8ba(2j>3xR9_Cz$g)Sw-}<5M_Z3dg%43di-;=P_oKrpK9ufj6zA;HQU#+eaCXU0psoYyhye>iELXkpt<;27oX^zeiIyvwZIjo_h>I!JJ4a@+=8MUicW5okVu~Q_l>=aN&0E+B~zsjN-o?9&bbACC7q0Kha2zh118) -zVp$>{!>P@ZATPR?< -z7Jk}H_gT4G!@>Zv>O!q#$EIc&tqL_WS|*0FYV4;*{s2DSvU|L! -zvj{!ja=DAgTRwn~H@>V+%pCd~E7c+-=B`Qs<+7#>@iir#G1@Q`-IgJX6Q9Qbsu7?| -z1aZ7&gCs`D2s@vy^E;+Yy6THsk^}~~PbYDL1MJiHWB*BpJ%t}AHk9~*ykB!6i^yNA -zEn%sAFRH+cKi*IQmEgS*t!TC0xARFh20>`pn74?}XnD-zSqZxHp*WHj!8&GlsyMRc -zr9>1*@~bT;IbevwP91O=&q{W{w1|!#aLY>xJ>Zs5Y;HN}3E+#JJ%N^&5_$r9)vvkq -zv|z5>^c<%7S>+BsYd-2(+$rhGNUy~um8vKuBGLg8=VBCNo>^H8J3{rWwPw*9)%rL- -zk2ut;9MS&eBQn~QaZV?W@K{r)vvq9erj28k)mSQ6Im;cjxS_bX2ruU8V`!Xj%{J%Y -zZz!SkxLL-ChQ;M9oO-^WHtQ+N+A_Iu2L$o>W(!SttZk!{&c8RGx&f0NHc%xrXIbe! -za#dJG78Aw@_mudAHM@7Og%WBnYX*&rtxBz!uLM1%NKYvb20eW9bH+FB -z$c^GgkZYiHY0>%`F>PTqP1Wc9P79>LW#)9vO)O94bKri^CaBB;0}wFbB9G}5)lzl> -zKc@%B=CTKyBb5$k1o&QEvWk26ru(Y)9t+7DxJLN1fgeD^sYN7+ECCZsgd!Ndu~^At -zgo)JW1;WDZ#&E4}pS5H+npwIQc#y~7c1dS2Pqhdft5wRym23t|#|Ud;P+uxGb7+OT -zZTl2*dmH%q^2D^Yd2uJE$FPeF&j`?Mp^SCvoL${msZe%CZW-wrX^U&8B*TWS3A>I7 -zqYFSF`b|2+D73~XtC6L5!*{)_G6(vW;cFco@f;c}>QNtp!h6L;6~k@lr=gnKb8v~`CNQyROucH~jcm?jDOX~8O6|OZy9#w( -ztV}gPS(4NAIk(?fM0*N5-EZ%0*1=Z6BkJYqEZfdXlvhIL)P#jrXo+Ebma&lN79ENG -zE&bq()$BxZ9yc>jHd#B(7kV3W`8p@6T!aeteP>73Q3NwujZY=sH*QPcm;V -z+aTzdsx(Td%sM2M@UX>|9BZipUgrFc{}5a2V>6sEx4O=FmW -z6*h){ut3XRyST*i1$lcRs7^e4OMgPRjbw~Uwc}`AJ;!r;(AsJ@=`=`?u~0EP17KSQ -z>XyPXv_mmlw0>-gkOiX|qFa)QIYQkgY;>pr3VT5?Zk7_%M&53CS^ie -zjoMPZXgh3*@<~k_(Fh0LMYGJ}8ll_cG_pC9c4j`&jd#l-cy7KxCVbMJP%-$ZI~sJi -z$?0eYjU%jA&^BY>!eLF}YL}Tld%2`2^8l+gXIEfu$4{9 -z#!{tua;;M0;s+N%pNmq8w3GE=W2`&_N1Jn|3hF}z9o0ouZ`#vj`-LXUb(siN);R>? -zs*3$Gr|MD6olLV2`K&l@k4Wz+NSa}W(WL;?qk_*|`Fiabw -zW80K9EPkBZJJlRupU92vO=t1HUh#*?FPQeu&$HRRV+DKy|H}?q>~Z)q6ik{R&lPOM -z=h;nhbXHD9JrroROsSSu9YZ&MEGx`&7JyqY7SM_en*KC#mxi^mRAO4aWney}c_Sky -zRM}x;Djltxmdu%1NOrsrf3wgQChb`eon2>gjC!PLY7$JKU`>n;4fed3eliw%HDZes -z`Fef<hteA1^1L9;u_QW_q&_k3?OaBX|QJXh14XLe(oF -zLWYHtAqV@5ZJEvpmga72b}3&k!Pp#FSZdmPvjTY|-X!98rYSuoQV+1djU{p -zA+=}7njPDZF{geTR^P`UhBfZCr>ASXpm@@BPLxM69)1sDZj_%;GXBQtihIA`TS4Dnm2R4o2;K -z$0&Ba7a1jZp&(#-opaEZ>p=qDkCBb*HYE%+2#kIO{kT*;8crb6N+QJ=JVCuB+p$D! -zsQx3?1bhsPcEa!4i!tHrU=*SHFJP14l7L=b_l5opzxWiWPB&(q!u(nMLgOz+qG(z- -zz!}rVaZ&ed`SdchN<|fG^Lor`XI!kP_mXQ-aU$iq!DrF3euW8}dbAhc%Y#mYq} -zlo^k;s_COJ#aL*Kl#V{(tO>V>{5R>5 -z(L}S67&~B*297NO{g}YSmrU+&?W|()!N?_$f0?P#xZXTvxMCe%%`o6_-TnIoK%g># -zokE#l(h3NL?Pe`(d#A%P2MV=X1CBgd;>m|nrh8fITc^`A`36T2o2pSjV5Wxu%=2gr -zIs3U*$9_vfNDbQrTCXE+I&iM&eA=(Qxnw%POK*iFvuIONK6<9inXm7a?HF?bU)RPuY0e}if|d`zG$5o|nTs4+38O=qKL%J7+X -z;g_x7hK8F#ij?pl>MV;qDKn!i@?Lk8O^A{KVb;co^Et=^hT6GkpT|m3{W_jq`#cJc -zXy+Oo+bj2B%@Nap-Vj!q3uZ_maOTYN1n!xl=Ft`OQw&_iPDibbeS-m>BM=^Q%s69rZ}FY7pRH`uPW(18muiK{Lvd8{_wlx#XuKe^vZVi|hKM%yvgnyH1O$UW-tzaNq__CMpy#t;*{JBcmgL61iFn -zI-EYm^TO~*aa1;Kmt+fe6xukb{gNCc3AS7a}Aw4%;A+!CVn-L|$!e51iRDyOakvWBXLJ>m^@SELq9j -zIKr>4X&H2Mfd%=weO83$Mg^&OE4cQU>lq#$2bIs-@eplIZHJ14PzTeKG6PMPf~@S9 -zrH>&e54C^zHXr1bt5%TzRGr;HWzvo^l}1Dtc~BOmJF#Raiu2-52kZH2skYz@X|hBj -z6lH=S+rjw`95~sDX=`FTqyaFQ`_iDZH}>Qga}zqd(00IG)RV}L;@KSGJSV>F)?N^x -zc$-DFt44rMb+5;=Ifl@OEI}tFZwNW3dnmZ6as;AoxVI4@fSaw3I34oNkw6Z+3_Zk{ -z1F*jdTwwQM?pZ^DVIF4fbe}fh0yq|oMY!2&EAWK&FXqd2|AaRZ`YdIaBac5P8>|3x -zy?913(z2^glARiJ9kQ${QgboaOyE=w_=Eah3NQkl@XvYR1xwpg%)bun7Dx&X)h%L} -zgk0tE+;cd`DO16POZ{f|lv|b37p{u;DxFIZUJp+(Vl_K(bU+tV_>JsbLTVHSy6J~& -zv=m(LSzJqjgd7Y7<~$>`2`6>WGF1JMoLOoJ7NK`?;bhD%99(jg3kO6Q?ill36jN!U -z&B+#cmLCa;O)(F2U>^OjAg=8E#C9fP+1+{e3BBCAF+6QVwkBl5{brEZ@A}ePJB2hj -z5KdRUA_yhiF=P_!)?vQs_y=TGG9%SMEi=H)3eeHr6Q?)$JNuBh#dB0~x@|_9%^Nc; -zf+ -zxcJDR9^JKLj>IWh@Uk^ZFhcEtGtrO7Y;l4kb~Rt9*j9NacUq%94zE2_3h^nCi%a(4 -zz;eE_WP>|$MQ;-9eF7rUNNn(yRP20REE{At6;ha`Gc%PVJKiDaZ1Ijb{#9!yl=xwtI6~`U4(apXt7e8MRFhG -z$%ODerri0=UY_hrdA}^bx7VBBEAxNxNt`~pmIIP~8~LehkQ52$)7Y*-*HH17pJ#~2 -z%B5+Z!GLH2uk5Ycya0h8CO4F|gwni)Y -zE@g!K7Wz;@g^o(xgoGP*qF!6f&r;)RktgdCWMHD8K|g2qeD~O7`&lX>_(6!hne!pP -z9i-wSDkD4Yz-Ar+N1sP#jjW(+l|;0N1a<`3K85lf9(q8$o6ssiU~Oaq3!kG1MS#GX -zcLf%U?M$CSGEbmN0E>z%q|Dl$iR#HViq;r-o?7VX8qnDEZkAT7R3Oqy636KRZe!S@ -z1_f@Jw7idPn-_T*j8Bh1jpNkGls!3>a|D*m{AG#avRGcIQ8+=*{{0rH>$lgq(=ueR -zc#2xkVyqeViA1VB=nIsH>5Ql#CUl0jw5!s7{V)VLstr%A)pzHb_5yfbjisqVs!yisPcq-I$Q8oUN-`f0;_~vi4Y=#mSF*5p?BU2CyD9< -z+{iJLimTZTQn$kx+i64 -zwbp-3uU>S~&QQRns;!L07(Sc8Eu*q;gUBP_juKHKj^i}y1`BV&qm57FuXAXF@x0po -zkzVb=P_K4;J=cKJ;bt`ui}a9aZ1$Dch8sn?Opc=<={g@+m=n4oe-SlRanURWcRS!Z -zX$d_A+#+eA6@~5Snu*$BkWrzu>w2HSPi1MQIN&(97Q|3oOV+2GC4Qpde4M&==(7xPf}jE+@Y-J#4W$u%uC)0EHUnO|U|p3stD8a&S9SsKyntGY=L -zrgQVl6rJIWA>r-95g&{5=~)?Z+-P&#I0tkzU00v*d(9YX3ui8hp*624at_R?T&C7K -zW{h~Wycz6*ixDfnZKmdh=L*DeYBHOKV6EYx+b13<~*S=cy-*6*Hkkw -zyTP<6Q`!TzA=4f}5-}W3W^PFQnhIYv3muL${4{_!z*pZYZ{SXQGPZd~A=na%>a2OI -zeR?#ljmq0Zv?=<^3N-pahAqP0#CEM{xymgOjzmyHX!{Uj#tJkH?dr6ifCj7wc3IDrpIq%QTcKJ57qbRQa!>6PCLc;hsKi59EC_dq-b3B -zvvzG++e|SM9=O9Q4c*Sni~;O!8|0Rb9PpKRdKq!aV{9qa^+6~5C@$cd_=!aux&LEn -z226yJEvSpIVD>)&jiqm>!Nx6F)X2tdh{rM(T~{fx)aiM=ke&%Nahc$ZJDr~c0a^_4 -zdn1g=dQ6f50k5I!i&{iC8`l?QZLF?XrF=8*x7G|P`jW{6sYjYv61n?BtO%I+8)wFX -z{H23`P_hj5EIp%Ui!4sj_VB^%(| -zjwMZ}B`j%Rk8ViHgOk6YW*fjbCOiV<022cXjain4fz&eL?#Am_!%QCzjPRy{Oj@$% -zscaL?Z_!vLs?!lUfjud3zSn5Md{k$p6FzkN&{TfLMib-Q{CIjm{M#ATh*^dFmu{?) -zyOQd;^q}`Qq%1AZ^K(?l8NHg*>_l>CrNhGVENK9ZYq85Pmo_0Lymc^{47C_Ik`{_d -z4mfX#!xJ))>MWtfX*h;OU_c(uytf{sWAsKZ>iYUL*ZP<T6?GkxT-Gju_d7P@zbNimR<^_KM33{o;!6(rLk=t7yJOEtVH;)GydF3`sN{ -zl{v&8qjFAfCXq1?fZzfC5(_~@Zz$Y%omMikAzVz!Ma&39*XsH9*`&*H(SHvqA_x;> -zjl|&9imRZ6dz@TMTZv+jin)Ly4^DI0Y(IsV8JG4Zko)z7P&L6DBz4Z4d}ip*4V!t+ -zl~+Qk3lB@M$)Ii`j4yi|f-a!qbrsU=h3|-`vGnEZv$?VIpljc^;bx4gPJ{8IT3;}G -zTCPsRBT${j)tc$KDiVpuL(_5M^@tJ2q5GZ&oep>9Dx%{H=og%;u&Og4AO8(&LFZya -zI^BR3fQH)CQ!wW&$!RI*1}*hBc*DCs)&M<%BbhO$0VqmY48eJQNwOH)n=GrvI)spj -z@UZxH9@TkQzQo}Abosmxo-leG--pszH8O4{(8Huk#N}Ruye>9`KTr?9X$mp%KUI8gvuwgoF}_e?*MdFL -z11YV{fK)mOtDAI8xk!8>mSI|SqL;(*N`f%lj&z+Wu{YPAjusg`a6J&=*)X_3-O7!B -zqX8U+9S|AO@}aC9rDGwpiw!f|%E_DTl1rSf+-y>q`o&aXnWMA42XER_qXN%IdSRhg -z1DhyMlSm)VET{Z2JsdEy0JoBSIziAvC==NkRL(@ -zOgQdmd7~LM95mcOdSangS^>?I_NmyZM1=0Q28)$4RN{1+eVGG{QBX}x-%`Eo_;Aw0 -z@QRl(;soyU<$S$N{+!`Gn9O3KG(E88J6Xf}W_oR!*1jIBzR96 -zED5nJu6Vm`ylMTS{k%*^aQec-IK_4pzj9*ctmIYjp*+!^WHA6H9@{W_1LTEx2s6v- -z^xCTMV~wks(BbCQU}FUx<`>c#{{L=03*C6Smp9`qQX>Z>nQ(>;3GbFsk!_C9<0kwc -zDgml_OkVNTd8^7)_|7`cI-y?g5NpDwmAWg)y)ERZ#WW4RWD6D^??=aXC^>Ch13-;h -zvbGd#G!TDUTu!Ok1F=J0-VU>!P(fqy>~Nh_1SjIi_T_CP+f`l7wdz#7>0o0gx)e`R -z1#YjnTnO|rC8blGPHWk_tV_=*DskzXtmTzR{!h%rz`03>vvReDwR6#~E`W?35;l0{ -zpy7++8)xo;uxyQepRyP -zq|0J*CCgT6k(UOAYsI`Eav@+NimE5VvS|K<-ps7T8%2IVuy%&bg)WTgY3+rY%_5YmEYm6Ei0KUOv29F-c=&RDr23`WFVQ4adf8CK+i -z<)Z#cd@V3W!yX#m`zR6rkLz`CyjY6Pqib0~2%|>RgAqn)=I!+I4r^9JaWS5zwG;m& -zq}F+>>K2CifWLy%(g)+|N`61TKzTgQlMev$)XSl;Dq17Qdr~ebIhE-@nn@K`&=VhW -zJTlpS*>VwlR%5BIM(t99*GEYv7(EE4&o)N4fk7`?tPB~NC4nL7bdWboax;Uqwdx3? -zN?lISim`x&I?Kk9Cay}vVFd;F^u6LkdVeglrzIWKz}=i`i=D96K8AB6eBH@9&5Qww -z#QYiDT5R)IQ|bcFlTZL>XzD~)azvv#&ZG}G#cCZLr^-817NB=}B8fXCABwdQ5!6Ng&l^@e%|?&&TBvzcOi -zm*eG292AIKoP|sC`aQfBMcm2j<*jRsHm0l#fNtR5i9us~_cike8BD4?(T -z2i0+kiLHM5DS?C}r`nGNX;eS{+Ha(F;~O*U|L -zGfl!~b$w>(@bavg+!u-|b7;t*#s15g;_ -zfkHSw%9vTW6CD6kG1G{@BF8E71GfM*dOK((tk~PaD)zPp`sMY4{;38z*_&WWIdh6f -z=SSVQm*m0CbB`^<9Knpm@-a>1nxyNWo{E3Z8qaG%coHvdtvW`K0{1S2NuT*F1kGwl -z9~qQpol>x!Hf%4FM=a9qD-`B)C|xgrF+><<%EM13ITu2a!+KlM*w|OO -zIKVlK)bvtS-#1x!OTv88aw#xQ7nL(C^L?z -z9B$mTFiMGW+`P;-kpv{CAE5<#je%Jl3deZX~f;K6h08|g2)6@7|_6ugU-^C#-M#k0miT~kz+M9t1wR7vgW -z=(?AX7~G)IOB9KPd=D*DptKc=3WN@fn6}O)vf=F0eY`iPan2QR#!|L8Eo%zEITq10 -zbb3aYK;D}QCI&QNaySHUfHk6SPX>Zrp#Lu6D~)cX$fi#Itl%|Vp*NbHF?hiyhik<) -zTU3V~I4CiL$aIS6B&})RoRt7$Q7AbMQUydF&_LT6F-;y=x;l@>y$t^?CXLfklaI&4 -z=9O50x=kVs&fAq&29!oq7K7i8jg_fs_S1w`iiiT07?!p;JTt-s8r`zYj*ZBH;VO;p -z4wwM$r~zGg18Hh><)bba)1A3a}Uq -zNeGm0jAMvykFL_-=Ne|y$BY%x*(jWiFoII%sCzEd>xzny{X_QN#d6)|b?eamp;h?P -z2CaO~&{+f=0ICYPiNMcMEjL8LnMv?0sw;8SwGM_v;W#D?P`E@?NYqJU@g$%s#vYCq}6<@e!b!Fo23$J&=kk?DTkquA|CTv!(Bezd0(HxKo+ -zv{bRZq~p|rnrTWKT8+vbctcUS!(7I=oYu@l3jXMK672rNPq(p|Dp7t(a!F!zdzdeh -zYh6KMFS1p%A?*y&tWwR<939n<1q(gmQQv?nA(=$x1*t4N6Ra(v;j$}^g{qgBExCrb -zPH+5_xif^3BQ+=yjjuh{u~O~qvv4u4#a%0Zno;Pq&^K-#S`$-1TSz1@3y<(gDB_S5 -z6TuVWi0@NLd{e?j8d93>TJJtLwpl4M1+UCTr8pJRU6Vyt<0`%sO(Zq6mZ(|A41;CEW31=k4 -zW87FQ1Fl2ETbXlQgx9$9S2)eOQK2KQB{3gK53oe`r5VgM;{#9UK^*}Zj$X&3=AtAQ -zAub-~CZADA1SV6O5lb&skjAV}h9Fu%ZkjR~!l=W!GNnIWEjOZ!rdn=SUIr({3+ls0 -zGFC*-zqr0jBYi<&LV0%vvT`CNhs<)mQZC74YNlL-QN8OjFvHCY&sw+G^GV@!ywIA%QyxOq&xc}#ANOwBQ#leP-8S^(c39U9^p -zAw&#O?(dxBOHKFss>-gf%Gg&2lw#&QhMc*mCJC^~DBp1H`KsD-yzGMRI$fKliXg-t -z)Wlrf@iJ}UW+8GZ7aa}_G6i{$E;vDe^#u97>ZAe&d8{;7dLfSKz$oMT)?D#5PN8G -zFd-5zH5P42Jfkb5e)C**YfF7Hd_M -zhM=0HFjjz3$J28{MybZ|J&POiM12E^MHogI17nMD3zJC=8Rvv=6mRpirDjcsG~dNR -z#LS4`J}qdtTJPNfG|Hfg5}ba38Z{KwfH!>F%^>ut%`DZ&7p(GmW~rWKCpJ%>Dfrss -zl{5HBUh++5v1>GEa9GocgOmE)V%)ZIdwK<`x*mG)Th_W+>uY(u=7tg}c192@kB??# -z=_$qbN+&9Qt~@seOh`XMGe4t?lxs}9zPR(|A938wn_(`;aN5mh5 -z7lq-GXW8IKUQ9>N!qAD#`0RifH{nS0R?(WIF&wHnA{vd8Lrc=*8bPK7-#ho`gTJFK -zsDn6WVP$YNr~8-}f(k9E-j!Ar;2+YL%2yF`OyaolpvcIidDR9HJGg`b4(bL2?SKky -zP!zBO^Xr?Iy|CC+=75rO1MLyq`3hZJQhx(O9NB^jth2B>W=7N0aWJ8(j4PXjo`K7l -zWV6e7ZL!nyQx!JCNz=LBg2a4-IXduzmjW82pJ;<{)>0X0g?<&lY0|*7&In~D{zDTl -zdYN^@b7$Fi!`jy&Sv6?5C{~{xs@wQoZ4X;6<>n;Dw0__jCWc^O2y1M?maZur1<;{e -zqlvrqXpy?~QuPKhmdtUURjOt1Cg1qH9_DB}>5@?iX-;-GPf80d-FLG;+FTJ4JzG&a -z+?y%YPp(BqKs8i;~fuAc*bhn>^HO4 -z6*nsA>7g+l&@7th#7_)nDl|x`7=%J56%-KX#W8Ipd3gbOZw~nZC%Rlp6k_V>ijJn% -z5sTI;E+Mm%mOCYIn!+8xou;BGS+FnIvjH5Wh@FW}8Cl3V$2&=`lI2P0M*I?iJQxL| -zW_2)i5|lvm2dH&8tU1`W5yF(?;2t}_8(stSyU3Y2t`MeNR~#-X{R^ySZMR+JHVvO# -zt*EH&nNUV7R3ve5JGxeiGR^c4R^zCr=2K!qkR1`%MCSs#QTV++7^H!_i}L!21_TuD -zhmXS4e}bH(zV;KFqv9lnutrO1ygt*Dh*HxHgfl`(Kt)*9fV`ZePb!YF097vt -zvbZ~=NX2EOT#<4Qy>s{r{U8=6XPq*<`CU5Qswiu~A!+t^<_P2Nz@v+j(y89Du7a3} -zUUe4HV=N3Oud}#sJTDdtMj&RvzLJID0?!IHY1Cs))CU!vdx8`ymgXB~zyRZg{o-nF -zZRP=+k2HjaTMS1z)m0*mRms%odaXpV*2LF3;Q$}mg%w80wDzt -zIblu}tL01&JTW}eW2-6CBWZFQQ55kZauLYfWokDqocrdoV`z7X6gH;o?(QkZII9GtwRrg0+!C-(lxY?gv;%@_x`{^^@NKng+LMhnWo%Ad0=-8u}W`EYP-u -z96qStFqw4r2!_BOALz#LTN^15ge8deG9wmc0pXZGKGh!- -zd%(V86$_Zr_YJeDo9ce7foxKwbuA(s}_*eqN>0qsYf(q3A-1^lz?t(j;?gM!Js{2W%FKn@vTc=T5K`nW241CU -zuq?DwVrmahgdoj_N46oJ;O^ip*FDIQu{JI>Ynzc&3WEc(8}TwO)n&m56Gap7kC2#A -z2r9CjfXh4l$*gKv$L%VxdPQB{q1fSUoeB_QPc84TS5^(RlEiXlhT@D}TohH6ZE9(x -z2^rKhc0zi;)=Y*fJp6uYGC(kOz~{eq)D)mA@7NMYp)`{^L^|bTX#@ZcC$^z07nI`G -z?=}Wi(>7J4#&_`qJXo(F;qFT{ftK<{vS@UDx_ -z@@509(~TzUS*R!`d=kid%MQ-j70hN3 -z>?k-am++Fng=qsZWdD#G)FX8mK|NMvK{TN-XJ39>*xWU|Pz!a!%I5j2TD}<>b~>*y -z=X?Y<&yC=8YG++1Raf-a<*Ye?;lda|I-M(p!!27^ut(+$&^gtOXMI3kX`K1h$fX*?3z|Q -ztgsvrYjcBauNnIe0A0Bh?E*}h$ -zHF9ApLP+L^kwXWH0$cHgdA#n23&l>lOCgD=NK^feMn4^*;P3($hDHsi7p#5^ZKcY{uzE$Z%FT -z*utF|^J_F@0UQp_N@XqLr2Go)@`Sq_tIeKTtM5kGY++-yl&dZyV`f*wu8-vx3Z;Aw -zsx9V7p>Ywzof-6)tPG)?YEQmiV(sc?7HQrD3PeV%ol`qGnOCv>o7cNZ4C^JM%e=F$9-cVPTpo^)M#9mI-9NG(}IE00xb%$&I&~VRI|lPm{k8!qt~A<-)L_w1w;Xt+>8?nmbU-O+GMZ -zj1;ncaENCMO!CE-VP^dY(l(amj+bhwO8ZtRO_sW3mQ}946h2!+oy&YO(s^@MU!PW+ -z&pLNvz9!c>%tGPUV_i}Q>oyBDV`u{M+t61iMNFLZ1aHBsW!dVUeal$!&C -zr^vD2ka3tg9a==g4OCx4pitjfa*Om*yIA@M%PGazxmAQWAZs6%(nP+Fpu;pb!LS_! -zmZ&W;Q>b+GQ7r_+!DNQ5EzmbA<+E+5DR_yxPlRn)9u~;WjlstDyHNz02%N(4NEF*a -zb;6Z=(MGB+^uYYm-kjSNV_A4zAw6I+>v;iWw;~q+45(epm34AMzzCdN&#OB{S=dmooG5;L}ZeNIMaLxc+D-=*K1uD}52*k(z8VU}`*Tq}=n)!B3<+Usyjl};%u=J-Zpk$=!xuxpv -zA!}2;T*3g&iIDJ(aUBT)udX!iCt;bJ^q#kuTr=jz>FKCp1aWI99M6B?b``C)m>otF -z0bUhCCx+WjFXVUI!5u_2SB*hfCN4_$ARFYj+q4C;bzor$WB>ZuRCdlY6veU=Wv+1& -zs`{D7#=)+zE>VHU?#ep@FH<{p0Ocp0`PQCuF{ck0N6%8~66sBXn($@kf^%j@-m-vi-fJjroU5U19IJe}gYp`PmRVpIWJlcV{ -zoFnh54Bl2IHZs8RLKO$F84!Fg%Nk*hYkx7jiWl%?cT6u~0+XnYmekeE -zQk)tLQKm8JELF=a)p17M^@^A@L>#3177LU1_F1_WQbdSesfON9sJLJ!#;J&8kFUqL -zsqkY7AZ)UbU>AmT74~_TarM!}kLUqg15c9xBT!j^;Wok-9y{LX(r<~U*)tp(X~Kp; -zZs$ymBky1lO{1!{bZ@h~U~@_*qovO}C6g8w4icA&yUA1;E-i5vW^OOkCic(V*xqy& -z|LYZhXopTLNfaGH6;Nv(+R9*y<3)Q;@?q-2bTIis_cq`$# -zm8&%@xP+^$1sz#A<1p)Tcm^9;#CvnM)y7K~vUJ<#I07n9VMMILxOJ~)7>?>NKFwO8 -z3>Q0iTxl9nb1zGu2dmMLdD>#~kABJ>defBW%uXy&#Ze5Mx$KA=f)yb}11^Ve)nxV% -zUxMOlJ_=7`h4$kGx(taOKkqHsS{>8`Xn@US0@myD%j0lY-v^0c-Yr+!IfG$`8s=ru -z%05FvD4I@TUKPj_;(kh0`*HUw1cA4(09}P+4ricd!eXLlw92g`kUyRY0i!V-5v%mI -z1`qG4ZU{5Da;cdRm>9Vr?mqPqJ-Un*kgl=zodrIDs8Fk2vP0U4F@y~4)8Yc$P%JbVIvJ_ -zL}^G~Dkr~bSl-$(;x%-1)6+F76k}r+D10B3vVhhS7`Drjf?1Dwx?=V$%8^q_k^SBO -zmmx8^4hv&M394zYfpo=h-G{o46dWEN4x69mPgDE}*FyOUAjw3WL>iJ&QX-eU)>sR< -z1V`WXdoV{wi71r7GpA&@%pCW#V&4S09BIx3mwDXIb$E_@!tF(?{Q=b0rWKHO0;w2= -zw;hO1Go)(W-eQ)e-~rLP+(3gIXW5B4Qds=H1b;QAMie^9iTX^Eya-zn)wm=VAMMRJ -zMbaL+A#lk|2R>&a2v4co^;=jT*Q}els$i+d3fD;?i1Vp!*ZXKB0}14)nW-%6GOUFU -zj#Mj%gCy>11&@P-v00X%{nKs1wlLoo(|2N?4gx!d(*b6<+7CDWVla%ze9x!^MR&4Y -zyz~}A->&iwAmdiMNqQG0x|0vPElVw~@QHT6xSi5k(M&<}X7q{C32h@!Pz;$y0zaJe -z5^2Gr*y^)i3yxScQrM{ohU)~K4}UE#QAhLbqNTamlvOG(m&$!kB*n^X=;aI04Z=XV -zAqXiGT7BloYcckzy$qg_#ihm^OWh$a9)Bk8Njy}#)KHJRm@k%_D;&pTGi+7e1%``$ -zVt!@Q7>G@O2hYFH)t*Bh{dk -zny5nIKVq2VEZjsLW;xz6xww%$aE|1$E#{3@0?*;d5?^6~szIFAnPtE<3!lXw?qe6K -znr`3p+RK=$z#i#1{304aC!|=C&izr+nJ$}a8JT{&%7U!Lr8+VhF^NMI7mx=%J?Mg> -zia2blLt3rP0PVrmPTfV6p%COt2HkUi7tuZU+8g}wc*+24|IPV;nj*EL4*pz$TiDhA -zJRRZFZMEkDA_O#gL|=q)kQF&ayfs-rRBdJw%XWTdCB!Ce}oM`lK; -zYdShgFve{45JD=^874LXhJ^Ai6V_j+@?*wIgn_x|6#Q -zRYI}~t&bd~8Ryus_B#R19>L0BVMPT=!x@}@l`V5?Auhx3vmbdFj^4?bTe!bk@OE$` -zeN|DcRaj|C3O59nA@3Sq!jQac#WROTwB?#>MYoNN_b6_EJhu}mWl8-*9##NWr>2y} -zR#sG=0S{3uYaThlNmuPjBsTiP%|w93n#~Xqnu|+w8g`Qg>gWPEXn&4Ldjg&kzcD9= -zw-72U&7g}A{`hZH&n<}vpDyzR_;fb7aU#DFTc`{-C -z;P`5&Xoteo@d_IA^&0XVsmBV;dt9X_z|PWj@Z;cy4`QNfXr~8gWW7--v;yJjEi!X% -zE?+HGP^+?Ks014w6)MgZ6CfbYc2%euDwS?HeGN#wN!xhEF*{JeO8KiSM=xU5 -zi%_q9qQ#6(j}7JCwc!SREvm;LOAy -zo;m>pN1M0$0tOS)%fW$%;b;L++t~bLPR_18K_W~M{fMeS?0=>o|gp*6BSpw56EMXDmE^0L*Rh>O()4_0M#Q!yHa5tCioyFt5I937wr*B -zsbrItgd4Ke(4;?HBl0+*11qsPGNoWhW}0M>*A^+07bRutu%SpqVwnj(Gszom`dd?) -zYO`EjVs|a$`^?kK!l6KXog5U>45Fn8`14%f9s&kLf0UAhKe32NI8u%JohH*w8iQHS -zYLe3bW8I*5X -z%{dgL@g|iK;u&>x*oL=h;A!OiIhzZ6;qS%A)I8`G?Lwk>1Y(e_-u-5dX31@+GwVk&V2OsQQoe%;uf4uDw3LAQ$Ehoz -zIK@p!;Sz>5H4@nsyooT%2)EVBRJF{0*|0X2O2WGqDx9M7Z=CcMsSRfOLQp=JygWox -zs`T99_=wMx7$7>;KMU(Bp&J{zCXq~J2mu@wH9O_TBH18LDVLcAdv)Uon;MoscMU80 -z2b6Q}`9j*4+G?874cBhi%

|1&E2nRjoAfK!@q@Ie$b*rO8B@QX!?EZiz+slH;R; -zPj@F_s-`3$3I+B{-PM9zw6J$sQ8@-qNDr~#Ydjp#H^}BM%P4@AZ=e$(T9wxp7NHsx -z$`uOB5s#NS!*nCcP5D@*ik!P!x5 -zUXFGm7f#lU8U8s`H&%bq*=<2y -zIMuJ3_Ud0M@qi5?+uNzLWAu_9WTp>O!|H6Ne84n$sMI1P4dREqU=b*f)#Ra5W1FKE -za(Z3&$0`J3xGLefW}u+P=*g`DLL0LnXm(i4F$!=iKNE9Q4o?amVoD}UUmYnd -z?ya*NK`o6nFlnBpDRFie+q<7I0W3Omh>kR}jMS{N8oa1#wK!r#;kn9G-4yOp#bLP_ -zPTrJdRcA<4mf4wEki_@m-ew$b7StkzD~~`0vmFg3l{?u$Z+R-y#qpu%i18BrjU|da -z{aW!JIAb6rEjbe{2%kx-CI7vWUE~x^D>1}E+z_HE{W7s;;Yq4-UAclIfDH7OjOJ6O -zL*}YHWDUg$f?EA}nh5w!@~C$(C66?JbqYK5?~J&e?pRGC0>NdUt~zMH%Y=I;9r?+< -z8LVZ8Z!nbW@@=8Sm%Eg`xk}8b47ah;frVQv99sjaNhriR$A;WO+N_t$__;ora!AM) -z9G;a!Fwgd`N+C;0+I%UDy|(13@Q!;la|;{?p&?usxo|X`K*uz#x;+-x*9-+swxe&| -z+Nok;d*MA-U7!4%N1Jn%IU^Iy7$jL#$u7`AeJ6R^VwUW3O+bw&;7)n4f!ocI1)5+!@i0HX%dI;&c)Q)9?_$9caN8VWA+d -z4GT9yd{rc1vA!hBme&ZL7bR>_D#(N_+#1WUNQ=CvD?+j162+QbKp&Y#GY^LdI})8d -zR4NR_3Qk)5G~4IS+5tLrvU&dgs{T|XU7mufM3V2xwF<_iF@Av99NbfM -zE7A2##)=(0L5=I+Ms*E9)EW!z*U0_6tP-m7LDQ6+OCzUwUJH6E`9EUN7YlcSUn8lN -zJAKt&kY&xUu_2u%T|rCTp`4z4v1m6MLL<<{1N%@MIqA+8t)JUlK^_`I0U! -zG=T^J0}8Vx5@9cS1m(Jy{Lk81<|y_-_(oe;d`lTQhRrU>zr)If%`Py}qO#cqhu7dqbOvCeh6X-H~HWpFVF9BWx*xaOv&oaL5g?@ScIs8`KgDf-{>DQhP^y -z!QLS#Mf@yOv|RmMk+ECMZ<$KO5SioSwfAtC%7R&mDgAO0_IZRWnsff^kLDgtR -ziYcHHnVJc0ih=5EI8a&DW{Z!1Kr&U>rTlWY#>IlnTuY5-wcBp6j!a%wE>GZTZSd*F5CuP--^BM(&q!3@1wM*=jbQ4uwr7i;*74VzveUIv*-1@5P7{tfdmf2)Gi -z(CbBZs@%rCvj!#ZmY;E%wblTU0{#O7@jNZ>GEp(Dqi><&Ob&%`%6^E&N=8*^sEMcw -zo}9gR7+K<dlZ7dK1rR(Vag -z+jl_5EA`LaTl7=o-15sfNK9I6y9YzocGdsvR@320v$cW5%l=aiyJ#E^mfS{T6iTVg -zas*j=e5r8Qt+Y{}!Rj7Taf~1OZTM)@1ryED)EuwS8)CQG8ALGO!VPu}8-mTU?Jogq -z@^R=My3*x3OAX#+!?9vJ^TsU2+$4nIDBO3H;VK;pezjWfocE}rJi?EXP+1xxcNl9VPR1F6h -z^^lSCJez!v$xEBL)@^-+e2d?_$eh=F+oB!g$mVy86LD~O~5CAsRgvk&y>1EO%9^ipLS34`m!OiB_$ -z3B}djS(J-}nHh2kgsM^_2K50iIAV8`>24`lLwspU$a5wc_QE)N|Ip-NWmmyL(%#g- -zN}nNuLCm6HfsuIQ!SS1}0@VfbBPq>bZIqkT#sG|$x-%Fm5W4jgpslEqbiG8b514ia -zmhTN9eF#2na*M?T!8 -zJ}HH>Yq4+O82}R6l)Bdz+|8UVvetuBwgbvT1v~c7z^AzX5uwA$6 -zpp$kvqeGx<41iqWDdw0&E|uNJsCK6Ry))_EtU)DM#ha8b8tWWz@$ucu^Xc_`vfNH? -zKaP&gKeHz%CZ!)7>OW|On7YN*=p_6bYz_uO!B+qz&_@&#q_qdiTewcGs-H=v$xWVT -zAB=RK+4wjjeoi07;|7f&`W;2UP#i}dMQIdH7-nM3iUGdB@!G%)jadR)ieSQ5!EzPD -zE-B^fO9+ua{V>3MVpikOu^yMBtfQ#%0Sk{ON+k@=!V(^%$u*fP#&d2uv!z8BiydHR -zO}I9YlEIs%Lj>Vd+dOTaaOO>v&8Wu@#vS;37=}y#uMJhc4V4O(1HgwP;8`;UzY0qq -zU89M~1j+Q~{t`tS9A{5>{0)DL1F-ig^Dxo4L%4vF#3xB;T3FRuLv( -z&t2q|NpysKx})UFAIfRt=LCd*ZCCezNkU29jSmi`1+j8K4W<|G;>(jtsdHxZT5U>{n8D?06IeG0SS5K?Cr=W}9KX_)!9ov_94Vu= -z1>MD0%PTO}kZwIq*9)d4MlY7D?c(}7MO}f6{~xMep=@by@Yc$ObrDlEF=0sWEsJe| -z@i&#1}{I94JsL^tI11J~TeW%Sv@$}_yF;f^kE=h9~M;&I7 -zfcch_|_&aj-)h!ZyhQGif7&`6$@wH -z^rS(i1tF$8C&es&a<5*RMpefuQdEJWYI1EdnfZ{u0Fs5@cKaBiFlMOQ*{i0ZM7G_9 -z9B1xyt3b*L!xL}jvp<`=`Eq=V-m*Np{vpfdNlG2EPOn$%Wq!FC9n-$enF;40 -z#XQ13A@T8;X3&y)8FvAOI+z|)L}d9R4v}TRTfuy -z|CpM`GdqA_N3(QL)1w97)#;PswSXz%=2i;@rxG|39}0LT0rs%$VP=TRX$j7^ -zcbmyqeDnwr;~MfIsWJFUgYp$P9Dfl|@v8qlI1G5XOF9eih!@Z>rG(0UjdVM_4KI7O;)p<~&^BrjuO4iK82w&kmMvmGxh7QBsm7l6wW_4dUOgxOUXVjm{kJ0pqZ -zqYup|XuZLKXXihO2n)BvIoFJG9jnlDg-g{BiaK+@%hZ%7svo)`nIWic91)VNZRp=c -zjFhcip=;A$DRnlowiIFK87Fe3B3rgA74MRi6nf_%y*G%y3xi(pDH<#HJT`T>pzp=h -z;J#}F$#3$|K2UM>Qt>S__d|Y1!HTXU=5TLu^$H}XAUzz;Bh}ay;ydc^RC!R>4D&qK -zrs>BJImbuB5@+%I<5`nu<)u_HvG)Rb06uMFmP(AZiJxTLW5V&K -zA&B2`R*|kM#8~V_p1@c?Rb#BzA}LVsT8JKFsYWRKsR|)+w1jwb+RVA(e%tdVuI_W~ -z!v3WQ?uNGS2d+&kJW`EKcYZCnT?xLz41d+E~seU@TgR)$leYCu* -zyEm?#^F2vVE)@tsdxN4Yj|IXrm(J=B9DFO723?(o&~G^dT*z93+Qx$*$qFcKKm!_3 -zIO37c71S@TXGzJ>C00Vf;a!m2@94eCU#8M=cN9W_U6yW~NN%nwXx-k834=P#nhc -zbKX88@Z$=5@$XTapL1L!4B3C5BH8F-WF6`iRe6q(a*2MVjvl$#WY?MhKx)q!e#4V74 -zzRh(p4uOG&ju|^1 -zICK=yJ&R+)oIv?`O3TRe@fws`9zr583W|ALEmv1;F&NbBl2WXwX*tA8ZcQbojZl -z#u|xbjA<=Xhck=+xc1;!f@7(d96&Xk7^;Eu=&#WzSv_X$1@q$e1i0g|1-vZdNm)*B -zy01F9CblSq%v~b+!CUTQb?j)mG;0st_f8her`4ZxdyGeVPUGEb_9uk$$M=uh`8UI_ -z#9hsc(L&y$5cDefNP#PG0|^}ckLPb1HAX1>Vy5{QhakKZQZ -z`tc}aTjRvG4gR06BeBLg4hRUmy6*|QPQ2Nvk`^^?qXPnpGs#Cp87j}T2X*u41<#Ng -zg+!}CQ;pv8lB4y}2ugpXbH19qqQ`@hXNd6h;W;8dJf!Kwf^31`U8&ZPxqO*U7gnPY -zZx0gkc_}spE1Q$5kENqoIA#kgE_;EZN{{LLMc?JB-M^)k@fC -z4Q@}=Z@bC<^9^DWjeeYP3m&gfOi&8B;0oH13+7{neCZMeWs`3(bmAr_@4t=4_`etC -zKjZN?q}$9N^B9vJ8=>xuW3RU8nKMBXljij5QMp+(Lz6xL6i-Yb6TDyn&e${qkWTXN -z)Jm0ZXs8yq_w!S$8A`F4my2C05B&nieB~jXbV!;iLCo(sco(aSUmlk;u8Lvju>f9L -z@}fb8SZ?v;7pxQ661*W~9Efv1;V9wrRhh-XbC+4THYsm{vEzCE&pY3uA29Yrj2zC2 -zVjqQN#G=#}M{`-sBH|w`9yygx*zDKz%X)QxHeI7(1o%q0V*C-;`c;D;PYk-od+Y`O -zwY?9piM+VY?AsK>@1$bofBxsqzy9_5r%5yV$Du-VyMC!8WX5=X7I%JE5a8)Ez8Eow -z`i5G(SPp=|`w%d824s2&-~lHu>No5J|GvXZ$;S+LmPhK4oh`JytYN(qmql)9iW)Jvqz -zsH=c$Er6tgf*$3bSvAKYp(|7b(l2scsjCl%thf7Ttc;n+&grISxD(tdk1zDI_4VhQ -z);@iV6S`)43ES0u2e?AGH-30Pa}XG65(%^pOsyx#)R&Sb#Lux9w{5kANaBfkJ4_N%XzsIu43^stFIAkUdEr14 -zs2%2O6o}qqy`w)jSmlz66Wf-H&{>KA-ee%o9=Y4#BNv8||QBH`iERrQkF0o6?M?dUxH`Ah>rDlyx2yG1Yf9L{+t8O9Sy<4d^PGHM*r>V>juSH2gN1mB};LeO~F -z93{xSQAlzK2Z;k%pt@}goNJ9^GX8~zfM>|<8||cTG2@=j^R7W6Rh`;v*1d -ztJPGy!UI`tQ`O2PP8m*itA`09DD2=TRg;T-tBo~1lntC#1zKS4hYG_`t|zDX0kx!nB$rR0zD}e>qlAWL9bt0b$)7R>dmmbyf+7z -z)2qfb@rFy$m+r8$VZr5F*wgkGYTu*`N8_s~JKgz4Y!yOl+BWCMyE*m3Pp*R#5*=s5 -zFE=gvGTUM3qTM+GGpz?Yz+@nxQwkGyyJUv&GfqETWR(qs^ -z`jM!4Sy#lBXjYDEgtdhy4;vL+H1Bb3bZ_H4#@yvk=UnRduxWN%Yb}lEGH_<9 -zTn2ur?P)?=h|AfS;VD=C-T}In43=9z* -z2#X_hez2|MYCCQ+hDW^e6aL5OVPH!=s{=UuPmDo&eRsz>1(PQkwqnA?u!cM@(q)Np -zzVmgrLN^~8)$fUSjC6@55PL?m7xb<;HN7j^j%>9#Ek-Nc3`Pe=i{`B{?g0VFKUeEN -zC)@e`=hu_T`_&hSli-w*>Xs%^{DJWkf^zjYnoi6)Mt)`byBw!iKp#N4C?p?CZ#O)h -zl5aU0j&pXtWpXV{!i(D=@GRVI>qU(-1mq|3L;_3?8n3$G_Wcz9l!I!Re|2mIr|3@U -z1{xKf(c2&I;9zO19#49n$!*CmpxWHTXd(x)^2C+d@=DnfnlcbhPB^Gpbk@w!xPJBdPH#c*&G-!Rx>R -zZ~H?#uw=TUn(JM{y2qD~_YX7R12E%|W+L|g{o`0fj5tA#b&GZkv=JPEOA0e!mFmzTr6_rg@l^Z9U?;E(j(b0UpMz7Hs -z+{+hqo;L0>zrX=naiLqmzxfi}m-}kiibK`OUiB@@&Z8zY=qZqWIG3^7G)`I(2e}u` -zx?rcJoV+kH9GI{Lq%dz!6n4)-R9K^%Z_B5Jc-UWz1|r -zD_%Nq|0a{#&DksPGl|5VG4&qOi|7}`3d7*KOZBJXO77qWtsbF;jc4+C(70%Do!At) -zc6c9ZU&mJ}y;$J*BG1pGsF%bI>3e8zlOM^^mXeYuH0ZSA{$9jpl?0TElI7|oO>9E0 -zlQ;Iib{YGs$L{NVu)X<88Sy{)N}2qj>5NjG^zK{iHa4VFo>4}D2m+~*|FQtcSW74^ -zq@(wUE!Oi6HNjHSmloksbi@Q~b&Y86DA@21-9hvDk-Uu3uVUbtriu1+Uv-8Z_GozK -zrDESM%F%7i6$Bj3MMOdb}Htx0>bMq};K=(KKyA8>cws -z?Bs%S%Hsk`@(-zt$4yXEAtVLs7|axW%K&)jSOsi;*pL~8#_8#AZ;OKn-^uj1_gc0* -zXc?*rq&?+4vFAzAp&vPwZL&BqU^Fct7Xi^{WM}{@dAIW6S^cdmKR_p43;3fGo`W`} -z_L_U+0Nik>D1`k_omgkgiro1Mb<6ptRJ0S9)$K#kqR6uV!vcJIR-Pg%AOh4!euRQU -zwfe!oBLpJ{RFH0gNWw>D<-R9s-qz%fHuX;2&~yR;jXABpu{@GA07|517dMZ~KVLSA -ztTLL|`&~(JATpj{VQ=Sg@ykl#2i+;ht;WBEa2iQ5_AV|SJlc@-{%ke!+v6HcoTvR~J1noZM& -z{jfr61XybW6=t?-xdnz{?QgobAxeFi*9rM-7mGrK*}pGc)wCYG(%z?l!Wh5`#8W_> -zYkFxGr%z3qX9;@-9D7s-q0I^mm-jHhdruY0pgt!^7SWtN-|?bWZM9%5ErZK8&FiZx -zmHjz5j!PJt&FXPI>r9UGD!bHL(3PMb7>Db^D_!u=o-}s{2bHDagW*&-@6Xy*MJ2BVKyA8!@`P&2}^nke0q3?Pf-2(o(sXxLE -zaL5lRoqU8c=Soc_F2B18obanX!;X-y?T~3yPEN}c_NT?OZ1-?j_Z1jLo59yhg4xWL -zEFDR`NULtpd8cP(MsR3`6UDCHsrSiFS1oj$qjo0lbJmYxXjHZ{cbMXSH)q}EP7 -zkZG4coJB*I#=>2|DI_+5%vO2ab&9j -zEP;K2b~MvS_(129Ai;`|Ef)TFq8`JH`Hz_IkKcK^y87eWV^z?cIsNf@S@KSJqzJZL -zA*8Tx$VniE*e;fj(vX)-nYs;B%(nt-pf>-Ym2(+%-VTmQ9^Cpcqx@Zc;*P7io%;J3 -zJm49cz6v4b@9&E_Rp^ad+*<#z-VH=RPP~g<>h#sp5pKw(L}X`+|L~YUs=Hfj)SYT~ -zVX0NOw_h4ua$eJYaQfb&>To$v5V$(Cz4juu-uGm7x4;n@jl}n=e=%fif7~9Y3tDYW -zdYL_Pko>vO+U&v6zr#~ugZwL>oCu_Il5&BJhb7+(JHiU+k1IBMlOke;`|#%ohEQiS -zXYZ6oZW;$G;G|sKEOC1Kqe;Jsq=}B*WX5+is=Ht|gY`Y%O9{GU!Fgr2LC$?D-5?n@ -zzjjR=Sb?s9@x+$OFkph8o`K+g3Ytj4p_@%MBlQ!`UE3xsq@u%M6j!*FR@b<>NGSx# -zC=N=OQSr}gr|Tf6jFpzk1JzLQWG@W`{X;n(ztpYoR0?0NOXsu!49jUd4|!<)3CM-E -zwWWY?NGgLDWl=K061^1(IY%?!-DGq&K4mK$wqR1PmpA!+c86@X0TJ$PF82Jm+<^~% -z#)KudCr$bZMr%`&YzRP$LZMC~@Vz5Ny=sHe>30VIDN^FtL5Z$Xm5QVc~-D&=j -zoZDINr`%9I -zk&eyN18M1ehTH%Y6Kpe#tjl3zGugFFY1xDBytLRT)UYp56^n4wG|`d9GgQ6&;$^;7 -zdh;OYg%P7?5(Hz^;{ReQecB<~VY`chb@DDo3j3O!!^$U3?oOvQk~kncST-4`RCj{g -zH>Q}ocAvc)g9BO>x0+r`9yn1~Tm=IO^UI2#6rqSa0c-zB%X5m?A!c%B_8431imt8Ic4vpUjQ>YCc4#)sG7(1Lc`ia -z{$rV8^euLIw~Hsrh^l(0I(;5M(K;d~EU{3rOdQse(^rHQGFrsZDH;)7VT=d7%+qwe -zm|ot^q0?@@PSLv$a)ZU43O2|Rs4*7p2#V4)3m9k|zgM%T20_I3af8%LruU)hBsO}n -zUEI%`2k6VTB6B-z{x}#J^$oNz2t;VgENIp(ie$Ksj2!_AGjgC^YaGWca+L89?S8iB -zinpz~-+U3T?D*>!dZLk3e@a+N{AGTxD_hwzzt0M`V0=C_Y=x*YrRd9unDZ6qiy&Ec -zz2fo;W>wy+q;8U0VoN$8j0yW6y--t^TlOhMVIm@8P$aeUI3j6&L&i@XHn|*>I?;iN -zh9?Wr=ooFv@wz|NR4Zhglk*(kqv?;9|CaC^V$q=q8GMWDaB%XiF1Qo)Dw0(p{~JF14A5BCfAu4(_=Kyd{B8{=X|%Sn!NM5Lns0(t-ymx^g`CB{kCtJScD*<<|nYTLaY>z{IA(6n(>eJM6Uf -z1VLYX$3WDj5k9^=pI*;Fa!qbOj*iVgYtHN7Q2#*-C`7lho{Ubyzrn+aX<>GEe+8@R -z%tfJjCx4_opLW8rcRXCKz6Ong|1o-{ehC}at6ITF2(BUWv5;qA1?XBi(@?|5Q`lX^ -z?w#IfK}B`s-d=wqaN!+r(98UYmVCnIJgZ)d>AK2gC*f(XreoPIO?5|s@vi@pXo>Nq -z_6taAl;iDe&lh#SteJI8lGneMW+Yu<>yI -zxeIm{mIkPlaX-5eprJAtNgOIZX5aC@5vNxER{FB!eaZ7Qmyq-gJ_~L)K9J`{h-=Sw -z7U?Ft{{Q47UA`e;?wCcozu1vHr!}Y-pOmiAwF1(!U!rZ32%>qt{NA8N_!Rc2dvuLz -zAoJ?Y=MQg019O6Lo4>Cy0BYuWIS4IEF{V2)5pxvr+TfpX$K0WbZ^6X15o`6(L>Pod -zN0>eMB-&y-F$7Oi?RVN69O2L|ha@LLRiozf5IaKbyh;j|OXpkq_^ZFlixw|&Dj%Q$ -zpjLKxeck>m1q4FB>_}f3;|tzlx0Z~!ULTs-%^b6T?=Ugx_UxUu9(&ECnK1LHU+V0Y -zN}cWfN&;omN#<{4o4>OmzJ0vstcfOS|5?I%pxb-ckvL8J#k`%((3H!``5_7^y2`^po4fa&VkRthgpvfTpr9g#Eh7psYyrT8)J;kH( -z8&eI?@tQ&ck0lwUnfzX<=N>_`6t%ScV|TLu#%uGb<56o3cV3(}p(iwIa-kA!5Q}*` -z>4cch+l8m6D6@_5J}oFF(#a4@N9zS*5ud}!(8BYp1cI6mBRnFS2FY)l4Ag}2u8k{P -zijvNzJBF}*zN=9-EMuA7Y3q~I@t)I*WHx>|o&E3Q0(1X9pUplCMTjZK$V7j5#C+45 -z8eJXk7au>|nT{8L#4KtN5$zu~PXa_WXT*+=QT{mB0A_*Ckj$Xk*549pb+rcPD{8oS -zu*8&~)x&ot7@N_^`L{mz@X5P}rLak$yMZfvyr7BY%viQmqTOWQB+oh5**6WO{Ad_HdV6iyJ!tyUwqdSLikDUf9j}@)G4u;Zx#fCpAq` -z&!B=9#5xLV>U_mho%j}rLA7zjA$2Q2A@Xh;jzG}@b;!fr6o=VAzh$mnlNFsA`U+9X -zKnAmQr->*C2d*>gs>K7CS*$8iG@4Pp`lU044wCGNj5a%eBn9kuA4$dT;tcH(#sC6l -zU`r~_=$hs#^>pE-iDN+PK1$n?c`Ve}AUtJR*_gM4JJ(>c4gOb*PtgoSD4O}b2q-fs -z#IoSFnqh~3!3-noiA$_q!7Ahrn;|j_)S=fC4UKaA56dH|gh|Ybo)H7GLq=B*1N>N3 -zoay#4;E}*BNo&aV(8oZ~*1IIMaU#Q;u#nLuI^&gcii*MUU}bC)FmldtXKnQ>ewdt) -z3d9RTTEUL0AY5}gL_(M?8SD>0lWupKDL{VTU}}c?y(uuwodYSBDDR}aU -zxwxynKPZE%2_uhWOguHxIL -z&k*0r2stcR!P4yq|AgW|oUFYPG6_EedaHFa?fl;J?fifHEFSCsc((AwfjSZA!7gCm -zdy;V4cA*mxD#hqJo?829j+QKsgGZx}oZ(h=MQr!mqK21O^X+tTw}F&W)Yw|r-)fS? -zbGemSuHLRqTK7*tlAAQy75zCqD2Mh9qO}YyvhATm*7V=nV`673L$t^qVX>7tQs5hB -z-I0i00zS{4E>-l2ztYmkppu}8rIPS~jwYm}Fv0haPNXnlgH}>#9QLr9-Ka10u~FjM -zmkLfC`*OsDuQtn~4rvC$>JKxtZTR%w?MUSohs|vhB`* -z@>J2&4kS)j4+JcUdMlkIz%v8c`rGU4eKOI^E^dI5}+Uo7eZSRJNb_<1_!=(cHgZ4!35ZWVaiOp -zchnF`M_rF|1QIx1N>oA}@h(Kz8VZC}(U&N9wrUIq1U;4BM`0(adNM<4jiZ9y;~iAR -zo!D>nway3M0O^`HcF^=f^;b|$#k^JSYwY#woNwn=g*(v;Hu`oYC_zYH+X|~pZW%0?w;(Qq{#Q+W_y4PZKk3x>!Tq5b`C?r -zgEJm|WfR(kHXYsmM>;$Bj=pf%3-QyT#81|-JP)syT|prp!JJ`poz!HT=CvNuUQLeR -zq>oi&tuP7v5FQhxjLdsy@L8fo1|E8TEYg%^vv0C*WU|`!I_`-efWi$J?K1MIoC3zj -zTO;X(mBkm2#oeS&jD5rF*z9HyZiRSJUM@-MV?6ik8Ay_ -z{mL!`fY~I+?%a$8fFztye7BL#+MLbN;$ZnjWwdRiR}F`7RLb{4h)*~ylZ&d*6MAkV -zVMlq+?34E7y2CT;#W)L|RU&naOji(q{R(hW@msJ@IK-_O(IgH&f=+}PLZFjpx_?6q -z;4t0M{8ZOU6wLV8#W`s~Q*c9FrkR1ep?WeC9;=Xa -z>k;wc2oY3vi+>W$8~5`BSgwIjpc1DiYWCOYSWTd@jgsJ*7j%=*FdXT>nr`P`R_pI_ -zMP-e0I%=6|3!rGbawpAd{T|@>wQ;;&@@^a-&GXn%wu?g(W*qi1I2>2KR{=V5=H3ZS -ztqv#T5d$2TXP2Ps*x?4%g;$Sv^K}D^1o(qAPO>=#Xd8d59@ZmFBgf7*9J*7+n93Oo -z!aUzDLmgg(drfLM2uFTi(wn!W8a`;pe7#e}iJS#4{42O}`F0Sf>?F2at?#GkBDS5c -zF?)qjQ()!!TTOM<-gR#;Yp-@I-xC&WZ^o_m`#tYqc-YL9ul3$ZkQ?AB>g3XwvJy{m -zu1Qyy{DD?VuU%e;*1CF!W$>E#3V~{WjEqP@&|(QWKYd(ePEB6f5?{Swkd3iM`4|fW -zv6xe_;;fH=uR6xcP-BEpN=E((|A>2hu?x!*WFzr$uvva*vu>01R!m}OV;(-?hL@s- -z`h!y@mGw!g@ON!hG+TPAYOR8+0Qb%3FM9I$8kz&ynpgTS>8ETeqG=$jq}gdGYJdoBD!w!5Nffmt -z!iEBpR5U=`EiY(jG&vA%$N6^dD_%kW1*cZECuop|u7&@BhmP`8;ig>Lylk<4>)A(m -zP2?@qPTxFs?W -zSJ|rImyPY7u4uM32LV`@7V;D0(80%wE{bE*LM~tNh#zY(D~f{0r`4ZiRNa&qK82RY -z@ezY3o|l~?d>Fk=9%jMrp>fCRyBgLbx`+ooQk9`@L*3gI`vB`iYjg0A!+#ufJ$w#` -zk>P8i*HS}8}-sn%E2Gn1{|i!Z(ZtSFu9M@*$kb< -zCuiM9q@~WqcYA3v)7K$UUn6eaLvhB9M@t2TU5(KBBkE`i1uPgn%7f97QzTGz -ze7!w0j16LYzb>c=-J5zPM2gsYzaaYv!` -zk))|$1q!~!p`nmPQ+^L?g^Xke4fU&zR0n}vm|}icH^*)IKIFTuci7HOUthMR2F$lh -znxf`pE{UIu#cD8k?cZniT}W}pEo97HF+mrl%Tg>O1cm~$0>pd -zmHVw#xhrj}qWNFho+j$im6cC8v!r)v&Aig8DJO%Nb~5X7aNc}21%NIQE%pXLbUO+F -z9h>1z72WAgJtz+E(4087*Nw{&4+S*1Z_Hgowip96Z+>1a=aT+br=Ok5bZr8MzT*$W -z!R{^TV%FWvRTxhc%S)Jf#U%S3M2XA`)oaLchOeS(?x -zxs5W)*B^AmFNV>OL#7_OJsxJBv;uC5?THI5^Mpsfm#sIrLd4Kz2{PwKAg2zWsL -zfa<%*Kg7SwU2#n6tvmMo*$39KTLE?#xiIgcFD0wYqtQ%Oo95HQe0jgRn&ZhKqyXE- -zQY3TWLi6plHsI$F3c#j+y4HHf^GUXHiAJMl>J=98SXwoyd*@lKGIGB)PM8OON31M9 -zJ(6~SV8_mqa7$%`0hv!5OnhAew?57+{JLl+=AuOvqA0&W?^_OMRtaMNZ8Pm03`ZnC -zO#k*Yy<1#i_%KxgC<03aC=rzKz-EERkeI<&eZG|wk0tQuEj#DDl;ZizI-0eIIy-Vv -z#VkG$|A?$a=yt~E?{Lg<{v{$VH|oG|r^f*7g|-f#Ogq?2)s^vO{wX_Dehmlr{$aXC -zVfMEfSpF|_I69OE0Ph>eN75eur}#l!u|5$}>#UzGKyr|CLMqcE9_N{N5RMa%>)BJ{ -zSl68BhcSDiT2m({$sp}$h*}h2U^t%6&(oNmR^5o^34xtH1Wr>v|N3WZMN3`z02@^p -zLzh>K?T0ihZB?KpJz1=()h(T6nx -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 -zfUI^t|Z(p -z9ltXfmGr`@P5iS8C3=DCW6^qzEQGjth`{rn>@D>NqTS?c1%MF%X)?Q^z&WBn&L2J -z-I8<4W@DC7Kk=;N-sodc)- -zgGWx#y+!XI=HSH#=B<7GZ5MMDOFbNeSFi_A^Y)z!#4NO8$oKK|Dc9u;G~(1#=C^1A -zb48z^j8LR_xAE=-IfJstvUQ&&yIO|Nj7=Tgh**XsgboOu!8ej`MZn(aj%_j>i{{uW -zPb9&oZwtHSyc~{{YV}U?MQTP5=v*elREmqbFt|mt}Sfh2P6WCJrHbDfa+E1nMG?3#54Xz)pNnjxiTQQcYOU=W7! -zrw~X}YL4@R|Jbz5DWLB8Pl-JWg~|v3HEa0SYSRCXsbv%YU?+xZp;E4p*PX2~O>QQ6 -zDxIJ~hOl8fRfr)EW9Xx}Cf0M9-Mo|}S(QC?3m{9`Q7Hhl-U2K0&zt%3_1zt1D3d3t -zRj--l3ep#ruws@g`tE{cNmabIWla)Km7q(lbuMFr0_YMKj$O_4aC44QWe&XbUE}FF -zOt6_7)pGJBy`W1}fr>uS!PV>K)#t~ht0>uwFE8WnAkyGCc3qm7LZsqW%NYNQ)pS3( -z)vEk7-ONp`c=Gt$Pbg5ixIgC`TnB&9fkf8T?MrssZ>&cdj|MDfifo(zFQPoM5`iWI -z*ZqI~=gq(V_4=ntGr}~{L%x`TB`2Hj5Hj754%GkJ7Ukk`U#O)0j58mU+#g{}d5sH> -zPa+!M%a5R>x_+}ldvs{2)T9)biGebU_&{J$R3@VWCI=4Sr9u>u%4}&DMF5G!kpq6q -zqFSx4q9=9q>XY_rnPV0vw%-aU_k##fpSGJ4J`v5@u2yDkg&)})!`$yDg -zpFA!pV^Pdd{;P|$vv;b?kA>1SI_-Q_hH>TC#{T?Uj|ag{@?Ix;Nm=+It<-drz87^Fzjq<~cA`=^!%dHyXgqxleN$BZuyGOz73f1H -zV2NvZnoBX|2Ma+JhUT~&EHsfIFK+|S(C*W=n>ICL`5*U}sM9RkAZE{J2cEvx&|!{( -z+jI4l6FZI@ZqJb3gNf~dmF(M@mFDuDY|nemviz6;q!W-D(49X3^*+WdImD;j|twvozbjbZR4o&*25|ViO-v#Su3uk@{j3`SpA~U(PT<1`ltiMmbX7;JbZ~;~5nRTq?hykdmlB -zgWk7yqJC2}@&k^)_J?`%8lCc5hvU6+buLQ3`o$ju*S7kL$a>^$oqu-97KDe%ZBUFl -zT>Ob&Xcr#M;=Rw$pfU+W#A%rZ@c5!s8NHWNj7QSMT&pHV5Zwe#o$887$; -z{sDA@Xp|)kxgX(T^V00>Uw!%KYW?Q~94P4P$?^$<_}G(9@fP%i+24WW0G-NJ^{58Ko(`5NR;(w&(kV4CF`V(gF*1A -z3E#9OByb)4h|^_$AAq5%q&>n-KA3UYPj-7U{uA%snY!&Q;2mfCj=>DJLM?g1Jmhxr -zHc4X7-=%H`6b#9s>;{Ww>g^WSlYed2%;{pkP4f`b-5VHf97#>vM!o|bF}xxXf2a5a -zwsvJ!b+GFgdVgq8SJ -z`^6E`Ygd+%1%*a8K@c=Zn!!7*`WN`9Dv#gl*VxA6bRT{u;c+=_a;Qf_O9C9vUlkHs#$4`WIm<_Oc(C2FJVMx> -zDFEiXflxIG$2Zx$!E|cshOT0ya)~Gs5(D_;G8`|YF-;wj>ab0lYXuA;3WCt!Vm)1K -zH`r5jsRBEN#*d$_DL^2>tTZ(>9?O5}IIGE!&P6JTotLU7RaSUEU1DBXPyvnSk;b?n -z{ncN$L*j`k{3md|FJA0L^Xq*3dA@nP+qz4R4OGI*P$<-DdrO4czi;XM$wF|XS_>NN -zl7^ss5Q`-%Kp$n~hD?SUS%%$phoj_V9_42#T#AksggEVPFQ`4WH=~b0)D0_a#+s+S -zuYY)ln=3!&N9jJkeU~bH+Zr+n2aAU$e;qXl>pmI*eB5JNH}6#Zo$&lHGrR$%GBoev -zBZhZ_5A`X;&QLca82~6VxnMoE(mK!A7a!iRqvi!?=t#%~ax-@Jp=4Mm7Nv==$km7I -zFt}XftGPBYK7c5!GK&Gg7#qzkj6&guNvxT`%Flxo8_z}{n$mo<5Kk02kCF|O;SsYH -z?yk3m7fMO_B>fR!s^BeSD%{X)(7x_X8ePH5eH?x|o$6L0WPFowth;ofJo9F{{4$^1 -zvEK7DD&^H*h)UeZK#Qk99~pQMb#80$O8*GEQv@x#k4OZTM;6g3EOfg?OS+fyA{>GYNfj -z*NRf0v_Sbf|BQy4_y6?csa|ZE9K06(n!;twS4^)!V5Dm$*UJsXs13*Igos>rT*N3nDcZkV@oV}VK -ze!jiiP-roNt66hCFe6^%t>JA(hiXvZ3ev0j^nNk}xd9srF>#b9_tz%qMs+zpM2M-- -zPBpwtd3i@eC|`K`6?6clw-eT_DU}B^U;^yPpW5I)s7@e1ecX;$G+{na_0#n3aV~W> -zqY)Z}ASl+;7jbmj%-Z$Cs6qNblvM@i$TTdR1`>QatqMaQ6utdjQLn$-t|8FspNas+4HtHlY7GeEz<|n3T&0?e -z6RZi_Y7Ur)9g^16Y3QudZ`$Um!Q}5yqtMz3tb3}__00`hTl>o!KMILt_jDu)qZ<^b -zu?$4B8T3Cbad4wfSUJ-a(sLbjg|UF%)7u1@DmuMDf^KR0uHrbSP#e-UZHHFKNAA?G -z@|CS*7}(booG9<2#=Z&#&d4r+tho88riFinMcOrL@s4M5o? -z_nN&zm!DL?UQuS|St@17Q{Z$yc_^l$1*A-LhDgnvharKatQ%Q0KLT%FlLV+6d#;gmOZ -zO_gL(zE^o`wN#F*q!j4=t-F6K*?EZZPkfBe1(f=OPYtSg&l>4A1k?Oh!H0umX{0oB -z+B#FwEOQ7y!Un-*FbOeP-k}-l^2-O7cBwmTq=h(9ZZ;}#C9bEAS6*!~sYJ7j{sB2{ -z{+Qk^uBKZsXPZBv7*QqLtM%*km(An}Xe*aK7fkkqusZ2>p30V$1s+9%nU-BLj$xPT -z_b3HGUB{V3Gz`Lu>WYpPDnIG$=~6&$w+GLqd_X>+`=T5Y)#*+LRTno))V}Jfzqn8D -z=#|r;cd@)hJNOmr?ztg1p|O7UI3{^RYk;koL?X7dEs&5 -zywW1&v->W<{E4*yucQ_LRm8d8@MGv#4^rKFeNMX1n!#U`mkegZw3=|tA~I{BtL9s| -zXxP9l%rRlpX3Ku{5^9+I+(Ay;tM6J0Wx^ouDTi9Xn9`oHYpr@>%+~kTnmKWpFd^D| -z4Q|+s7wOb#GOBz&?00kcLLnDAICxfMqG?NU*L+;=r;Ky~rd1&Rrt@PN}1pq`B -z^Qr@Q#lFJ)eZ-Ab^F0-K_=WBxHw@5Rhom#$Rp@Fm1`b7Wx$?N(l3)9*JxJV#*_K9BrsQlmg -z6~NQOcQu2Hvrp9DsXs*3v-*_lV>qNfgS~JS -z5X{l -zho!O(lj3){Onj#FC9Uz&`5b66>D^7lNCp(Q%gz-qTqidOVP<9AJviKSMM#p0k%{{b -z`1cOnTYXkPPbGd=UICZoyydu|gaq;Ua5qKuSHVH32TMo`@XiEmovhnVV&s=?VF=^G -zezP<2;~yF@>X4O4mor|G?JM@@!i!(8)S|dY92;rEYJ6ES2n~@`hZluREb1Bx*NdRr -zhQOw^K@2;>@9LNy_@V*Zmo64jsZJ>~k+;YG?TLJf&Tr-Eu;v~Mp5!?Fqgm!LcOd+I2WehfDS0AeZ+xR!K`##so8e4 -zK{r6)2ggVpNE1g^c+b}xefLmVB;<*FJ}9)#SVVw;MI&FJGd4*YHM~gpZy6uN_vkWjT9pxn>vQH!t;ce -zh}-44zp!cefwkZ|;k8rw{$ctayCqr9iph -zrFbQzQj54du@brkCRlXb>E+j3#q~O9{KmRoMF9UH1gXlz)8aVw8@@~MHjwMU$6-ne -zWRPT!+@Usb9)d5SIgn}&BFo?Fmf#IOx>(OSi- -z=b*$%pZ82N%Ro@1n}9eM?>lQ4@Wi=@obpsETj_QZZ{=>wjq9E%__Rw1=8imhM)zsQ -zGafc-UM}ZevP=uVrAm2}GuE0<`4@sO@wF;h;H2aDE2b)l^iaG*Z|P%;Nrpi_7N3~+ -zv4>e7>l=x>g(}RkbSYX~Mv9vT1%3!mc(OWup}O#vDyuftiHJeIkjYI$Ix11CatM`e -zbW3il41Y~O`u3jobC_5#*DpGpVf~;qODNu!A`9Gu8tTyZljYDUwHt0E^-_v){3M%W -zM2h{Wdsu>72E{Zrb(TN?H@t3|U=#H>E+vdWs*C~Q4haDtTHuR4K*3GLPrWCz_Q5i1 -zzt%8o`5W(`r!2#bd&lbsm7W4JbA&vgY5<5Z5qA3cZSq$BZv13BXE@uj$Z0vg(-^*y -z(1$UUH%p)|ml|S=LUx3!h`Zr%EeSmw(n+*71QJ+rHEJ8%)0wUF?PuyK{8@{xk|p<8 -zsS%4^UF3i3(s7v*AA>9KYG-Hf=@(VMeGd52*1LG0Zl5vm#ZEE7PUkzu9(a3pDUBVm -zC2`=(eJkHXuu^c2&OMZ}557G1fF8Yrw9+D)f-8%GQdk~V<0{V$Y~)r%zDb^ -z8snrM*Yjqz28#^qba0P;g_tWU|E?K^jK#_+25_FD`e%ip2BZg2V58ClDyNrUzgud6 -zg5C{Ph8R{}V12sPO0- -z|2tuN}w|7ikiQyE@LotB|OA`UH^WkU~^ -ztX;t&dRMpnXn@9LU={d5mufS&$f37x!ESw+{y85gWGTAW7z!si!%h#2%)QLk7~^8w -zD3dpHx8W9u?~t3oh3-R5mA3{ChFjD5M%Id${fI)awsTG~1goiLw_HYntaB^b@$}s> -zREEo_iJ(+m9r7JPg)?0>SE+QJdVvR*L}Dj?&U40h_)HQGa}QnMPDfC%h@`8Ob`UYH -zw28VnFWxB6PI!P7sp9IhhbK?E+ks!Lk3Be|vW-Nd-6BNNt8mp)T#1c_pcA4RUy-S< -z_chY+Dm&gxdrK!3`N=GtqtN_}*>^l!NpxUtEc*?1uijEk5cXH0Nf`^T=itGkFVZ* -zMmwYhPW*`)*y&`k)tP+STQN!jE5)c{5Wz-4AXe4`6=8#%n%kS!BwA?(PSGAG7$x+3 -zWGc+<^#QLtsYo8f7UCfpSL;2QcTLSsbrY_|Hc{srh^OqH1>HtQNAqv!Brw}HU=C2H -zh&TED?t1}%yzq5R860v5na}s-OjT*1-!rDiJxssAWRH!`3P<-EQg&@%n}dJ65HF-f -zw_VPm&>_!NT{rb|-0Cd*<_z3dT>KUO%flg~7j235;l{LB@f^a9>k;U`smPGV3olKB&p6{i!g7r2*0;g{1!F<$C_VkKipa7nJ+#FIv!@ -zrlq3-GuBqWz{j>IqBL7IUP>ynl^f0HDG|D$>X#))TwVZM{1alCmkmurUp_Rxc=*^X -zKdMIg$@+}gG10c$P~+iYp4eH(92NL)WqqA)9_M7$dO^yv{}qgBiT7@>RtEe9n;vw; -z>BeGq+I(Iw*!^mz2A~uJ7hsZql3ilQ`%P&csK -z?rBG0(?Lsg*G$ovNh%?!%-7)~X)kh*ZHt^)b3i>QEucqa{rueID& -z8`;S?lS9YXyTPs>z@0KZC|WErL2{N%OplTn3S>C>?&Ip0$0b{aumMI^tBY49mg=fX -z;9l10=|OJdU|DgeqiMXFs|C$wGY>FaPWtJIm{$}&dfYjS@1$qWbg={hWFmH)$->BV -zd9fsr7`?dszGVU&{SQY6E0p6j3-xa@{DI$Wx+I!E$8}NA*jes>k8)srf3brdUfOe4 -zG!H62GPJoyaAaanz7McezH<5{fW0$P_eiJUTV~XQ@HV|!-LZ5HtTAsLd;n@az*PJb -zO*Q32TVL00b$PVZUFAJVTVTjW5I9KA1Azmm`YboWA5yYjU4>`#g6b;@kb{`t6~MQO -zLZrlcsBiJp%%Ld-?n$04#gr~Xl*$|7a1<1{Cs_rq3GmTJ$E!<5tI*_4x8ACdBj~^! -zmgeuxF}u*Fv=@8k%d?ZQe#S;2W)wSy4S;-NdUb^!Qk&Iv50+8r1_BP8K8a-aK*YIC -zOlyg_n#-o|T4C{Xm(b~2Ty -zBS{Gs1>s>_t6k$mm3?Xxgha4Ub!R5fLqe>Yk#)*hzA{ELwiM8Ld0wYjGlWA;|Yn8~olu5k@? -zf-j&%UZTjJMe%}md$$_Iw_*KEP^j=m=j13$IYJWrPZZ_9Mvrek!V?%PHOI4U#tq&F -zVM|axh+D;rrTA2o!xvFRzK+LS!_J&>8B-K!NZX}GdeqdgklA<9Sq+ae0OjDE=q^R9*!&@5QVIuRk86 -zi>YK^vjj5K9eqVWhb)?Z)0||S{J@xNhM~)hd9XMm4FvB{;Q-`t -zeE*2PzM3l7hjS@|qQqgP>&ff>UDxvyeZO>J@chO;@QEAwAkek$&{>hVD8!pJ_E!%N -z@J~T`7cg$|W%Ju~!y(lcmnnSDSYap;Ele7Av!*jeXTYxnUJ5$PGZl)XV{}=Dm8SMu -z$;X^Mj+&F?N-cnuT+u|3Fc|EGJ0c(x(D^)g$%^RT*hO>FnqI_}u)VPIzkgJz1Yh*^ -zgiylByj+XyXQ~IUjVpd(mxRxD8sy3BX1!Xj1R6Gn%^wG&gU$C1rm?er4ULKc%TBKz -z*V4Xt@(ngm{&DjD+h~mcdtv?qggE{N6zu#3|A?UO#ddLz*qL%Zl#SBhjL@L|9?j{u -zDEFL@Dq=nN1nSQViWX4b&%eO`5){HTz-&onDJ;6=x>@lud?m0Yv+)dO9qk0Qd+^Ba -z@+a#OxRoN1%{Xtyfi~2%3`yWx+71`asKQ9EFhF86D(NY^9k1!h;z$smkSGw1N&Xc8 -z|NAppM};TFS8A@xHaWnCS7#z5Gg;`i1~1w6L>PqyDJ -zkDF@A@9Ff43*0H*pGxI6M#k2R_{5!TENjD1$cq?8X4LSFDGw`wW=&)g3HvwA<;JW%Qq=8%JrS5!A -z09dePt!_pK5|zOMbT8janw#a?*PyQ|>#ztaCUxkuivB$e{|3sjv{i(&;sZ(9Nf_8@vjRIQI|HrX)QM -zU&P{T_cKIp`lP_Uxb2GFzT6=g?rL)kzoPFW?o7Wn$GAiV&4)$Q`KC{4i#qY!uhH?H -z{~u&D(OFbdNabM$`0dOv1DbdvZiyK?2cjt#MXKrCWbA}jT)PC$-ckaIEv&RR(B+=UnhS`6DIc`Msv1jalB -zmBMrnRF^*(Jzmm;@#NwI4$Bva4(IC&6mTL*d%@HMkA$yuJT{aZ>NLKf(M>T70eMpf -z{R4=bV##iHM6Jd;N6W|i`Fb&H?iQGnxtVOohxgNO@(w#uc|r9Dzs-*?BLv$fPD|PA -z8{NGjPFn+c0;F`Mt)T}&R3hV+vQ|*aCDGIlVBG0>_i-g%@9-5gyEs;9*`6BH03`yX -z!6E=gbS{6Us}u?VrIYE>cc6?U!G`Sk -zhOULh=;3lnax46(n_NV!R)VI~XG5=KE*6G2hZopftQTJptr&Jvo(*{|H8g}+5K60T -z8HVI4ESZ9Tu-mH&I_MI90hBzOuBZ1-pL3YSlT7n?>_yMQBy=q3v7+GtriH_udM#yq -zIctqHgyrN -zU2q)XiEwYtQTIOjsk9}Q#(17m1)|{2Qic7P8=a5nWVRVa@}V3*o%b0&Sn&=z={Q&F -zc+^N01_RU)_P5YY;APzD^$`RIlbsY1KlgBYJUOj^VbA%TOEi$3i3dZW -z1u)a_=hR!{Xafwz=-PPiy7<`LGsm<;H2Rd-8heEE?X!Lu%ZwjkrA)2~STE9}hybl@ -zyl;CthV(jtsKry!A$ZF}fVEfJss_!Elvqh23I~O&1ydk5!iv0PX$XiX0Fe5my1*G# -zy)ir%vpcOO-yn?Sh(ca;a -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 -zH$~gH!iA_ULB -zOge4V;H~#XJiAod368C9V<)tZ#i{rQb522s5cQIH>)poAIZ>CmzUFMmljTGM@jllD -znZ?V!YpCJYpFpScj&fn;7HuVlwexYj?ww;XW8L;!hvzuqK2Ryxsd(k^jAqSUxLG20 -zrC)Bl`Fjw};sw%KD(NhlXLT!aXIQ8R)aFmRxV5Lc*q!g$<*t9nT*dhRd(hmIOuvK> -zmOZ<50f4-z7QP-n -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 -z1aq?aI(+12O&n0|N+~5+x -z0Qb5}-}sW!Y^4CfqduEF7(0r!_SYgBCdG4vOMpmncOj5JT2Os(Ea5MoAaz8kpl*Y7 -z+-!SjWd9TmwHWLEvTUvRaV5$R3Ndiab8TQ?Yt)T*`8fRHZhYMF67nNU3*!K&+CKlN -z9U^bQ4w1jD?yfKvXfZxSZLCcjB!iy9^{0I7IqM@M*-GAYK+mERwa(uBS8@^RoQ4-J -zm^1+sIX?eCsI^8*fr`G6`0Y$zNLTrJi85r7UQ4SrPk$Yfg8+wZ?dm0YKR!i|LE4>q -zY`}X6q(VjZq)U-qu^5s27L9kV)}4QuSv7p8%Sz|u#|8`_pW^gB -z4Pc3e@Slnnu={IR$6&V>htaJZqHV%QMj6Wpa;DkidOcsxzQ2Sb -zU_QOy7?)j~PeAi*o%~1zOY6Bzf*u`j=36vrkbhy59C!u#Gm1GAG+-g>i}#3^G8O5g -zUoYe;n9u4UnJ%OW{uo -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 -z@Dz9RYa=_l=G*P+>z#ZfvLD)ygDC -zUIdH;=E(wh0}|40RYe=_@WrDB>s&y6Xmr3kkxH~^7;Dmk-mp^*7QfJ5KCS=Y-}{sD -z4H$&O$)viqTCFUiF2&$^2fAS+l~b;X;4F=U&Mb@(n5CpCu?L@rE-fD&^}WGGI0 -z&23+z#T~+*ij)>!f^=1EfyC_Ti?j9V!+hh>UTUw4rqaF?T!OT^k6~LwaQZ>n(}(`< -z+SBbjh>)ec$PsAf&7FOwH;lrL?II-la3tuGL?EFK0!5$`ja#n7dr-7}#vmcoS=n<_ -za|11*`pg%L<#s#!927m6Xrg|vTz&yHYeakOTM2-K{KoCDS(z1;Ie5Z!*;FwhG^u%O-H!hB$!tCw_W0UT_ -z{z~$-iBIx(GG6y+vW@<|qu^CIi6Vuk{3Mj^5{C!*o8$0kmO6AA%gCsKM*vl3#IOrg -zhvRd^0r6h=gZ!-pVk2sgr(m*f0H16IR|s~cKORw%saUFZK-mE+8Yv1Nu%$fUORpiO -zI@~{x&V=9Hf87>%ZG*pHW48TkT)=32%tmA7yDz|a$A4~6&6r|5lR$X5wBB^B{9T1j -zRh*YDi?vZlye=_$kYu(5`Fc4jm|YPpT(R}+&-s=CTS7*J&{m_=y}<@U+A&o-ANL@aqeAQlhfL#60+m)kk@}R; -zbSk45``gP614Ap<8$#k#P9N@;L&|zmKR$#`+89t7F{y5<#r_bJMS@~@5qS -zNNb|Ag>1$n#2_Y-?B~xP(%Qxl;g3zQ3Fh+c`VqnJ2Ct6)Q2Ml9enNo2ysgD2fipYIGh -zjN0k<1pvS(RJk7)5LSzOU&Lde3@>fbYqFqKF(ZM*ZRBE_uOadNWH#K|MXGC3JKY&*H?Ery?b9Bo(sW1Im#pj4eH8#r8e -z8M`x?CzTrZ3g6WaPl}>XCffzpcwRJIg*-E?vg6xFEFDTj4BLtTKxvlAkUnsv$Nb{& -zXe+X5LUcOGPq3j$9393bA`PzliFXRW8l-E7Vk1o=k&y>zy1N6kboF -znlal3HKuX^_Jph%5tvtnW1`f@fcQW6=1|4nS|K!UusQhK3ki+QaF95h_azF+&j^cz -zAQyy+GMXGgYu?;|>qD -zJ%7Bt$3ztq0S)w1aZ5irHY)y4c)YN=Kfh~($SDdMz1#+!b&+j<%2Cg=)&#{eARjvL -z5(?D&?n5VN^uEwhFIl5}vjwmc;UBuew#!BVQr>T$02e;ZEhCp{GH7GOazowr5zibB -zd`~&Pm(x#eh*iqP+w~2bYRHa4H5!$?9hWWvQ|xsLq6HPNiJ+;;OF>biQNj-B7|s4R$9ZGMm8-{t2=Z%V=J{>WXE*=4 -z)DDwAtJU=-!5#N`elUS7I^dbHP6&Z$L;@8QO;l%-CqFp^4Pv!u*1-0c^ILFXtZNdH -z%@qea-{z8(TB$0hJ&Ya{&)0sqz~#BL^hWlXpMi>dXZOa#je -z<7OqSOH}jj9{Bq`CA}z$@CAn_kaJ -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 -zQt#Vp*tk#Me0w -zgU^3fyw0dlMJaUh!W&*CTg{QvN<}nD00=sib0JcVC)a4THp~p{gQgE{0|WIPKr^nd -z&t1;O=b6C=T;1rY -zIwp>@6QgxsjB?(e>=KAL2fm*Pw)rD=5uX+=`>gHN^a$G}u|xCymD$5{i1cdy{d@@;CY!a^*cOR0 -zdC<0%KvsLlW0otAfxGyOqHx|-IEj--O~pNT;fe<(Bl738lo&rwF1 -z8YB;`MxYqS;jko#bAVHUh>vYF+x6uDnl|)%I%T}B39jbzGNllt71@glp!BCX#u%9u -ztFsPYCw33dut)J2>=w=&)K*E(PxM*9?K*icV7P+q0Nzz+V`7LCF^;h;5D_W;#-HQ+ -z*8m)zw$tm9LAeo>+Qkx7GQ5ts%$d&}GUdXFG< -z65-HKv8~g0UgzLIip7NYT5p?A_shFmE?`G81d0* -zHC_G(rZuKa%SX`bvqU!jWxhaF;WmS1R0So1E}BXur`6Z!k^`4k^z~W>`q>ZPImXA?L_~0@M?ceh7}lKv^iQa -z4g?=k=dknHa}UW#r!)DA^l|1 -zGIWrik!^d^Q1HUr{&w^6blS|c6Rp&P_G=!@Fg<8(+=_UPRD90mAHiXIJFfkv%cg5pUUR86LV7$?aZl0K2a;`18G~R82x0o!h -z<{L8WRu5Zjr7cp|G<3QrGgcuGhe!QV%TPGM3%`97w{ -z6a-olpu8ASZJ7)E8Y$nGc55V(KgfD4Hh2?Qg);OCr*D{Ayj#=6+QN!EW}TA;R~}IL -z9AHHt1eTy}B!XGxUY!j5h%C^ek9MY~hfw%F6R80Hr|wmO%8_SB#1usupmXIS4Gui& -z)U0ttq4Xs*6q&4M+_daz>^2O(K=FrH;=>qxDTH>AA4!8Z`oHIQSW>lVu$*0~=4uc} -zRkmaTRLvC9E}sUps5bHYg&wFTEHg5GatZNHz -zw&exMFBq3ov7`G?<7BvTm|{n4f)u?^^`M!TF`5YIMlpj8*e#% -z=nTV=@TFcM%7<3UWP&}VWi@$~SCfJ*DHr6r4QGMml!L@`OGt6j4m~bdoj9|_?e&Yk -z*lqU(eK8P}t4)?&)59d68ovk_a!ifiG&6vh`RIqOtTz0ykO97SZ=mV~%}2Ep=lVd_ -zYGN6Px8=af_JTQbXS^0KH?RvK8zVPVtl7=X*EBQNKRe?6`?%juWTi!b7;J?T0(*uD$4_ow6b*dbyF$=bjGS-`S~ -z{%)_g=m2^pi7IFmnBhJ?EEV1ctQ$jeeeKAt?Mu`OIE**JK;2eUE6-*h41yXPB@CZ@ -z!QhXt%h?FW=ja~>e4-(^7w2{A1CAjWVnd-V!zW8C6o^_b$m!;_(!9}WgtEX=&mNA``K7`Iy;@ -zW&(g;FPxjYOECmd)qD)`yzdKGR$f?~ropU(%P3ptXbHJBD&=1)+)rz!`xy*Z0i!|! -zF&jMQLE2E#%FoG<^oal%YJxur`s-Z=A_;xjY~|NzROCC7%AP&FXzma$e|(>{O)q3_ -zq&h8fb1ID$JdF;VY>QJ?cHwK6588>q`Bez4P8L_2_1$`M{II%R>MjcI{(GQ|zq)u- -zz;gBt)L{A7*@thFDgPh-!A~4EzaLBvw5Od@E-@sEnGJp(VW0WY7xo|iPO=yU=&Wg0 -z+s1tzRoPTy@FkNM?X%5L-;_bfw#Oc&<)2aLoHpFFOIXI*XDhye>+gi-3U;dJ%Puvx -zk_h)wjKsQS@^Zoj_s!S(emFiMl+rkiRK0sy1q#vaNwd}E2e=O$ -zT4}+B?;aAjGj_uuzST!5AW)9PU15Vy4PqeBUDC^>W+JiIQYxjpbXV!QvBHKaDhOtN -z`#64Kz_xdtcYmFPNS@K!8$dN4tkUp#&1pi}f7YFsbG+(bH1o86XNQ&`|uznnFug(Kc2bF%QWAmT!SqDErj -zTL<}QE86(AqAB)&5g}RG4%-j)BpW@z7Q3oCLVa%4ib6<4RWhWJ(Z=<-Q9xP!cbxEa -zIPcMk?jgcXa1-zpedL_(jg?QJkQnw{C*3OIer2fos4e-aCuVg=#{&5h!z!yeUf+v! -zj?%S6{bPM|ffZg%$el+=WYSNKW3)7a7#H9p1032DwX@ctSq&I{Pc4T_4s!?y9C$dy -z?gla{>#-a^%r|e|Egirmq(=KZRcmZW)-1Xjh@D8Dko8{XD-wv1ox2elL3YTS*3&3S -z)#k2be#+-(q!(fA_%7I*02FW28MPVMUNB0mnUp`z0rsvsg#)T_bpD--D%fw)kl3XR -zaWt|*7NWNO|F4E=0WPH!oviMj)_*Krp(iquzF93vrn_(v^*v1Nb#M<0Q5K5uq-@2Y -z)(n5eclI|5>6>gCHI>JLaxpo-pR`;pg~ciTQii78@|U)%~PFrArTxrI*RcjXAjA -zm?6&j+Y^p&0g&EcG>=>(2O6-^0zb{9Nw->@roY&fq+To&SyE^|tfg+L7wl1#Ep -zXqKc;7wgO|mtE2SZ9Gbk+KWdkyU7qplsWt$*&t*bLtd-tDYAa4v{S=Qjn%Vh3sn_0 -zdmHEBK87EuSXBFfft5s7S$Ui-L&Ysyz;E`@l=28HoH_zPQ?rYyS!I-1l{^?6;v7@( -zrXVa6FcT_aT-u(ZDJGsCgKIf`c!|lgf6g}-0oI-R%1JIa=uCB_$v -zZ&7B-{{i8CyEH`m=HPEHMr%dzV!;&}vPFeP;McsS1C|#PhWkx*(*d*skgj>7PORwE -zI4%kK@g42yQFN1<(x2^(j8dDJ$n6Wg2JE}=xVxCKq9>L|HzY1;A7^a*9(nAu&QJt* -z^iJiEo5#%x1jE~Vl=bc&wiYZ8UK6f{apQllH-F49{`Sk8*-RH}P*BfK4-~xwsSnGbd@0svEi1>FgD&BLV!4&Z@$hxtd3g@iB>W= -z=RkW~;8qIPe7C4N-Uk-NF(f`dfvXPcO8co{ud-#%n{J4ZIgjT|#|5S%P2M<{5`yC; -zM1uctJ%} -zx53tG1Wt_zn7km)qEPiIJ7LJjJEBy<_resp3JxW?2#0iyYWW_G9{=b<99|DN4%w)>pbzVIh4BI0PP<({ZWh=}yV+oP4FA!n$jc|C -zJEuD@#=nzM9dJ}cL=Y3GLj>uA4kA)fr`mpY}N89K{ -zdmPSu1SdPFicfLtym&kGaf<3#d7RHr`K(sGSEud}V~y=#sn!g{ac*IvH2`C#?tMj3 -z{22aca`w8pQ#^?L+dWfZ)T3=;RK%<17Ys1F0qm3N6V<`I8Jjx57<9b{^&bdFS^q;= -z07Ww9pw;sc;HwMs5k_>yL9(?gZZ=F$eY1fh-*aOwR9Qhoi&8lc7wbXC3_A?INWRCJ -zlWw0L+AxN0zprAyW-PK!LpJLzIes=+IYc~eP -zqq7w(!!twbvD2*eAP_e3IY+C1L1X5>Y5p_LbwIA@U&lZfR!qa(-84r2z?XRFLWC(dzSEmN8hwa~8sG00YKq`zKX2Ce^RL(<;zB`9VS8$(Z5-1(;|ak^H%bE~s~ezo;=WEv(g6lWH9vp-1x^Q#5$}+AI<5VB!MCvSQEg{P7#+teb_g -zPlR>kPC{Xd*M0*9ox;621@R+`?giunB;>9G -zVh#K>lieRy&IfS|wIEv>LclQ-LeX#A<>tfu_WT0oESQ8y8_SkVEw^8yhxNu4R>?28 -zycZ@njLN6eQ=9u1@#6ALBH1Y4)V-NO5lBanuM~sae1jjzj -zMo_kJ -zZLyDY^Av#N(p8ld25J -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 -zwO}goH0}=21HLj0fv`h@+=b?tjs -z^d@_l_KUCrZL87%Cb_otHXJwP -zl9LK;?wDu1^f(2TDIIfA1eXFeDcctaQ7q%mM;0*(2&=wIWfrLZx_x<_St(7M9L} -zHvcW#Pj_xDnj&Y(Yoy$>_l*9vmjl#(YzU}XJ0I9S@TN<-Uq?&}xgZPH_{V00dEqMF -zPV%Vw$atAKbLb%%j|Zt#vrmFV -zhha%pTLqYfR7c#v@cc2Y0P{|@`VL_))dqu$p>~v2(avg(Ap+b-&tM!5(>(VGvdDC`1AX1u!S% -zHiE*KjHCy1{*q&~IA$q>pQC5HH_|^6Ycc@OCJl>%ThD95c0#LOF5IFBpf~0^9z+d!$b7?oqGN+?RqzyFIljyn -zfOw`Q$xIu#dEnrZ!{+yc$$`#!!9oQP7C1=el^sMd!*G;iDXx3d1$6QNMOi>5G*sbN -zCNCaVw@b`J2MjzrYs7K#FF-p3ebh}7P<1(MzMNy&&vJ<}@&%~>4@dX&)dsCMTZy)9 -z#GE_Gp3+Y?SPjiamfknQD1ghSMnR{U`Pk6a^bpFRh0=U%UJ$pU!%?_F$Dsr!vz%aE -zJ97~H5=w4b?pEkzhTAY^!;NwwVbBk`dmr3~bRaVQvt68B4L`d4LLEbOlMg;YrmBLHpx69Kul_+>d;JLsa?4sX`B72sU6w*t-@xWNv1 -zVO_9U6N -zuJ_!?z=JjK(wKTIjj7MwVKDpoUejLFMfYUq0wIL>d>V8ZF!tR~Op~zR3>A8TK0)ee -z$YAMFv(l0kjA%Hms4cp*f5ARQn?dKSt_@5&Pp7Q1_>ztg>j)S(q(LBm+-wkdBMkx? -zRqUZU@p68_-SU?jj))Q}XpSLEuCDCqYj?12W;(tY1g3En;xyZBhI}%ds8`z{4J(DBRM(0kj-QgeH5C5P8FaxHW`Dl7v2x{e -z&VXiu;t3E__D=f&__-H=L(vD;D7#NXBc6I1Xg}ztOa=iMqEcPvFiRyn&0*gE3O}!TPN;@h%dkqY%l`^{+Tq#w92W7tN&zzX?qBi}Mf~pO}W0@eh -zHzml9oq^zl9~^Ocp#0&t<>HYTd@!I5uN#KUfgDSgX$_ud2@da;f3}nA1^_!H#c+s^ -zK9FUZ?Qs`D=?!Y#bE0rgkr9v~S=;f)X1r|Pao++ARsW7(f&w63<;K!Nd;EP9G75D9 -z<_fs!4dDq~is_^P$|QJ&iG)3`6-1-37W+i3kq$T?7?`;=0eHHKp6_SDh<(*x2Y;>B5TNb;jfPVhu~(mcM?F -zG%(K{>cm(7JBvJ8oa9_iOHm1k#ysDVs@%QHShmXc-&bZc1E-^ip+)vf3P6)|d@2Oh -zQ^O#5Y{f0g!Kj`HKBFB~UAHTqwG&m631ZluoIfQAA0DFl+4!>o3q=Sd@JpV~xLaN* -zaH#(AQo=Wn#rSj!__Km~a=QNpIMR@wneHa8(j7vMkB)_hnm)h*U}WCK+Crc^XGhHehm+lOwuB|<6oLU -zZ1^S0?m4JvBao-$Xw(9 -z2{_RgtIO4L)Bhd`VSyEbdA1B -zp*eZng&#j@ai0rR`E? -zygx0Q#qGVIBt$QZG7yeO?VXNFT!_jE86g}AWC$qLl`(G-lo(nF|Fp&A_~}81ZK+zM -z<<2tv0m3kClC_kWJQE9h9OLX0hjp`6;EC%7Ao%Bi2n|zndXwtX+4Kqu{NnSstw*0@w -z;oIP;PXdD|+YP-aoL^9BhVlIf@I!}QKvCKWVs#SO?MC#cBDYmp`X5l24<3M4VlD+? -z$t_tjEM(c9Lc$jcQ8EAbZ}XNv7v6sFRkYG3c=__ik|JO -zo&=qR6~A~#x8k?MeU7zh<-BK6n^rr}(E7$`!VLa37hy798AFBeyj?^Ohn`h%Bs40? -z2UwG0fTh0&gy3oeCyOehZd+&s)`z=UeSW{7*DFC>wW26Q$~OOj6xt}aj(wSEvMLzq_9G~>LJSzCQ+t;}d*naKk1-jQ|OK0srCFcyh^pTW4Zc@2u2 -zM!TzKUL3?_lWvm5r^27kXzTjn{*MTKaw$2b5+9Mu96_gxMhv&Stb>D7>=9bNJN@+W -zcTN-jyuMj2R?F@5^8&%Y{%>D`mhxi(`S>-41ir_a<5j}Cg?DE=mX$n?6;I4$lY<;) -zEB7(_O2iY`f#gj(XinS!m=uTsbvdE4)Jh8xUy5m2@|z}~nJE`~Ph=1y`n_rxO*?~J -zRzE-@9;93&_AhI`%?wBi^q_9Sex~+(_B%v+=%f&eYZ!e-c!i>LlC_oT1_fq#jX#u! -zP%s-Jz!k9Jd$Pn&oegKRs6F(~BdEYh++cYZ_}#Fkj6bN1KWOxMNt9TbtpQ$bVzpRa -z@uDO4W1BW5l78x{VVusF#5%}3~8{roB`Rw -z>pAtl$g~fg5caD=E&a}^n!Lr2yZfwgb#XenDkB9MGJ{2W>m|$F{wG`t9=Ut@{?|hj -zM`WM?rMjNfWT2`&wOT+Rz*!+rU9o-@&O1Lci1-8QW3=>fg2D%|V%VW=2u`51jatp> -z4Q#^aM;xa`dH!`cY#n>Iz{NZX@+V|)mJ3LBx_)Z^E@DwkbUL4JeY?Td%V2? -ztQ-*T09GW}(t2DI{i+=$MJ$S$aa9M}SLLa|b4`0!WKL<>?~@`B^ewzv-8J(k45?6S -zuFSVwowj>Vhg+0Ev|@ssy_mxZjP4ykC#)@)bLT6avM2Jc;ruku%LXAwKHjAc3j-ax -z=AI>nI|Hx@PJzx^gXGsuHb~Z;srYyWdK?|WG#%7m2?C^e?P1y!bcZpRD9eEdrD1?w -z?z>C_tiTDpR&L9Ca9{lD0;3@a&tm;c;GJY6?c~@_II?70M46LgRQxWn;t{{q&`^+u -zf&ZytEeKT@F?aoIRYY&11q2JV^ETiI#uiGWkOVK^&fBO@UV8m2U%WSavSE^UOBmp+ -zi|J>W_$up8xP=wTb}6vnd^%-k?sjPjh2m99R1E{O*17T -zZ-5Hny#!5AcT+DHb#|^h^#2`81&WQ#TEPC^r{zXw{eTzO#$Z9L|MbKJy)(++k8G~T -zL^el-_z_=eqmXK42_Hz(s$PMCRm3jOpnw>&Y|E0_^**jG`Sf7~AT0q|B_PdNAN$fU -zqzhFVMoFL^GCT8|Q+6o27987%c)3^?Lv8w3glww^U2%lX-Cz8I-6t%sfIh;az3L8@ -zGh^lanR3)!F*TDzsgCG+-sOccLjs!|ZZMXYZNy>@5^*W(CDq}a7DVl2q7Lk!Jh6^U -z^1^t#v=P=s;=e=VQkHW974}!H$&2$U`}eRO14iRuBr)qtzV>!rz$6o0SA!eqlx4b~ -zlf$X?sBh^fY -zTS_pivzvGFjat#tU&7*@6vFpg9Soma@5qychI!&@lMty4CKCaB8Kt4{J%FYviDnyC -zR;%4}rr0Cc5^SD*ms+n>)~bY{Q%@20mG2+X{ySVXkW0o|8dXA{%LkgDA>d`TUiOjT -zI!CZQ=PPMUJ1T;quk%^joL(?;-BfLzA~bn{(IKR34??6};zSO@;#h2;!<@i_8K<(K -zp%V=i(=ErK9lAJzR+q^{kJpkJSKYM&z9D=jh%a^`!HM$e+Y_zTnBXJEDhP~~4#q4F -zP5FULH6S3ps#1*QM(VaRC&`8GxA$Hl4W@gkG*11 -zi)s11<=%v`+s_6H{Ch;!)s2Ffbx>#&Ohj*3$b|kAY;{1U|A=)`SIZl02Lh;`kKS-x -z!Bhi{f=r$4u(itJk%S72ah|_m9qi5Of0ij$qKv*`<3W+`<$oj;sVv8K%bq+{4us!h -zk7L$K)9W|U)_*MT-eT6o`5cYRIubvQg#o~R -zS$+kEzT7CwS$~z@+~EYIsaWzd)vrG8C}&v6F{;!FQ73>v1ylX1lTAkvQ0BG-^!if= -zBgimaO(%Q`f?GCIp#J{I2D_8h-4m|WHB=;BZK#sHmq1D%5DN!a6GBY*I`n{_px09G -zq4jjrX=iW`?gJFHvZdaa5UG7jqezsl{4VKsG|2Vm_Y%4UmOmE>7(QIjFz3=^`7qT! -z$Vsjkw*1#@KyM+f^Hkdxq6S6OiO~A0sy+}}g0USUeRu|55?Ed{JPZtIB{{QczTQ1H -zi*Mg1QB`;}&H`g%sx{<$nUN$KLXr1n0=o~_vMTK8VtF~onm%X)269`TFA*4PlTJ8q -z9b2QO?^KsC^G8P^$&6>^tpndi#B}y}e*>-p#zW2iiGzP9z)?HEvSNZvIe#fI^o}us -z6U|w8jF7-(jJ??1+)_+j6nn2zOEHP9V*%TRHf1MZ^+NDfewQpvMj`6W#UPux;YP*xHVEVuYE}?- -z*F-@eISjjkDBOSDm$z6Qi)E>(&uw%|^lSHTQ-sOoWWpINsC(lo^b16XU(u>NppyTx -z^UJJ#*;2k8ZI0KfJm}JeilO4TA`6db-fk7X6NGS|o+e7gAmn-n-c=vN7Q*(|>^MOn -z@%QBe$0>1Vk&I6l2VBEHLLsl&E|-|jLiTcx|K4-5hKAb(OYHke6kr -z=6t)w)^ChO=!g%zU@(qYPs6XPSflP`!@JS)Xq~-2Mez7lP+(<*2&;uM7_elV|D$5) -zQFHbn!vz7TE4KDRe(l}DGv3NrMH6o{2Y-9vBG^IYqAr@kMAeT9EW^Gq+pn*~|q66iv4lF$n*4QAX63*MU4Tw*E3 -zfWG%%Opis%T?iS^|3I&@%TP0BBlLQ~$p~?+LtsF5z~V1h$=QiLfY<@0L^FF}++YP> -zFYmbMxLIA!{<+<-L2oc-PC#KQv*dJ3XHV$WjyCDt0NaQE)UY8JPk8TVowAe* -zpFFn|rNu>CoL3Zz13gl{zy_f(4_W3xz4I$%;EZM~WZyd; -z`vZ5Xz8372an8%p!wk(t@L -zM$|*!j^|8o>2huzgx2#yLWU7DDHu0{7n4A -z5FmeUOhZZ_fPtZJBmGV{A#P!Z@oZMbyZvW2cn(6TbDXdAM~t=?NB55i2NsCHu=)q4 -z_l&N32m5oh{eCCAgu)Te^%k^@w|7-qG_sdg){eaF)r%-AHay9;z|k{Z2SxDmx&wd8 -zxz4o7$Grj*mK6jdTn*4r8{7D1$Zs;!@_=`zL)Bkh&=@tUbbyD;y9+g`d0$)zzeuDB -zS$7h6jak7^&ARJmVsXmf`gocc1C4*|#cHmmVXqk4{BGypX4i;@FBWk3NUoN5q)SvbY`W0$FyE}{ -z%kKp8%fuK{>7z^ry@+SJ6XdK}ff&;eA^&t~=AxX=8VHj9mJFox5{c6X6i?(cCkm#{ -z?rzXabNBUEOsb^Fx)x18R!6i{(SE7rlyZD_03P;gAMmk5C -z(YA+o^M`W|6L6VGQtIo&uSA&ZL%1Ru6@X?meC}%>Enl^5*7-rHt7V -zuE-nF*d~OjK?n%h8MQN>q7{6>NsUhX4<{(Dem`F#KbXt>+U6XTKm6Mzdn5rb&8|$T -zU9B}^2NxP8Z!3h+GPPf0dcr!O3eDv8c5$`5c)USdBGxW0Haj9Wc -zZbE^@PzffXCmRg*#T-qn7t&td8OI{I`U8wOB!Lux`T6Q;!X#|F!U4|#|GVh`)BpOf -zxBvX-o1bRQ6M~RDKNQu_BX;7V0G<7F7dImnD|u^>VYmMToW9_H`~7DtWkCwt7k*0mAOp*E{s>v&AZ(EW$Ssj)J*j -z`Nwvo*9_BQnD_E@ez}}sA^i2n$+7)+CMsx^Iyf|c(6*M%?=Fza%qA!C-{2|4hKL*7 -zhxzZg!4p)}xhvefuWKTS=6tFv@X@#+mE~z3rNdB)xFrt_$GRC67zjm2UoMf`BH2T@ -zz4)VFE#0beG*@3pZagCKaV)5ZU*jC6&w5q5s -ziirSUWEtp(tQ@6GT@?(f%V@#Pj|k!bhbTfQUGb+6H{00)XERw~AiPab7nHmOhS=aQ -z4%JeuK`~g)Z_TVi$TfuToP=+PAer(Vin-@+5&k&(_AXUHQ)MJpgE}MBi%pi1hw4&YfrDk( -zF7u5(HSi^$n;9)De(jwO8a+7HSwG&&BEcj%K -zU-(eE0hQ@?{>RdI&KTY3WfA%CW7b-Ghtf(AS?{peO?m3*=~}-DJ_17s6}R -zJ|*G$AzO=UJGE5#e{{c#l|Ky8Rt} -z_!r>cxCDDx;M(b!3+}ON-$e=D7>UEOgWRJ{q1hPY*QI1a4~X~mo;-kIOQ-H$5Whcg-1TJk4M-|^CcNlU2DcxpV=%=$ -zO*TyTF_a{c`X!|zU2}6Xfjl`kBBGq#6w>y9P^YKpNTMblzcc}PB6y!337rMYckn)_ -z9Idy_C-7UaW^);b>8>ViM)%s(D=>fzem_xTy7fLp8Cvf9@B616}M7@lAny#_QzaCi>gWISThU;w;IL -z(NYe4MOK2pEYmGD^NU;tel1WFItti2JO?WG@P#PRLsu~sdx5WDoB7A~&!9JxL)SU0 -z6R=%f`Y)6R^}LbWV7TNC^859Hb2%3-#Z6Ud4xR??mqTD}yS;shz^o+F51qZP<6UsoFWV*! -z40aMg{TECnkAqS_Z7w{#n_!e0Yc^up>TA>=%)}gmOKq%V?(jyHy_F|F}A1>hCnen$E0ep -z9>zb0tKJ2n1{y9T9y%FeFY1ypymoIKQMROo{G@McjU6v*uA5gBDSj>tKX@TzgY)%z -z`_PgGm>V}OyI}g+aw$scS({gO+oS~FIpSQ=x -zSn(W9(2!oSf@x%2>L9wC|(1f)gB1+)WAO^ho -zg~GAC_t_WjG>azQi{|rHNv!;UoXYHG;%k`o0MD~bx!@;Zi$t!Ymk*xL6VFsD;lNvH -zyAHh}75Dcx8SU5i&|LZP0GhOi?_MkJlE75MU*Q&^#JBek9%GuhDMy}(t2(>7Lt2(! -z5>t(MhXh0)wn_)cp%*B7#F7k%P6V3s~F9 -zK(nc(K82OkZW91HKA@wR2=W;``Ss=&>M90Z3Y3{u?KqY+iZC(#BG4N2h@7IKf*XrI -zuEllZTUr}zdjaxKevT&}?R#x=Yz^ws%RD;-dk?*~I(HNSKQ?*X&%d&f#WEe#x`dVk -zd(XCCZt2m4fNBmapW|_cuYn(Km)(ti;Ajg<~U0J}gaYW!SWH{&;(DX5V=3 -zJz{?k@h`*;75O0A -z|9EUpjR%W&ip;%j%s^CmvZ$!40IlwO#XL$Px-^fH=?+{`F@N)oiVOdgmKu5h|l>_-*7ZLe)_K`4aJ}64Tv8 -zOoGX!tzpQDL^`|PpIzk_97ARccR`|(v@bY4Bu}n79HJ!QO_!rYV~&t)2^}Ry -zFS=ECoM~XTZ1Ej4nXvp^*kUMMpL?b2@!4oG7Efa}*0d&%JTUDi+t#+b)s;Ce4R1WK -z%jHw;VoQK+|1sbGh8>eptOcu?RM&doI#6X3^$VQgIjqh`G6c#&3xI7vD(3dSNrW7f -zkwcxItE*&(t1d%%uk<=J+wICNQ3j3G#o8rh7}*?T7_pMu@!P*{sxTU%9Y{2$ZHkJ9 -z$PF4*KIf4590+NQB3(}pF$Fdi=%Ref{m4C=s__ -zx*lF@{QLMT`u1!0%!J7byN5dtARI6XSyI?zBk;%#lkWxl`A}2T2~0j*c-cbyI7zJ6 -zAETMAaZHLmsdUNej}`{RphE$mL~KCY+bgWdpT~zA#Tf5y%eQ9u!=zuR&XW=n%rM+zdynO6%Q3MB?rh+> -z?JZ2p&%^tBUSdpqCLvRfynODMpWP$Vc_X*muTpw8ph1qPQJz-5l(FEDebhm=w+%Wp29(^mdh&Ch01u+PU%6()lbr-+X5p`_O1bpHndma21xF|O>xjUU;LNdj9}#Zu -z-tHqpsoxo%nErfV>Cfy@MuD2GlHY|D@||YEOaCLhI*)Q8ezpdWZxjrJIM8Vj?-%|j -zr{rnDR}dXj>)3zShAvXSCj=c=OT;4}}+o1-=leq4?-#eJ4Y9_}rhLKy&;e131QZ1nj{if!7A$ -zlgvk^SvX2FfIYX1PWk}SyXeY!hn$y_=;9h8gJf6YpSTdMVBq`P@QZBZ`C@_9X|vB2 -zmK--_6Jrr2uR3eX90}u%!3i&QXK((i^G-b9!*s?E#XQBii|ks8q(4B3nj4(!|Ihdr -z^%;L#>)zF^jJIL5UvTy1#4N;{%=kix=?K<4#ttg${qHt^?2XJq0qdF^WFyI7r?asM -z!l}_no|cghTq8M8WW_#P7XVT%CRZN35)SMR-gEbL3U<8`EU&juf#HF3qY~sHOM{qj -zCbxAy@*{aFZdo2H09XxHO<=HNk+S?SNWJ)S6+svdC57HY4`}$K#YZE7_+JEwSKSb~ -zSEumT8zlF_2J(f-Du`te?AmwR?GCiSPg=PTc$+RaJ4v5+UuMf2^Ne>s>_^1yxslR{qjku2RpyEnHyB4gkE12E2 -zons!_DdVjLt1A@%w)aW}ExWg(P=Krkk$sdzWP5}Sn4s=Utw}1a$iM)=4J-=qN>05b -zWvuz1W3<Je-P_YTjYf1I^5KQ%8SDIzAj0w8{p)rH-OvScQxxJbhUH -zYjC$Xs%dz-h}H@*4#=sKExOp27qZx7W=`u^cAW@n{RJ?(22uUMb>{^I`8E@h@FcmA -zuw??~lHbwLYESpy6ySv=Jq{$UqxCEFAHGI*PC^|a1XuU~&rM|CG29KJu3fk(7$5m# -zxGDJ|^_&mvb5rEb)QO>-nQhovg$+AJ@9yUJ4cO>H)5-SYubcS|jSzZ{F^KkDw*1M~ -z7D!Xdy9aySZ1z+$@U}$?YH{|jJq?Y9K_-GLY#B62-A!%2ZYOf%2)6FVu1>RV~9bsE~eq}WZ*4> -z2ejVQgE#C_nP8{PE1AVy)2+(9tkVgLGXg%`2{dtJbST;coMSGmrl{A;+9G^zKQ9T) -z5u(s|X9v&bT9^6V>f|TVT(?*Q=3g=dXqHb)PJ^~JM1Ju;EvY(%bRobbhkYPg3?TeO -z`rnV)1Cnq3jP`)w)C$3Q8A>S~5eg*uXrC_IjmWiIv&J3*h7!r_czwX=ZO8V&puFfN -zIxzuJQ(a{@s7Gwt2;R!}zuu8Y@5PvUKJQBEd0>>ykZspZKtvKxor%uA5d4sepvSAs -z0g{X24$N0bN< -z^l6D;W^xy=7IqHtROvL8&6nu6{&T*$fF&(1yTZ#C*NFkock9Hw?Pc&vL7tGUgqK#8 -zA=C9fyKm}njg1X91JL_u2|5x!SlG^hVec%1;ha=^#sOh=Uo?rX`?;{o6Aj$tZb`x) -zk44>4w#(;)_u;vW6LviBE^_;GYqxDc)2WNL_#`G`WD^;gJkW5)S@Rw~DePy2 -zc73tzj~ir2?=;X?ry^!sLGQR~ylXmy4go1}5GtIqY%}l??ug*l20`B4hx}&0isnZ| -zp{WTnIPuELHbEBmyln}g!OM-DJ~)w)!(WzPSD+?g=GOX-6kVCLcr2q>Qq5jI%p%LG -zWQ`9MAh+eTGu7Iq0PcMK4`sXbtL7JM&%D9T*VJS=e~OXjp~VWpv-cwWoAS^otO3^O -zxrX9|Y_6NJuwoF=_sDMxVjvMR1Yy}PBe)3)3zp>eS(r&6|GM6|q^k(OuIvtyHUR=; -zSaooph~*K|Bl0lea`G$dD`|rtr!t51Nd_i=9OtbMDe2jw23D%qVqvP~| -z`vK{vcPRf@!a*5BE^L{434reQcJ(k-YWg8k#z!nmM%h3t#D%V#TX`+{V8%s(R48eI -zVFtiDMfAnnBO6{jMA12kwB8?YG&xkbLaf~Kq9rDJN{30B8i54{IQTYLs^POBs-|#w -znMjzX7v8;fbrC&W94=0TtUgcc^S-V|Thh>r`+Ut)oln3q!5e|4&hbIqWQ7QW|2h*d -z#T_w$!Qk*dL)=e{P0^hPp(h031nLlPg;Ub4X=Xk--JxwD8>w)jL9-;8&d4(;h2rmfNR=%LH -z#oi9H#6D!o+tTtt+8W&Cl`D!iPxH-+ld~o-{+zEKVD=tXHw0wOf`!B8_k+oSmR5lr -zuNQv+WSKOtE*>?Un|(WdIF^5%efTz+;{Uy{|4_kW5c`Dyu(CAfh~GE8MwRyo^U~QE -z2!)uy>_QH-REba4DkWiG&R~34-7a-plG*&lCJv)rQHNRC6%>Yv_8hh13epgOp&Y@T -z9=_-XsD9)twj=lruvoq4li7k9S -zYn)Qwp#V2^>H;`1{1CJRDelCDdA7X?MrUg1?N0_L(Z!&)!*G=1S$$`X)Ze}D}*idJXOMnSY -z7oE}1$?w=@?SzSa3fCAIw{o~`qVl$Jya -zXepqn&0rbm2m3XlB%&(#<1j>#qf$L=gFf59gK(rU$5Q(?5ptx2!Fag -z<^p4Ck5ve81RGSPasCorCZ9h1XdmN3<;XrbN5`P#nZ?hr91YedoYgIN9*8|$aOZ8) -z#q%&MD%$~C*wko0{AnUKI37N=7@S{_H8{0c8NoQlWHb~$bdXSYwE7UkRK}g@n393p -zvZ5P|1GZy_`9%+LM0-h8L|K0AH>Y|&Vtd>$X1E$`oSNK(hf9xHCO -zcM?^cixk1Dj!_om2B8>__O)ynl+9ew3VaTDTu=_j$I)sQ2{#`xJw`zv-G-orfiXA= -z!Tmxg;s*1QvmF4cvSza$1q{<7+1~T{mk3ZF0CEef$ATu0*7bIR6vm$|zdWnhj8M -z-)XcL+y(0>e1n?+cj7LMD6cxeTE~z3+eGr-QxkfAaZ3u>@d>T|H~vykmeLWS>|l88b)I5MFRS -z$6J6TW?(ixJVK2^q3FV;Wf;y1N#EyoH7=lPl)prie7kL{-9p1JuR9Mba;4>DFSpC( -zAM4A@Dd0UE5(k}~;!iGC8{SAT_>5*~l%5H2>z!F;#L((a*GAb;0yp=pp#&7W;AHy! -zoQcfKH*Hhj;o_98f|S2a$KhJJ3L^hPXiUbG{-!O%_LuCgf*IK2_aM}ODrJ_yB|F0$ -zG8WAdh$D(XU(1$>Pg>$%L1Y~N>Lc%`bi={-2Jx)vrRYsboky`~y?bQLC#k+vG0tjcn!{%}Eu;U<;cY+cJF%@*ruZM<#FYb64Kh1S^jNzxr -zapw8$+Jousud$Z5(@Kif9O&5PP>8pv*$7PrWk>*902>X4U$8g9t(LXG_~%~n3@b__ -zb)jUbsbNsLvQ5HOj!v`@@Yq%pZ&+3`ezVt791Ir>@TzTu4Q^&6I&A5EyQ0H9?!sPT -zJDwE5NvbPJ(c|KTMba>Ya345wA`yPTLp!XQi?79i0g$uqKo0i@_q|}Qq!rnav2?nH -zc?L5{#?OUj1drwU+jP(#-lqRjP%D4ICe({eA&I^DuE8&Q;K6rb2OQTn&d|aT4t2H! -z5qM3;rg%3Xb3%5yfn&3-0H~!mC&bge;1moD8m7W83>`>fg5Z8^E)2W$3j~=zphc&Q -zCQ{gKPkM4#Xh#`Ow=Na`(StPhQkIERnf@TO*Y=ty^&JiyPQ4djD`WwT3Gyo$JDOxA -zG-<7abnXad`3?&>7qTCsHVrBJ$Zjaaph9&(4=cQPsf6tHR>P8lRvQ+m{J|bwlN!!Z -zyScG+>>|am#b4)l^RHMtjHY}g(WnsM+;*R|8wjd>0~p(>WdZ4UW^vVUAe{NvW*+DR -zog4=LDX6v%El&ogeDb{3jf@*11(e%7^4hM3x&Hi~zHFDk0eBE@aB(f;X>o;!55$0W)tb<*F4#J0+46*S{g({}9~{*$ -zS}xCT8-eSB65{p0MIk26BHb!sJFYp5`L`QM?+^P}Ytshi^S6(7dP?%ftfA?J6z|tt -z#1coB_`fsAZ*zN2_QtXy(>8%C<_A^=P9;b%x?XSu9lE$0Z~Da>De`zX-*^j!eK-Qq -zwv1SnXghCB!t@|`7bZ(MTho9*o*$tQbr)Xn9*pCWin@hW%eR#yR@qEQ4%sKEB!NZy -z)40J1PA`7@DL-#jcY -zoIM`vd71YaS4DFi&A2Cwn6_~CxeszT&}M0Qxj_SrX56OFrr6rbC$(X9P2TwQ4zg#0 -ziEiIVs1d7s9+G3j#{i$%tCr60}bK3_L_?n -zNteJdgd=X?$&z&QBm5F1-Lbxkh>Hu!4-t}IEM=($vdrmcU`mSZ1jU8Gmq_~Ld`B^+ -zs}eU3K3L9gJ#pjHNvP+kL1+K5VzMv@cx1*@$?pn$SkA3vf7@zUDQV{eY@z>M%8v>1 -zj=N!2qy0-K`Zp%W8UiYng|XJs3m1r$IAj>EYqfZvq4uU@^xkG!XnnhD&D7bFGj!2S -z+~{u<&F6x~K)p3FuwO$HpT@3?!xUi-~S4RA7C2s}(_m~ZQn -z$d|XvhpY9)_VDv>XG)Csft%vk(EqI?%oJZO1}Q?;7Ys&Yl)fM|k;Rok);8=M6$G~T -z+XV?|b)nMb@3+1lFJ}6mgQjCth?D)$rFLkzBlyk}X{W%Z_(JeBs04{f#_nJC)cmSZox-T2Q7WcHE!%^ -z(*sMEkTW{SivFHh7|o(DHtqrS%oQG|=rP3vk4}$iN{WBZNpU`Z?93;2%`iCK0AdcU -zupfvfj-*H!#{_VXFrI1jssDO7Rs7=vFh~KBx{URhXpqqY@lTRJ_Dw#LwHde~%?ThY -z{;ZWmnsAz?e6)IPvs=#bdR@-K|zBE4ldD;4gA!Ue@qQ+|;`N~LY|%9DYJ_hRLt*2VD}q^$*8 -z^D#WF({97Gv(Wl`e6p*tq-D=tLtzlq3AjYcaOeUia17f&=l7U16&{9ff&gvc1u@gm -z4EM?ymBJ?^jTp|?8@mH9l(M>r9V*A}XvjcAk(8eRl=86JeY!8$iYgQ>G^i#68SAP> -zuykD7B2%gd1fgOKtAkKU$u$TKgsYF+W7FMzfI8*4)_`_-N}qX@_=t+8Vz;^spv_OG -zzlg&N4h^dNWx0L4c~GWgX@7eE`4v=^4&QzNZD>R!TAe#*m~9cutkJ}W;QwWehq*aIT_D5bdy6XA@LsDT -zO#l6SwK0<9_4>*r9}I~^aGXj482ih3gQ7tAfU)f^U@Ud+4ICM2NU*S|AnW1z_;J;c -zIe+7gf;Z={_RIsz#pqA3(WX$t2iB$HKUzC#Y&gJ9GXR7bLpDGW(Cnip43Vmm!g$12 -z3H%N5HN53|UyYMxH4cXMFdzxen7?9}IC5Xh^*iMFUdFfiYup!}uD;X?=@vCD;FW^0VtOgiZI3}crSh$)VZn5@w#hW8p -ztX{B>WUj3gYZWK412SK+EqjLTVR9gugr_DZI%>O2q)$jG^~yy^23lSgbu}fI5#S)^ -zKFc%89q1z#w-R8iWb(7C9(eoxPGh+9QrEDIm25Y%K^{`g!xq2~gs1FpIKxWcwqDf& -zYg%pd@mna^ueM0sm->xm{_2VmtyYz0oZE{f66Qf+XRBeT^4llOICTq(T-IEdP~7A6P2GQi4?X;M0Z4KbS8T%k6gdIgSyE`JG!JFlc!i79Q|vU?w>v -zU2VSEeY$s9p -z@IR4JPW>E~;RqP-J~2>obXb?jb4C)}rc!20Ar7$?95?^X+2~^IYc;uFKmAYwrA!=C -zz{-TjY<@PaMgw+RNGSgV%+l4VqFAKpg2prfiJAGo?R{-`8_A9J{-PXFZ??ZZ9uGZ3 -zziKUIlCxj>kQ8OnBavECQtbTt=K`pzuBxs=RW~WkB-xzZWX6`ren9~j7Z(738yX0` -zSg01x|D?-)S#*mL)|aBI8G -zyr+y!Wax;2aDk-JAE!TN3+|*?gWfoAa-H#9++t?C%=9GPr4qH&93seBX&5uglmkZL -z4w090O$&O$)~ECR}ZkJy#g|~ -z;bmo5WWoUttPoGw0l#xK&bo;dEwnKM4*DS@rg?XRvL@&kdmCEKuv}^I1~I>b=S!_` -zZWeQzFhyyNSDx`RFEkcn?4#;ml8&3Twk#kzixU-Xfg#VocS!`C(%-HZtJhe=gDado -za+h+=7<}-^0LT?%@Q<=%@cDV%E^bMUVTLI-hkrTHxqzZ?@)%#(vq*+4{Zh?mb(45H -zSw%Urv57<5z76n~aRnMj-2qgf|4750Je{Zg^&2PPgJ1LM6t#k~Cu4L#$$ED=20e{G -zI{Tv10^XA^`->AEa5(EF88u^ri7o)XR?+Lg5ajbQ~Og>^l4n -zd(1A;0wFHI%;sBfUT?l`C$wc$58U1kE8l0T4nmVFxWbpDB1o-ld&Gxts@8<22_9cA -zuBIr@p|Jx?-4`OXCdBorzn%^~a0w-=}*(~A2@oyg+ -zQa?1X!6{$~pK^=dEgfa9mP#5TiWNnA#$mOX!~K3#+DfH?6YjH1K#FWmH-Vw>a^lYV -zp}1*DXrol)@#uwBBR6w2Bhd~S+M(QryrEt}Q{0)pVw{ZTXe7NjH#}NWnxSz{+NG>S -zv@$FrMgI|N5tpF0rV!aqdgOwf+aJ?{JBv%x!A6OgoKE_gDmssz5wzo-ifT^O6azD} -z@DTd!2ddK)sPcTjMP&RDqtO=Q3>KHN4(*dfMY9u)OGTzmF(kL3cV#ZcHTUQaJu7S* -z!N#x@Ar`i!0c7xFfSDNjLGh1vfE#zL)34vgP>~{FxG`1a`r$g-KcKw~@fa(v2_$bX -zxE^0qcz(ZH^frEo$hs#8Hzpo$F9oH5vMt)v=)j`^&k*;h=HRh)e7!#QSI%b2;cHah -zPmz3~r%W(aKep?;ndM9BqY_JrU>zSD+UD9^J*?*NX^24HIE&AaBH*QIBP}3{Pa2O6 -zJu28C+Y2t0cet`<%cbYB`e)__2lZLmqH}<4#2nZiMK=<@<`A;h$CQ_TUB=4c;<&X^+EEfhjz$Cy}G)aW2)DT^8NkRmip{VbFJvuR2A -z3L-_s_4o)!5+T+sVJvI4d#=vgWloTfTNL_%U<#i9_&AuM7?l~qr{Ei6v4&;IQZ`Q* -z|F!`G9wZib6MNbhmC(J^k(;4Sa7NHt2sUR=(6j -zo;L(52~f~?I|Dc4{c8C--B1!pij4fv$dm7nR>SF_n=I1U&auIIi;!`Dr>2M!nRd}o -zVhJ7LEXI8<9yQFJUi}u#h5O}%|Km=BFq8xt1KKv#X^2*A-q{{*;u~Iy>Uq07b-}AJ -zWV4D#<#_3DI+vWX$rXcl%aZejWPqzf3W_s6d?jxVby_o-wB>tX?ra&|PxSN;oz*(Cf76(ERwI%wIa7{v#63NOyV -zmo4*Ee)Sbr?F=^Jt!xJfF`y_iloQYiPS(+J;zbYp)e~E^kD7t(r5Dd-%7qZz{ -zdq00*lEj!?3hDY>pH2fJey%+js!k$Vt9vm%Zet%he;sd)gyD$WYtNcpx{@T5$FE -zcOxZvv0_CRF#H`i43#)fp;al`Bk*+hN|9M&Pzq9$SnH01!6VZexVGi}mOV_hS7K(4 -zlEU+5z2c$|*fwma|AXa_I0Hu4MB*7N=i$~&N>1dASjG1dijmfm%IGund~qDz&-kt) -zF0JaHD+1~8R{R_f(ha0+JWcoY>hjCO3d`N@m#YUZCT+*FnULN=)Pfl&hCk8L9-4Jq -zyd^ifF!<2?C6Wh3q%i5l;DS-cO;d5qrSNXR#||LTuk`{mm9@mI7Kzh~6h9se;r5aX -zJRbxh4<_1~Hs0)Qnn_IZ1@5;Js;)=irK98u>7zrRRcyIAxCM`m&=I`?vI|rk^D5iz -z@+gLocysfw{*b~Q20zB&eU -za7BAOVP8*tJV%A5CH?K1Tmpy{xGlosNYjxj-tU -ze*eBeGFp=(wJjc$`52lLWAjmIn3PiW=%56|f@Rl0VsX*rM4tw9oSFudaljp%+>ws_ -zdm>vVPknr%!}2Y_OzVP=j0;9%(`vgIWinMfaRrz=jv$B6v4&=`xms^-9cFq`-W1da -zS#goi344{z+z;~G{THaa5gy*;L3(75q^N6Gc!6SYH8(%Z`ect6AH$b}D|6+X3+;^I -z7{db;t^Z$omm%(sV8ZW4-IqL7r%&s)Z}h-zE)g&(c~xSVO$(0KvKJkaLS)P{O0GSBp>z1)C~Xxkzr;6E~u896t?u0JM|ML2dUg1_QfOQTfy<9gHf&-P@My)Ou -zbGK3ggP7!0ND5J_pR(O*jQ}^{yn*7(-4?oNT~xFuUcYXIQOPZj5W-GR5@bEBH}`>y -z+;qS>I^nN1=ZBx67a#bCAg`Q_Ew|1;Q&FGj&<`{Z*Vut0N~ZCMz1lNZ{K2+8aL6%Q;o -zcV9=mcgVoIOo_QOZp`t-+Q83_rQ$S{*1z6Qv1!>jic1(tVw4|<5E_k;M@TrbKOJjsrP+<@ri_zN- -z=%nQ2eYl`p(?EEQer1^4$Ml@uRBGTrOd9;(>WDVSB2<+k4Pefix>Ao%+QHKkBj*wP -z5^-5cXn&0@M1XlIL-CqkRcm*%osaU8Lo_p6Y)Q~j)@|YmrVAPjF!Q4y(&_V2m_9Sj -z_l45uUu)85{B|aNF1+Us?k-fkQ__5@$DweDYo*Ger^X+Mkn?W9R{rw3dU1E)^rwKQ -zoAp0J@_wgJjrgQC76DscW&XQSwGE#*IX^Teb1u>ShD_2&1< -z{o)onoC%BG{<>XkK1^?CmxQzZx)XibnE#7vURT%{edBhb(4o1ytsgR@+og-@FNM;xm_4PXZ>$#OK4+dPSS; -zIlCK;yni#myuSp1AdJaj?f1b8DZNes8t*>1!Q<2Mt$r>9RfQ8*QSEO8qI}MMK=U6j -zq^ErAwTz-)T%5(OBy@0l)`fv|W_ij}iWffNEwrK9CFU{TV1PN#(~M0z1-}F7S3;PJ -z*PlV(z6Q)lz~Hdk!DYLauqbMxgcWQdq0$v93Gwb=RIVyV$Wy^eh6N=p#y!>(w3sgE -zq|e6|-r2(y1`c@jmI{xjV=hh%LKjH6{{W!@;IfRK$PH4=2VnSN9p6cg=LBMb3a`t2 -zMLog#M+ag%G@mBfB%~@vY$tIz-@y&!!>j$q-{%W1D}cTzk9WZK9>ZeT_nwtK!+9W5 -zHr}L5t@9L06Pj&#+I+#GrMOAHCuwk=i@F}an9l$AVYxwd?dmJ-_SSWcj|>O<*o?dLUD`ticENM@=(@DSQGf`G&hhGv -z#2Z92fEhj%CrX0FAbKbf^C*BK_UlK&rbV!`w)Hk?G|pOe#!uRp%0YnmtN;Zfwo(EB -z5+3vlJ(V$ue6LyJOAX{9_iU}x)T&2zBZ_E2@2SDIJYaj?+&(Knb%|2jzdSsz{h|;I% -zjK=pwia9_iq^$nwCE~(SL#>yQbX4)}2%~8k6BYe>FemtF4oA$MoK`V>1Q80=V{~-j -zCOsj-r?o&Uo|Q(>%FjEgmpXVTd_@#4KR0+{XAO}{^snz~s6KpFhUyE*Q6a+kCBA4E -zuwC;G@C}0WhjHrz(0K5s*n@GCMy&%TTRhp0}({zizhkcqFF4vh;5185{&;Saceb58)-BH{QAj5C|GD+m=a-5$tYu -z+tjQ$uE6|?ToN6-A__2ixQpNFg)PC8O_)YiUQ2Gpi)PjMBk6vVQAyx^URtM@!Y)=U{<1k5r14%hrd_HIx&_@V+ -za54mFar2+icOiER1nEpFfP|50`=-=A%lkGh9UWFo&k4`L9-gBYuuQpPharUF)nSU! -z_6>$#P~8nlKvp={)N0k`x1Z -z5TeFyS8ht#3CBaehsQktYaCE2NT5TuNFc2J^^H{l@!+P#>u{HW*@ryg(uj -z3r`iD*&Z4hayj-B`zG9?j*_U7@6D9|LbifRJXbkGk0GJ{uNb_3vA!T=LlISI5_;TW -zHhR&3ZiD3!8xJxBKOmkVc^vKW2r>v_QT0oAg}FKbhWYV}PHvIFF!>v^gigB55I(WE -z%Fx!pl=ul85oa_aEu}pZHGMqzF{YpT^zy)y7ueX{j(~Xmn6bs_^}~=Yk)ao+s2seG -zwS%5=5MSfZB?{k344VozCbd1&`Vay4{Oc{sW=p+TPA`i^9MZFeEf};?1D7v8ou(m%;X7}CM?gltE82k` -z+irx{B6$eYK;$Np_{2IZHI~mFZtq-sHhDfDGAuzj5n|Zk3rcfoaWkx;hQ*8#i35&o -zMwC|)XAnh+zp6qS_zo`v&_3mEYjLX>49Y+1yGnkF -zl+v(sNvlmGa0RoPfO$RR=S)SnV0b>RmY#1~E@8j%G~JtG)3^t7lW$TSrkn&6l_rz$qmaO~;BDws3m4rZ8B)za)V*O%N}nrUfi -zcKk?BY~r8tKV-nMc30#?!w2SHE(W5weFnQO>m+4e$DWQ>i+{)o;RT=reW&T)SDFIN -zT}Y-Ax_1-_rrQY9w%t+QvNM}v?lFPa^l~vS3K}a1J}BTgM^VlIJ@2W9sG&=1tvi5aMa1Xea?XK)WZn -zJD#jA`X62jetwTd-D98wz|k%`pw$kpUk-DP?rkR^JU;H4x;ni*Y57~F$qy#e%>Pj6 -zh4j}>B~cH%2f4Q9%>3U{N}_s5+HFz{g2%^(l4)5fj{TsdCv&q#1=He(?3|sdVaf5( -zyCBvB>C@YKmUhGN;Ya%cXLdgz@9X3r9lheJ4i6J@^uc6SQ$b@YNRT2CNhmI*3Xt+V -zPv__aU#%fOX)YhIYMQ11&Zk>51Q3+cOZ&%@@8|a?{1cN8-$!Ho|AGAv;{#Bc!Jp9& -zjlX}G9gIKB@J|pE(&yq+_-43V<~X_3RyvP+Ngc -zCo(#JelwA1%I8|Oo)sSQl^mfJ#@q73 -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 -zkhg@e@}v{%K -zZXgU-bTLmMW47#$UrHH_!Sv?qZhp1BtPPCm1*VEPI -z4VEmt^$#D=+#|Gms%KTR5;QANOLC`IUWO!=re#D9J_wS!eZp%LoV$2mT-nGQajU7> -z;iujWY+H`}??p3iw`tMedGjvL=G?H+4z3WM20x`e415I9GctY;QAodc(=-JBWatgi -z8!dMl`LKM3h36NvPaM?D$Gf)#cDKK01;!Dq})`Qho0W2CP7GLBiu9Mao;aC)t{n%k7c}|b)|=lkxabxze6o53D^I&-K1^?Cmz42) -zB*`^i3;vI&*DLJEzHxLqsrRq$Si%o=_UCgEyRxC=9ycpY8Dc#>_$`9IX!FKPJM7=P -z_YVGN_>YnyRWFVcQl-(MReF)FSe+MuiL^FQZZo`;$qC!#f+bHb`$!W*7Z+>dhN#mM -zL$cEa3Je57uL8Ry*%6*eT=(F_em~v-iE+> -z%s0{zL`cc~L|g-=N<820@i$hgB0~aU1O1;$x55*b?@W9tJ&Kp6&77KYU$MzMEpIze -z$G*KHeHDfUAJ?@Wx}y=;HwBRIGk!Y&K6IWm{3u5j_{T?DZv_92Ltd~sLo4H$%J|!% -z2^Ev6%pt*SPVBogE7zg~Kus33)GQkhJ6kmXb7|2YZK6SrbH2D)%rS`8+aB63k7JyX -zyv)%l9b(oPHM55+46dGlxOVTmkF5o{EJfNX)1sUf21roXo2*+t6R2c5_tbH#?yv-h -zfmR+ZwisS7Mrl5vMY7}Z5$a4Hzg}EE+$`ceg^H<%4SZ+(7k-;Q&3<|u -zBMV??i+`%A-RH4>{ -z1LxR)mPa|PFU~iE_Du!p%f|d)<#h0@m3LX)2HYNecrH0amPC0{Zra@*A%IB@DplsN)QcJtr-bdudI`Vzb3o9xTVi-Vsc`Tx}t; -z$KHhb?HvaVngfi*Bp(}WZ{y{3W2!~Q`|9vh#2V#K6kUy(HnYP%UgGgD7Zz>eN+eSt -zwrYoz;0d-dY8#fc;$Ijd~`)IL*6t3$$($ -zXaD2$$86C&tfreE4W{|emi$jwAPuPhV=|lIptQk9(NlCoSj5Iv!6Msw`0CATjqfK-|Oyg-4!>G$DW2qSch!0}o0i -zG#QYg@O}j^PcEaoBFYc8F!TN+USayFoQDB|?xYG~-@J9WS&Z(ynWW~vV(DtU3r;4= -z;CXfC!Bz|iI>msXyY;qP`=cA#jkP1*J{fbPY*zaeH2@yiM!(Ai#QD+%XcNHQib`#;@JRGv -z(h!3@?_u_Y6J1B@?_~_VDY|EZF}!2vPN96P$y-8@5cx|G5SuB3I1D(vyjY*#PdE2g -ztWO?ee-&^y>!Uig(d{o`;B?O89{1YP%Wihiw$enK@ -z)`N67z&qUahc6`$i^tWU63@S$9xB8D=Mp1+hT4FvU=KV5tzkyi+wT8$$+~YBdEZLH -z81O7Y#mHe3wk?_~bc8^(pR;JW){-suwiVq-tg$|QiekNpmxC9ZdmVvTS;BsX9NfGo -zRAEAcj)S%ZJZmdT=pkTbV8X-lOnt#scGYMMLvGbO%%mx^x!_Y=S5 -z$NVu^tTVs3epvmE&_U8qKW-paz&YSzLeW!_(zVC&FgxIsCYp{qJ65AxMZLp`onkIc -zk<#*G2rk|>izcMBqEa`ad(-c)?TaICRv{|2vUfG`=!YHEZT)b|OL9ItU>eld(iJq5 -z_4U^*GkhpMXpoc?Xo#l7|5AYQe1w*^@vzj^M|9B!#BX#7A<)op2JB0zXXKeV>)i1B -zLnna{%%r$Zqs;8bX)4M@>GB21CXSh%E$=YlN&*lvZ;)5+z@M$&0`G)yd)tZuCQTM>cWddNEMWaywi-N2lt2y3hG(NajEAf$r6@GR( -zrrsX6|FJrt><~Dv%pCZ5*K%i`z&0$7?CNyM-;pTo6I_2R#|vb!xM$h~4jcV^Ma5)# -z>pwT(=H&Ohu61rnM1qI)e@xRU?dtg2&ZtoS#N271zl5@#E@QH~K`OQS`f+`^5YDb% -z^AMmiB@N+-P|Wm9PIlZ_Tb{2UFrHsGO*&4&ksA~!Ub74($Kjk&eF(`Tfi&9yymRU} -z*hd0%njL|{oFR3@1-gf)?^%f9WsLWqpj4|>OCXTXvU9;(4J>UrwxoUVGy0pKIXEJ| -z_2l*eiYjc6xLG4SFa+RF6IbyKXsh?oM3PFH_s}mSfJmfD9H$~~>8wP8*5^iMo*Nsi -z&9*sdKG7+!!1c082QR0Li4uZTJcma+r4ctE^vwIYUqMWD-_AMd=&&@k5HYZk1YWDA -zn}(_~KuD8|uxBx_fnu@B<|QV&Aqw)0Vyw8Aw)2MhQ_HV}hX1npjrO4;R519V#U`5v -zmMCq$ZYMLP{LMM!BOW>Iw&WY|eA^P^HyC?qAemh#$7*d}{rRdPeOjD|FWZxqZz -z*pxcqPPnXgyZy>5M@)cpD(jI7mTlD95qbp<7{H$%08S38+)fx4XW;E8MXwlDZcMh4* -zih7W~K_2i;nt6jr1fkB^*#`Le4%iGnn(ZvwQ*Ed` -z7+{)5W9B2_)Qv`B=)*G-K9+gNU{bPKD -zgabLij|wOTO`i;}#Joz+r@~{tbom1-CV{%3mlX#6Sb%A~k4#US2pm|@=>d+YGqML| -zkj{ILvlFT;;>$8(hnvL}GX=tZ(YZ5PgXQXK&7CtWy2s+m4Fr=@G~4g388C==z|v%y -z`GF5Mc<

Zd)a;G%OL!#miZHLSo+6k&&V*ZG_BhCpY -zB2pN~`3^EIHK)i|>L@DHUBVJ4$)a5jj({5Cw9ifoFUPP|rKA#l+)P(mpZd7y|1~c>J!O2%D&eCeI0W9uqs#qek-VJS~>{mDzb| -z491h|32L4Ay07Rs4%2vgZMy8)!qe#A3@I2cJ;mLp@r&#`B?U}ybix4DbqSe_6bb2P -z0DU_1!6!I*=N~eF&x2R_o796Ju_LX@?;ZXPPb`&^#6Ca=bpC^dpDPgDPGvZ_Td4A) -zPv_U0^=dsjxL@8b8lH+tofAjRZ-=A9?T;<`_Gz;&*i!uI%gYBDyEyrNet*LMIQj5> -zG^YQj|A^ioU9=C3Byck1ub#1mYp7l1Pcz>+#}VM13I46}*^g)yDRFoWmdHKaVy`TL -zu8ycUdU6X|d&?7TEK0)HJzuTaPVUVQP_3c9u7g3TWC3J6rY7&_)kt7q8|zbvlaP#tcuaqCk3 -z%4)t^i`w@&x?~rwLAirlyk3QFRsb`YNnaL{)m$A@V5TxEu9!>0q^zx#Pfm3FxPB@F -zrJ(QW-^=hMBL-c;2(BRS--2VqMSyaRUTQ+czJ~c&?`x3k=Trg;mQ-yv=mN5e@X^8I -ze;=0cgm7%*CDpyD*U3u9?T#4x+M9FChGFBpq~s4RZoDP0S4Ft?;K4d7=9C9dTtAgY -zGq?t*UrcYC>%|Qw8PnVpmv1M3-`kQpx1?SOyMlKM<_G^Cihv7yRl8>Yj_YK3(yIl5&RV0sP?Ma<__^o=M&~0=>gj}Z>2=%$z^OfgbPn>DSO4GwKi=L| -zcLaw{&b45=@6k+Y&u!mU&uXlp)FCb@#L%^&`U -z2gt+yRn8*+WObLNFn|6~aM&5xKeQrBSjM0h4#~o5I+Z>#C&hEDdQer<8tl_n#n5s_k9H#6YS{kDnl_?I0 -z@)7lsR2?kQodZ_6wclY?@6@^{REFW6=-Lc^$-qS=+|>bQ+^f#?h0}rBO=JW14~2WPci{)n8AwaeX#@|} -zprf~i_H){~rGJLXKAK|)U&9K5*E@rJi4Q@yvR|HE&4>IY8#1JoncVLg0cZ)Lfvxv%hii#H2 -zBmnnyrrm=YAwxn^@Sil8jg6OJW-C=A2t;ApYafgM-PLTJa0W2`xjCJBi# -z$#F5=2xqIBQi`K!-*Fkf2d_HF#h!qs(3&K)ky80n9vV<^{dBCoqlA+&I7LW=okGe$ -zF7YWgyNpiF1hT8m`nI{hUT)b&aC3zLwuyN{WNT>1*v}G`$ZrCyM9oCC?@)IF{8FWE -zrk4OlueN3wBN67P>s(Fe3s^+C0KnB;MEK@s+kw=t#LxEx4%XL7Sf`p>vYoGpF;1l@)^vTmoN_1=V0!yfbeFdNhFi1+gmtay4+ -z{&$IF#*_cK}iq!%oJBhp-Z3C-Iy@mGaD~4PJHjBn=lX3DQPrBzjai1^< -zz^z!F?C27`fWS0$M_q5LU^Bo%u79xf65R_lD9A}G_XykM)n~+A -z>69)(>as5|R~+)Xc>8)T*AMQhmx~w56|f{U^hn+L_{Day_+7^D9be&pCn)hXw=;|j -zxL-8)#Gi%K0og`vs7_#tX!J9&%;k{=G8Qi@f52G@b)A7325t-)EqzRWdKmwz!1%5! -zXdPa?vW;@+!r^;1Y1`m&CP?Bq=8`XJKV*r8KKQqfysfq&#{q*Ec?3U3rBxr0fX8|H -ztpkI_^i_^VAq{LjTaJuk+{x1f_r%3urLxkxSMBWVizR`#H*q7g?Ya&AZtBZ)GUuXq -zM{0*pQo7FH*Ju{j6|Uu3dNct` -z`H<0DD@yQ*+!T+QC~qy17%-Pe&>A2V35bE?JAzo=>x$t)8qzK!l2tIEynL!IQe2PC -z)?*DED5gS)rZd=PhuQylu&+!4y}X+IeY^Ptq?8fLzsqjnplO}x!^Rk!x2*yqC+34J -z#e~(okJ#4%C?4Vn6}5=SH$&xpkV`kH`tk<665oE7Fstt_I+cR3t6Mo?7HToukGxYqT*Gr<(;O3AFp+peY^JmZt2*_Qzvk -z5{Qgq1*x>Fkr;ZIb3#;t3H1fnzT~6SeQ3AZ#rlHRtF@dfTp)e7SHrz%;Bt_-5$6iZ -zm42YI?4nG8HytB^pY4$TG(Bc<&od}G1Gq%XnSFrf$Y|q6a3h!jwVNZVO3L$y$>QKY -zfg7|+z4Lm<8z%&Hbeg;wh3E)vqO0VlbB188=K{tf#~>!wU*Q(ormC7X2gw;ED5oLz -znI;2q{h4_yFt;V|+-$yn|K32Liv^2l)42c9JRbbN|M%wae}Dbcq#6C?sKR`^SyekE -zCkj{H)?f&D1+9b++sAkqaAfXCX8c+g-8rSmYw>Y*BabPizXsxR$|Bej -zRwFtSZ?OR$6=lroK+GvED%ov;4bUT8CXY)5_45;sc*z@M7}Cq;Eq2?`g!)v^8IOk2 -zkCGyZJfV$EGKz(~jK4!s9khZcu778BuNV$$mehsp$wr^tKIrz<78(}n;f>CQCBiSc -zjr>r9w({a(>qmHOIA%C(9t4SpFt~J%BUvn!_xFW#X=czzw(~{7a=LM3$DGrXWYp}1 -zltV21hH&(5eY2cHF+nb}<=?(Qug52V@eElKdcM&8x(3AJ$-Qm&w*U0;%p_dO7|s9; -zxz>n$w|R^vtH!9%WJaE%V!pawek99eO|XpvTX^jCrG5m}pFK?_J -zIut?D&WFNzcH3v*Q*oJ{8-r4YKHhUFQK2OIvhH)ulr)`Z-|}5-1MdGXqhpS!c*^SY -z^1lskNzZQQ*yO@-&M*6iWqH{iH@zbZ1IUyI+O4t3puTJLu -zmN9ZQYTLZNyoARCP(D1Fd$p?Oe*ODm)yT+SA;_~7J6dNLmjsuUtKhSz6JW@fPqaJM -zkuO&d47VEEze&?$SKF)g<`#|UKTzUqL3$9^&bO#kkdq7^gbQ4G{PiRc!N+DYgh+tS -zE0G^z3xxIe!R03EjT&hZJOIlHp;-{BW^%fC8qwqE(r!L=Nqts>#wXM1YwQi>L*pNo -zHNnm-Cl>HH`tejUU019N_n;Ps4Z93fe-SREJ;Ty1Tguv}@-dMckaGsS)g5ZsZ1z+0 -z?mbEDWE*>~rZ+~V43f~JRzHlP8?eVA>*z5bo5$vze;^EL8_Hf-NeQZ+Bu(Bt+|e4B -z#vNsPgu1-henb)ymo?6Ip_QL?B5tx;A@mhj&i2-I$VRqQz0mGv% -zRg2)P*+rl>h~bZ(3B9;oY`4>|3yhB0029OGymJ3ECRK(FxcqtqVgVjOFv^Rj7PMfS -zz?zFWdCZ0%iXA8&NB-cWQ348XuviRQ5Fy1(aOL!*B@HY9#O+3i6?R9_c&DM?Xt<(j -zI{5HV4=bb?T|E9O8PXzrSix~+684UK>a-!&E1`tSjttE!p=f028&*R7Y=t`ka_Mm- -z6T#RqL!Rk?q3=IphEHO}h#9i^L9=4%3lg(pD^>`Q92Tq&CUw1%NnJd6dAa(=`6bQG -z8F@nl@HMX2J~CHW7}Zv6M@a>9mNXcbiPTeQ`Y5(i#g02&veghAk@I`E=9E(R@L&Xi -zjid?V+TEsJGP9b_6 -zycu!xl6Ua31NU!!C10L;EO1q(RBVsZAz+ -zN_ucT_f!fPOy9Fj5;@(n+=iLP4Ugv6(~aG_Ganx<)>oeKChA%)BKy{e@>q6r&X3Mn -zA@F{bG}X}|sI1L&e%}x{U_kUk*Yx?A1+N+l3C}SjpH@eGTFZ=e`_B9KFOpf2>C;<< -z0e@^3h!f~F1>uOg;Pl};+BD5OfApI!gTtl2yKF&{oCtq7J72T567Q>;()Z9|G_bqG -zE>|?t3ed=VZzVq1#sf>TB!O4olNf7`X$Y2iGYO1^8Hatxvg3ea%O$DJS=_P*5dw7~ -z%%J+fL>lg=;deWX(C!>CW4F|2>jFs}v~`b4QCuw0*L5Y9Fx3Gj3-E(Tlatayd4`uK -z1#({(qB3URc6cR+ujZuoU9>Djg9h{Y?~BXko)(NEY!Ep7L&o&HvMe_em|vSu=ac5> -zC~$M^mF!7TcNFEYoN(h7I}s>e+x -zct85+q5zqv2B08QZptJQGI-+X6||E -zO%M5gyrl1IStz~o;Yv`?Q2FrP@T9?%Pm@OkP%nsXLB2pp63@<)oS!sav_Td&I&vif -zngov6`}2yvBYbe)`tMyf&V@tsDY^y3pLgsCP^0I1dB2_TTHEgK@1JP*_bY8Vq7;cK -zlJam&SFuHp7#0}c)3?WrB7b78Rf+yGv-_L;L*I2d5t*UmA~581n)-^b@|J(7R31d74;=Y-|pS>itFq6VvA_EUNT#?vn -zrMnIzpBCb>YF4V^$M^A?nkZ2`q1SqI6&X*$UOsL^{M -z_Rx2pR7(*jktV?$sbk3J!zW&h)`Q}f{inlCfZKZ^xzd<*6Yl7XWelE{?N_MQQ#_o>wj -z;YfW<BLhE@e^^R`;WA;qY(t>U;nn={64{^Dp3E@WHJ1gGV|d#pTcyi7@K40a_!_LmWE@S9oK9DMSu&WBjI2cShb( -z2v(=q2O6aOj@fK`4ANOqlxg{|kdu}%5+XC8NiG{#b0+%A^ssZ!2Vwrua!c(FplKz} -z#fp;};druKF`)caAw~J?>L1J1CDuW0v7QWy={IkhqrV);rQ_)FrVLC1n{IwI*yl4t -z=M(;kRE1PdpFA3vC{YlC8h1`|Q;x%KchknpzZke}+w4wJoiGtTn48^Omxz}nJ4<5V -zHA9e*>rqpxT{49dH3p1AWv4&iZfdY7sfM?hd^l(~&>jB+Y0mf?PYQn&VwMd%&vL82 -zEE&V?tISUvBBuuYnrSjswLgO^r~!;2)G0|r<{Cx^fnNHh(@Xa!W`YQ#Cth8rZ4ZxKNjU;o!UN){$?Hu{ybzZlj3@ -zz&b@8c#ck1;_7^!Z}wp#eh2?&W8^?f51vKMTTD8Aex3PdM!!stevJ2kIPjElnO;ea -zYc8x+B(ZHTTy6~q7UOGEMDbGs-dEmeiFD<)D=)E<_Qh<|?)lJZQ^kIepJLqTUKNuTR -z#*dYF&e2$SPR;k!+6X^}*4>kkr=8f`mlurZFX?Y!ATNjqv}4o^91mz_irp2Zj21|= -zQ-rm%sNX$NA2x{iOrjF55bv%RD+uIT>iKDMD>?$mpd!-BqqR9@gA$ft -z2{A89~7Yqf_jKz)v4 -z`9pdgQIYz-K)(ZX95D6aTMGCMT`sJ9sRh0ItE)x9ILvK3xOH#=o>h-%5;htemcazU -zD+8lJMJZHF-{8HH1QBl*r^*PW0#YfMR;#;E=+8hqWfKpN@w*;dzOgdKd(~>tqJM%= -z4>yA`9=$_-MKvc;!3KE9SFo`lFkSuWq(o&{KuiIJ5mIQw>EJw-#nx#q% -z_J&|S_}Ukn#r^eW{f}1JKzCEf0LK0lLN|x7KPoOir%GttCJ>~b^p+N&JhuJE^low% -zhJhfYlRx4f7hW|ZK#pX0Ti7z`w_sHJbzl&Nxw+jl#A#a)woLBXRKT%`?TJ8mb8)`?Qd={SX!^wirDK -zVc`pmfm$ePDni!q!(z^p{E*q~6w5ED+IU#fWyl}}0OyYl=oJj^;_Xn(inbbz{{k62 -zzr8afbDBe20z!B_M?rP{fDn5rw1%Dz!Lfa8rk9rxH(oWgV%CC?-Z>6I*A#s-G@XIl -zd4d7!Sd~+(l3h<=U>0z)ncA7xZiRxvaJcYbb1I8Dx}B9u5SKUc4BMlA`l -zdyS@TDPeA6Xk;Ps)kT)fR3$g~qL+PMqeR8>zmcY> -z5HL$B7%HHD0#VHqSeslo6R8T1?@5ti$G~}vL0MHjVpTOsaRSx>R-i;rFw(qH3}Eor -z_08o1vqubehXxAj9x|d5TrP_DYv8|Hx$bcw`(?_@Ew)riu1+^^+vp3^E%XT|UUXgJwR3bPkb1 -zpKUh&P8y02-$!Ho|AGAvOe^J_kZLv!q&N0ESbK5uIK6pTjAPJ5$N_G0Q -znLXUz+2dA0ZwJ?xoMvKpQ%LSLpWUuqqN@@vYl%#3q?Yz -z0MDPDuXqWI!*R)Nu(tv1Smw&i(PjK~z4>9{u@bm?+(+VZ(tWXt(2EY8apsOFxrE3c -zS`Hyf2ohth_SKr6w)gAx!G-7y#Aq&vgtq~ZLqqYfQ-B+*p&lk}?bZ?o{%qms>+0Q& -z{?3u5m{XEbHwJasX8wKJT$vpREn_6>a^f5&wd1Of>K8-EK-=1qVgAWSz*mX#tcUT1 -zb6Dm907JT%u5wOWT!oW@#Z~5&st6!e(=xw^>sD3`AiS|yo<}jknGLPwM^6W70ktw8 -zu>qP@}It$E<~)}k=8FsOlRB>nS5jYrp!Z58l1*VpE;}plWgiT -z(f#a`LnwB@ITCqvVlfU02ErI{;0iKtJ1&sa1}*1{ngthS?D(VhZzxhu=W|TYo1B%T -zmrBZV94rbLf03z?utmrSDG*;TZZM%?^5NS7h-|)D;(AbNVhzn{^BZSx@9+!9my4_E -z!_7T7Dssvko+J&#f+iuGDXFtr9v!OY;^FQFKAVP^{T&AX4rv+IW}39`LQjxFlkg8= -zZEi2of6)0cdbMH%#yA%lr2yb2UzdA>`P&&Z;Z&WfW?wU%m7%OzHEfGh&G1IM#FCD# -z4V(VVtW%|I0Hzd|f28}C4nq Y0OrPPoHo=*B{Mq|meTOrZb{7dIl%DDm2obF`Ku=+S}}m&K>yXNsafkC4W;$W -z!@~SQ53d{ais&#HOBV$8^V)^J4xf4ovJM}PojpEHPr34aKBb8rr%zm5>-3{YkBKUa -zt2bQQ+@RqXk!5OlSn*x?yse0)bsIBiHp}~Wo8HOBB!efa0xYlBxndjO+o|D6bh$0u80XU7;T2s8On7G38nH*{6-9=Z$TRwt^Z1eb=_LoeNq$pSrru``gBV2ICk -zb2VMwJZu(dBSwku5U=m>7W=}vuNZ$o_r4dVBS=N_-UJtl`^!Mu0;yDy4u>fh -zSQ_}O%p5QTe=a4r4nBB#9b*3fTGQLrMDh5b*01NXSlyp#JOmtOxWK|P5kY8ErWkS< -zbK=$Bnz)W4J~R_QZYmzjbtlx%KSyTLO@b*36aO(fwd*-C_zKe>R`0}HH!Jh;j@MOiDG;Tm>uCHME%Ih1S -zT>!0e>j!=hni85V+1#!l7tM4+{Yht-BY8%!4OAi^Eq>HJ*_zY<*K1=1oj{}Z!Dtl> -z_@;S+FrU^1SewOlP)3B5m-iJ$w~YNAM7fU#^y{H=Ed6?Rht23{1F7%w7E^y)QArKU -zQhZAVJlT%Z$DQEG6eS*mvS&`l_Mbg#TASdkCcH8E3owp_$3v3^D$5V`Q*6oB!prj` -z5w$dUNq*G&ul`=)X4-c>RLfmsASDtf@h+;a8!u~L@1nxYgHfld_WIv-%%IOb_MG*t -z+Bf+ExMD;`BSwmUT6bwgaI~Jh!u7v%KTms`^5;j~zpr{85P{Rc55VS;C-u{wILkxe -zELCzkI=1K?+o(2xsYQpsF^l|s=4)%#!H!PS=X -z;02}N2vhN8jy==ZKQrw~i8))OC7JWprWtBY$+v95iq>Nvj#!4}Ww$GNeI(gAe{FA8 -z5=W_K;Sza!*+|w6#)2Mug+c%sR*?t8LGTBE(b$kPuu4q3boSLAShZO$!!0?56fHgk -zpVt*|MR+%~3WBq$htoSZ>SrhM9l(A5PH$u**z3d56aK9BHwCx3XEzNxAEqdX~u=4AayC*t42ir9ee|3lF1Z82Wy^Kvk{n2TM -zXsQ>)RG8|;rx|(Xj_W13<%D)ja0SyWnt0QIoi}{A0>5I=Kq*;w03seFJHc}vIqHJB -z7urIBc-vs!bwByY58U^!I-A~rMcYPRBZl8<0=#3pkPU6q7*dX>&kDR90gWw>CeIN* -zTd@-#*Ahx5T;jKM5@b&t5A6IpZEWMG)#HJP?Vbu+^~DD3co%YgPHVYqBXh1F5!Ygs -z3Nm9)hn`BO%?U{k?R1^wr+8_~eEbqSdwD^R#cUa_P7N<9?>1Dzn|gf%XBK+iE%MH> -zyUEq}yv3*2+FDb1Sb2TM(`77MDPjlDR|g#?pR2&^aExa7Enzrsn8_ys1X?y(mo^lo -zo5_@N??P-NB+cuvEq}2a(#O~6V9y|ZI~Ya0?|&qh#U6ei?^!K5Hr6)q()+M6e8EZFQnC`dA<74Tu$$& -zltg#O$ah?nKeWMh03PI<;!WBo=#P5hUo|wJLwGTYvQ5*Dqwb#fs1&1Hz9GBtsolQr -z9-b}pK9K_=dy0SoB4*U`ZB(o;7OUwDiuiVyH??4+#(K?r=ujM6KWwnZmH!^k1Ap07 -zz8+eD-F^z95j5kX>_yxiloe|R&^yOBC~a9SQb#cS>MnS7knG3=#k(3vbeW%c3fMaig5HZ -zh-jqShA;*!DgdUE8Cuc1jG}V~B9r%{nt<9YYGm&c3q9-J$e(Kb0$!G*CeqZJxn_sG}gg< -zD(-!`#@LMIKNmJxs3->+UPZtVy+6O$n$PrfrvplhBrt?xfk7wuH+Ym{DIJMn`GT(} -zo^&CMUD@dfLeN)dj9sac?m;V(M%&xgSEKH`T5MSEFM&}hc3_NlMCup6Cl9YHTM~hp -zRzFJr`biwJ^MkY#?mhKTk8!Gq^U%;9v}|XWkLRi)2&}iZpMg1cf}_BR^p~C>OC=>m -z3uD@HeJ}MNxhXqzbD!dxR6ubD(x2mhTu)J<>9|5h#BFu@bUph97{$=NttgAY>Kx;s -z&~HiJ2oc00w!pXPFIAnajY6 -zRp!Bu@Hmpi!bhqjBJo(^o`y&vX_AbcYc=NDC_X3&SHl;Vkm!VJze7y7r;93$2P0sk -z>!JpT=Z>s+PTJvA-YB$38FCD1VVLkpvogZ0iQl@@hEGNIN3D{!-+~BUmpz9)+`;z; -zEfVNE+;emre-U{#y_ldQj~cx(C)jxqi`8wXH-0|d_xA$!bB$%`Sn0|_#s7&8cxMh$ -zVP(mi!zcaBpN1w?Rk<54o?=~Y6WRu1^9D=0xjF9Ruj`7nRub3 -zpeE=stcX(j7jZQ%EXGm$J^5-wJ1nmzf8TCC0pr#dDs(dL@}-;`E$a`7Q8?0gN#KyI6UX -z2OQ2^eTfqIS^#PT@|mev4uAbB?uL!kJRI3m#74)%`&w;AkyV4pH%1n?y?!ICX-h5Z -zV31_v;pH3PSunKQL_g{`qcV@}X(}G8@O5`N0|NE7n#f$2&rTo{6i+dE`zXpA!y}Ye -zIZ1TkZ_m{xX2VxGk@peDvY&GX(yt0@b>{``P~N~z6#R5=8qyOLP)^_L@O?&+DDBUw -z$Gg=a_j{$NYu94X!Ce}@%8g?NqT{vH`MM{N&U3#yyvev=FYKdMi -z-jd!wVH%APRLra_Q_B+K=LnsilMl?UX)6}OE<<_(U>(wsGAp2v4uX4HO?XLvJUuiZ{igo6Delgz*Bg9EiJg_I%8 -z3~m8bz@Ua%$RMR*)`@p}f*8Lrv;X0HRTS>gE!K6NZ_l^hn?B^;7vk6!n=R5jOz5Y1 -zx7)>PyS!f_LBbRlMj57e`aS(VJwnrigLqv>J!&8>;W;87XKO={>;Tlgrk4m%hX^lN -z?{&kcL}J~^?E}^VLZ6mXip@h -zcwi{_FA1)y@i8^w)`_29KwR*T>E;qO_F7QK=T-rAh$bGW!{=&@LjXbW-t;&$f1HW4 -zt+r|ZOm}T~|MWUW@3Wl;u|p4p-OEb4a@@K*(#iKdIs)Gfz10%Ms>SpcngDzb;Wm`ErS}wPvxPThK`K7B=fRG@XitQ^He&5%e#BZ_%}BT% -zr$g-as0AR(AdVs -zd4#oWq391;kIP2o=WiNu{TLG0@%s*F5~sR)uI4IWxPBv1f5Ce^r~jfVr9Kk%znQai -z=5jjc6F3@ie3yU03{n{*Lg#iQk>CCi6I8XaTz#q?kHZ`cZ>$2*XK$>?16VBrUr*m4?%JF4$1xJQ3fycJMk^u -z%Hj(%zFUt+h!GjO;FxI=nu&CA{jmBS1Lk-q7{2ukY#-TY5cc5t|I>ThY+HGsdSc2f -zi`=<;WAx$)S2tfD1l9@GCM@s;K82k~{xGVC$9XPmNAc_8zwg6dl~Og(p>%U)rujcgI~knXXgfImaP7xF>*U`jOv^>dU+{(f4-`Qn$FTGA*R%y@p;3)_Fv#5miMrWI0B?-QqOeLEGg#1 -zy@emaYc|q$@?G!EWOLO+1>r}Ja^h6dhnK9g$caMBJt0ee(Q3RryN$L1MS;;bMM|f` -zDS7PCAT-L-@I11yV&O_m1nxF~(cc(?cO%Ss(vH1^b3S$iBDsyA)Pb_4g@>@)Vw#xz -zs+uDc?mEFJZKPXR5rBB;5o0hgP6M;Yhb}+=g5i{GiKXIR;$sq{^<8sbUn6IBjF$vy -zaHxv!pqn53{Jp8z1M7%P=qZ#_P)7`sZXTma3irS@1n~&9e49M)cZ_CX3v&L7YSkI^ -zR@zxz?a*>}ss_W(+ADC36cvS2JYQPOsHa#*02_|xYlZ8z_<}Mai!c1npICD7%X?Xr -zip`RN=l_giMalQEb?;%%rNhj$`^u2;7r&{PrYh?y=7(?I=m}+??lB9CbKX?N5Q(>&M8NT!=mLJl(&Y&QTt9bb^U%_l<(U -z0As6O_z4-~_xXYs#0oFUD5N+)8ivJFrpdZ?7-56Sws6p$dz+%<>w9tJfmGzn -z;w!4bi;XM^kY6Q3a6?q+uHfd;L}d!Y*#5bCz!u@}qlm#!F-qu8(g%SnD>Nzu1vb#r -zck7$w99R#QX%pw*Q~G*Q>)DWqc(jLL23w4xNqp2dMrT{9l{pFV_4sIuB&0J@F@ia}rp^_jCaTzmS^=@*;0SYk>+XmL# -z2ISo8c73@Z`3=EM@V%JT09$v*fBQOwZ)kt}WpPhq -zgyh(J*iKtDVl0BNyNEmYcW*m~G?zE*>uK+NMTn4`W_eV&5WT0{9|%9Uqtma8)nWr} -z(i|@CD;CS~Q+-aNg`tQY8k_4(3qT-iC@aR8a3@;nR;pq#>5g4TGhC|G$ES4;VLF_+ -zbib&8$S`!D$AIp8B9->U -zSG%&{(W9C}*HiRd7OvzkRXyF^oH{ikKVOSSpzV&dC=gLS;8`twEChDOzRUL*YjN<@ -zQ(By-YTkYCt}s&mjWRQc5sY%RC$wP~$}g%t1n(v=$laYg>YPJ;hhH4^U=pvO{w$KA -zlIO(Dv~0T@Le`gUrvg%A&m3RLXk-94O)fOk7V%G=!5`d1534d&Yy5)+saVQO#cwL4 -zzr|R(v*`w+Ti|o#VfZ6*Os6QIr)DGSFjd38R!`*TIFEjkqrGlRMLMD>)4-u{d4Zi( -zVK`3vJTKQx|AOlG%jVti4iHG`B<}o7DTW)!)ono!P6)9*wQ;_BI>Vn@J&b -E59O{Bxc~qF - -literal 0 -HcmV?d00001 - -diff --git a/app/lte_test_user/ue_lte_user.conf b/app/lte_test_user/ue_lte_user.conf -new file mode 100644 -index 0000000..27d5676 ---- /dev/null -+++ b/app/lte_test_user/ue_lte_user.conf -@@ -0,0 +1,42 @@ -+#=============================================================================== -+# Brief : MIH-User configuration file -+# Authors : Carlos Guimaraes -+# Bruno Santos -+#------------------------------------------------------------------------------- -+# ODTONE - Open Dot Twenty One -+# -+# Copyright (C) 2009-2012 Universidade Aveiro -+# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+# -+# This software is distributed under a license. The full license -+# agreement can be found in the file LICENSE in this distribution. -+# This software may not be copied, modified, sold or distributed -+# other than expressed in the named license agreement. -+# -+# This software is distributed without any warranty. -+#=============================================================================== -+ -+## -+## User id -+## -+[user] -+id = user_ue -+ -+## -+## Commands supported by the MIH-User -+## -+commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete -+ -+## -+## Port used for communication with MIHF -+## -+[conf] -+port = 1635 -+ -+## -+## MIHF configuration. For the default demonstration leave as is. -+## -+[mihf] -+local_port = 1025 -+ -+ -diff --git a/app/lte_test_user/ue_lte_user.cpp b/app/lte_test_user/ue_lte_user.cpp -new file mode 100644 -index 0000000..896958f ---- /dev/null -+++ b/app/lte_test_user/ue_lte_user.cpp -@@ -0,0 +1,1399 @@ -+//============================================================================== -+// Brief : MIH-User -+// Authors : Bruno Santos -+//------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2012 Universidade Aveiro -+// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//============================================================================== -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+// Definition of the scenario to execute -+#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -+//#define SCENARIO_1 // Sequentially activate and deactivate each resource -+//#define SCENARIO_2 // Activate all resources, then deactivate all resources -+#define NUM_PARM_REPORT 10 -+ -+/////////////////////////////////////////////////////////////////////////////// -+// The scenario coded in this MIH-USER demo is the following -+// +--------+ +-----+ +---------+ -+// |MIH_USER| |MIH-F| |LINK_SAP | -+// +---+----+ +--+--+ +----+----+ -+// | | | -+// ... (start of MIH-F here) ... ... -+// | |---------- Link_Capability_Discover.request --------X| -+// ... (start of LINK_SAP here) ... ... -+// | |<--------- Link_Register.indication -----------------| -+// | |---------- Link_Capability_Discover.request -------->| -+// | |<--------- Link_Capability_Discover.confirm ---------| -+// | | | -+// ... (start of MIH USER here) ... ... -+// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -+// | | | -+// |---------- MIH_Capability_Discover.request --------->| | -+// |<--------- MIH_Capability_Discover.confirm ----------| | -+// | | | -+// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -+// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -+// | | | -+// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -+// | (POWER UP + SCAN) | (POWER UP + SCAN) | -+// ... ... ... -+// | | | -+// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -+// | | | -+// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -+// | | RRC Connection Reestablishment notification) | -+// | | | -+// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -+// | | | -+// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -+// | | (RRC Connection reconfiguration notification) | -+// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -+// | | | -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -+// | (Success) | | -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -+// ... ... ... -+// etc etc etc -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+static const char* const kConf_MIH_Commands = "user.commands"; -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+namespace po = boost::program_options; -+ -+using odtone::uint; -+using odtone::ushort; -+using odtone::sint8; -+ -+odtone::logger log_("[mih_usr]", std::cout); -+ -+/////////////////////////////////////////////////////////////////////////////// -+ -+//----------------------------------------------------------------------------- -+void __trim(odtone::mih::octet_string &str, const char chr) -+//----------------------------------------------------------------------------- -+{ -+ str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -+} -+//----------------------------------------------------------------------------- -+template std::string StringOf(T object) { -+//----------------------------------------------------------------------------- -+ std::ostringstream os; -+ os << object; -+ return(os.str()); -+} -+//----------------------------------------------------------------------------- -+std::string getTimeStamp4Log() -+//----------------------------------------------------------------------------- -+{ -+ std::stringstream ss (std::stringstream::in | std::stringstream::out); -+ struct timespec time_spec; -+ unsigned int time_now_micros; -+ unsigned int time_now_s; -+ clock_gettime (CLOCK_REALTIME, &time_spec); -+ time_now_s = (unsigned int) time_spec.tv_sec % 3600; -+ time_now_micros = (unsigned int) time_spec.tv_nsec/1000; -+ ss << time_now_s << ':' << time_now_micros; -+ return ss.str(); -+} -+//----------------------------------------------------------------------------- -+std::string status2string(odtone::mih::status statusP){ -+//----------------------------------------------------------------------------- -+ switch (statusP.get()) { -+ case odtone::mih::status_success: return "SUCCESS";break; -+ case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; -+ case odtone::mih::status_rejected: return "REJECTED";break; -+ case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; -+ case odtone::mih::status_network_error: return "NETWORK_ERROR";break; -+ default: return "UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; -+ case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; -+ case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; -+ case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; -+ case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; -+ default: return "DN_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -+//----------------------------------------------------------------------------- -+ switch (reasonP.get()) { -+ case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; -+ case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; -+ case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; -+ case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; -+ default: return "GD_REASON_UNKNOWN"; -+ } -+} -+//----------------------------------------------------------------------------- -+std::string evt2string(odtone::mih::mih_evt_list evtP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; -+ if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; -+ if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; -+ if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; -+ if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; -+ if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; -+ if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; -+ if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; -+ if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string link_type2string(const odtone::mih::link_type& lt) -+//----------------------------------------------------------------------------- -+{ -+ switch (lt.get()) { -+ case odtone::mih::link_type_gsm: return "GSM"; break; -+ case odtone::mih::link_type_gprs: return "GPRS"; break; -+ case odtone::mih::link_type_edge: return "EDGE"; break; -+ case odtone::mih::link_type_ethernet: return "Ethernet"; break; -+ case odtone::mih::link_type_wireless_other: return "Other"; break; -+ case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; -+ case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; -+ case odtone::mih::link_type_umts: return "UMTS"; break; -+ case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; -+ case odtone::mih::link_type_lte: return "LTE"; break; -+ case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; -+ case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; -+ case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; -+ default: break; -+ } -+ return "Unknown link type"; -+} -+//----------------------------------------------------------------------------- -+std::string link_addr2string(const odtone::mih::link_addr *addr) -+//----------------------------------------------------------------------------- -+{ -+ if (const odtone::mih::mac_addr *la = boost::get(addr)) { -+ return la->address(); -+ } -+ else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d") % plmn % la->_cell_id); -+ } -+ else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { -+ char plmn[16]; -+ sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); -+ return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); -+ } -+ else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { -+ return la->value; -+ } -+ return "null"; -+} -+//----------------------------------------------------------------------------- -+std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -+//----------------------------------------------------------------------------- -+{ -+ char buffer[256]; -+ int index = 0; -+ -+ index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); -+ index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string link_id2string(odtone::mih::link_id linkP) -+//----------------------------------------------------------------------------- -+{ -+ std::string s; -+ s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ switch (ip_addrP.type()) { -+ case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; -+ case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; -+ default: s = "Unkown type "; -+ } -+ s += ip_addrP.address(); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -+//----------------------------------------------------------------------------- -+ char buffer[128]; -+ std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); -+ return buffer; -+} -+//----------------------------------------------------------------------------- -+std::string ip_proto2string(odtone::mih::proto ip_protoP) { -+//----------------------------------------------------------------------------- -+ switch (ip_protoP.get()) { -+ case odtone::mih::proto_tcp: return "TCP"; -+ case odtone::mih::proto_udp: return "UDP"; -+ default: break; -+ } -+ return "Unknown IP protocol"; -+} -+// TEMP : next 2 functions are commented to restore flow_id as a uint32 -+// full structure will be updated later -+/*//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::flow_id flowP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ odtone::mih::ip_tuple ip; -+ ip = flowP.src; -+ s = "SRC = " + ip_tuple2string(flowP.src); -+ s += ", DST = " + ip_tuple2string(flowP.dst); -+ s += ", PROTO = " + ip_proto2string(flowP.transport); -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -+//----------------------------------------------------------------------------- -+ if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(res->fid); -+ } -+ else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { -+ return flow_id2string(flow->id); -+ } -+ return "null"; -+}*/ -+//----------------------------------------------------------------------------- -+std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -+//----------------------------------------------------------------------------- -+{ -+ switch (resultP.get()) { -+ case odtone::mih::link_ac_success: return "SUCCESS"; break; -+ case odtone::mih::link_ac_failure: return "FAILURE"; break; -+ case odtone::mih::link_ac_refused: return "REFUSED"; break; -+ case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; -+ default: break; -+ } -+ return "Unknown action result"; -+} -+//----------------------------------------------------------------------------- -+std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ -+ s = link_id2string(link_act_reqP.id); -+ -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; -+ if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; -+ -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; -+ if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; -+ -+ s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; -+ return s; -+} -+//----------------------------------------------------------------------------- -+std::string net_type_addr_list2string(boost::optional ntalP) { -+//----------------------------------------------------------------------------- -+ std::string s; -+ std::ostringstream stream; -+ odtone::mih::net_type_addr net_type_addr; -+ -+ for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) -+ { -+ net_type_addr = boost::get(*i); -+ stream << net_type_addr; -+ if (i != ntalP->begin()) { -+ stream << " / "; -+ } -+ } -+ s = stream.str(); -+ return s; -+} -+ -+ -+ -+/** -+ * Parse supported commands. -+ * -+ * @param cfg Configuration options. -+ * @return An optional list of supported commands. -+ */ -+boost::optional parse_supported_commands(const odtone::mih::config &cfg) -+{ -+ using namespace boost; -+ -+ odtone::mih::mih_cmd_list commands; -+ -+ std::map enum_map; -+ enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; -+ enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; -+ enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; -+ enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; -+ enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; -+ enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; -+ enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; -+ enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; -+ enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; -+ enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; -+ enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; -+ -+ std::string tmp = cfg.get(kConf_MIH_Commands); -+ __trim(tmp, ' '); -+ -+ char_separator sep1(","); -+ tokenizer< char_separator > list_tokens(tmp, sep1); -+ -+ BOOST_FOREACH(std::string str, list_tokens) { -+ if(enum_map.find(str) != enum_map.end()) { -+ commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); -+ } -+ } -+ -+ return commands; -+} -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * This class provides an implementation of an IEEE 802.21 MIH-User. -+ */ -+class mih_user : boost::noncopyable { -+public: -+ /** -+ * Construct the MIH-User. -+ * -+ * @param cfg Configuration options. -+ * @param io The io_service object that the MIH-User will use to -+ * dispatch handlers for any asynchronous operations performed on the socket. -+ */ -+ mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); -+ -+ /** -+ * Destruct the MIH-User. -+ */ -+ ~mih_user(); -+ -+protected: -+ /** -+ * User registration handler. -+ * -+ * @param cfg Configuration options. -+ * @param ec Error Code. -+ */ -+ void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); -+ /** -+ * Default MIH event handler. -+ * -+ * @param msg Received event notification. -+ * @param ec Error code. -+ */ -+ void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ /** -+ * MIH receive message handler. -+ * -+ * @param msg Received message. -+ * @param ec Error code. -+ */ -+ void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+ void send_MIH_User_Register_indication(const odtone::mih::config& cfg); -+ -+ void send_MIH_Capability_Discover_request(void); -+ void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); -+ void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Event_Unsubscribe_request(void); -+ void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); -+ void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); -+ -+ void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); -+ void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); -+ void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+ void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); -+ void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); -+ -+private: -+ odtone::sap::user _mihf; /**< User SAP helper. */ -+ odtone::mih::id _mihfid; /**< MIHF destination ID. */ -+ odtone::mih::id _mihuserid; /**< MIH_USER ID. */ -+ -+ odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ -+ odtone::mih::port _mihf_lport; /**< MIHF local port number */ -+ -+ odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ -+ odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ -+ -+ odtone::mih::link_ac_type _last_link_action_type; -+ odtone::uint _current_link_action_request, _nb_of_link_action_requests; -+ odtone::uint link_threshold_request, link_measures_request, link_measures_counter; -+ odtone::mih::link_id rcv_link_id; -+ -+ static const odtone::uint _max_link_action_requests = 4; -+ odtone::uint _num_thresholds_request; -+ -+ void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); -+ void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); -+ void receive_MIH_Link_Up_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Down_indication(odtone::mih::message& msg); -+ -+ void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); -+ -+}; -+ -+//----------------------------------------------------------------------------- -+mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) -+ : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), -+ _last_link_action_type(odtone::mih::link_ac_type_none), -+ _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); -+ _mihuserid.assign(user_id.c_str()); -+ -+ odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); -+ _mihfid.assign(dest_id.c_str()); -+ -+ odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); -+ boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); -+ if (ip.is_v4()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); -+ _mihf_ip = ip_addr; -+ } else if (ip.is_v6()) { -+ odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); -+ _mihf_ip = ip_addr; -+ } -+ -+ _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); -+ -+ //_nb_of_link_action_requests = NB_OF_RESOURCES; -+ if (_nb_of_link_action_requests > _max_link_action_requests) { -+ _nb_of_link_action_requests = _max_link_action_requests; -+ } -+ -+ _link_id_list.clear(); -+ _subs_evt_list.clear(); -+ link_threshold_request = 0; -+ link_measures_request =0; -+ link_measures_counter =0; -+ log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); -+ -+ // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F -+ mih_user::send_MIH_User_Register_indication(cfg); -+} -+ -+//----------------------------------------------------------------------------- -+mih_user::~mih_user() -+//----------------------------------------------------------------------------- -+{ -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH-User register result: ", ec.message(), "\n"); -+ -+ // -+ // Let's fire a capability discover request to get things moving -+ // -+ mih_user::send_MIH_Capability_Discover_request(); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ case odtone::mih::indication::link_detected: -+ mih_user::receive_MIH_Link_Detected_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_up: -+ mih_user::receive_MIH_Link_Up_indication(msg); -+ if (_num_thresholds_request == 0) { -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ _num_thresholds_request += 1; -+ } -+ break; -+ -+ case odtone::mih::indication::link_down: -+ mih_user::receive_MIH_Link_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_going_down: -+ mih_user::receive_MIH_Link_Going_Down_indication(msg); -+ break; -+ -+ case odtone::mih::indication::link_handover_imminent: -+ log_(0, "MIH-User has received a local event \"link_handover_imminent\""); -+ break; -+ -+ case odtone::mih::indication::link_handover_complete: -+ log_(0, "MIH-User has received a local event \"link_handover_complete\""); -+ break; -+ -+ case odtone::mih::indication::link_parameters_report: -+ //log_(0, "MIH-User has received a local event \"link_parameters_report\""); -+ mih_user::receive_MIH_Link_Parameters_Report(msg, ec); -+ /*if (link_threshold_request == 0){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ link_threshold_request =1; -+ } else if (link_threshold_request == 1){ -+ link_measures_counter ++; -+ // Stop measures after 5 reports -+ if (link_measures_counter == NUM_PARM_REPORT){ -+ mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); -+ } -+ }*/ -+ break; -+ -+ case odtone::mih::indication::link_pdu_transmit_status: -+ log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); -+ break; -+ -+ case odtone::mih::confirm::link_configure_thresholds: -+ mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); -+ break; -+ -+ default: -+ log_(0, "MIH-User has received UNKNOWN local event"); -+ break; -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ if (ec) { -+ log_(0, __FUNCTION__, " error: ", ec.message()); -+ return; -+ } -+ -+ switch (msg.mid()) { -+ -+ case odtone::mih::confirm::capability_discover: -+ mih_user::receive_MIH_Capability_Discover_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_subscribe: -+ mih_user::receive_MIH_Event_Subscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::event_unsubscribe: -+ mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); -+ break; -+ -+ case odtone::mih::confirm::link_actions: -+ mih_user::receive_MIH_Link_Actions_confirm(msg); -+ break; -+ -+ default: -+ log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); -+ break; -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); -+ odtone::mih::link_det_info ldi; -+ odtone::mih::link_det_info_list ldil; -+ odtone::mih::link_det_info_list::iterator it_ldil; -+ odtone::mih::link_id lid; -+ -+ msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); -+ for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { -+ ldi = *it_ldil; -+ log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); -+ log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); -+ log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); -+ log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); -+ log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); -+ log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); -+ -+ } -+ // Display message parameters -+ // TODO: for each link_det_info in the list {display LINK_DET_INFO} -+ -+ // send Link_Action / Power Up -+ lid.type = odtone::mih::link_type_lte; -+ lid.addr = ldi.id.addr; -+ //send_MIH_Link_Action_Power_Up_plus_scan_request(lid); -+ log_(0, "MIH_Link_Detected.indication - End\n"); -+} -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::link_action_list lal; -+ odtone::mih::link_action_req link_act_req; -+ //struct null n; -+ -+ link_act_req.id = link; -+ link_act_req.action.type = odtone::mih::link_ac_type_power_up; -+ link_act_req.action.attr.clear(); -+ link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); -+ -+ link_act_req.ex_time = 5000; // in ms -+ -+ lal.push_back(link_act_req); -+ -+ m << odtone::mih::request(odtone::mih::request::link_actions) -+ & odtone::mih::tlv_link_action_list(lal); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); -+ -+ log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+// odtone::mih::tlv_old_access_router oldAR; -+ -+ msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -+// & odtone::mih::tlv_old_access_router(oar); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Up.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id link; -+ boost::optional addr; -+ odtone::mih::link_dn_reason ldr; -+ -+ log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_old_access_router(addr) -+ & odtone::mih::tlv_link_dn_reason(ldr); -+ -+// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ //Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -+// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Down.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); -+ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_gd_reason lgd; -+ odtone::mih::link_ac_ex_time ex_time; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_time_interval(ex_time) -+ & odtone::mih::tlv_link_gd_reason(lgd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - Time Interval:", (ex_time/256)); -+ log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); -+ -+ log_(0, "MIH_Link_Going_Down.indication - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id link; -+ odtone::mih::link_param_rpt_list lprl; -+ -+ msg >> odtone::mih::indication() -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_link_param_rpt_list(lprl); -+ -+ log_(0, ""); -+ log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, "MIH_Link_Parameters_Report.indication - End"); -+} -+ -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ boost::optional supp_cmd = parse_supported_commands(cfg); -+ -+ m << odtone::mih::indication(odtone::mih::indication::user_register) -+ & odtone::mih::tlv_command_list(supp_cmd); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); -+ -+ log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Capability_Discover_request(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ m << odtone::mih::request(odtone::mih::request::capability_discover); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional ntal; -+ boost::optional evt; -+ boost::optional cmd; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_net_type_addr_list(ntal) -+ & odtone::mih::tlv_event_list(evt) -+ & odtone::mih::tlv_command_list(cmd); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ if (cmd) { -+ log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); -+ } -+ if (ntal) { -+ log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); -+ //Store link address -+ for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -+ { -+ rcv_link_id.addr = i->addr; -+ rcv_link_id.type = boost::get(i->nettype.link); -+ } -+ } -+ log_(0, ""); -+ -+ // -+ // event subscription -+ // -+ // For every interface the MIHF sent in the -+ // Capability_Discover.response send an Event_Subscribe.request -+ // for all availabe events -+ // -+ if (ntal && evt) { -+ _subs_evt_list = evt.get(); // save the list of subscribed link events -+ for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { -+ if (i->nettype.link.which() == 1) -+ { -+ odtone::mih::link_tuple_id li; -+ -+ li.addr = i->addr; -+ li.type = boost::get(i->nettype.link); -+ _link_id_list.push_back(li); // save the link identifier of the network interface -+ -+ mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); -+ } -+ } -+ } -+ -+ log_(0, "MIH_Capability_Discover.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ m << odtone::mih::request(odtone::mih::request::event_subscribe) -+ & odtone::mih::tlv_link_identifier(li) -+ & odtone::mih::tlv_event_list(evt); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ -+ "\\nLink="+link_id2string(li).c_str()+ -+ "\\nEvent list="+evt2string(evt).c_str()+ -+ " --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); -+ -+ log_(0, "MIH_Event_Subscribe.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ odtone::mih::link_tuple_id link; -+ boost::optional evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); -+ //log_(0, "TEMP : Resource scenario deactivated\n"); -+ -+ log_(0, "MIH_Event_Subscribe.confirm - End\n"); -+ mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); -+ -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(void) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::link_tuple_id li; -+ -+ // For every interface the MIH user received in the -+ // Capability_Discover.confirm, send an Event_Unsubscribe.request -+ // for all subscribed events -+ for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -+ li.type = i->type; -+ li.addr = i->addr; -+ mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); -+ } -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ -+ m << odtone::mih::request(odtone::mih::request::event_unsubscribe) -+ & odtone::mih::tlv_link_identifier(li) -+ & odtone::mih::tlv_event_list(evt); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ -+ "\\nLink="+link_id2string(li).c_str()+ -+ "\\nEvent list="+evt2string(evt).c_str()+ -+ " --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); -+ -+ log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ odtone::mih::link_tuple_id link; -+ boost::optional evt; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_identifier(link) -+ & odtone::mih::tlv_event_list(evt); -+ -+ if (evt) { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ "\\nEvent list="+evt2string(evt.get()).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } else { -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ "\\nLink="+link_id2string(link).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ } -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -+ if (evt) { -+ log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); -+ } -+ log_(0, ""); -+ -+ log_(0, "MIH_Event_Unsubscribe.confirm - End"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::link_action_list lal; -+ odtone::mih::link_action_req link_act_req; -+ -+ link_act_req.id = link; -+ link_act_req.action.type = type; -+ -+ _last_link_action_type = type; -+ -+ // Initialize resource parameters -+ odtone::mih::resource_desc res; -+ -+ res.lid = link; // Link identifier -+ res.data_rate = 128000; // bit rate -+ res.jumbo = false; // jumbo disable -+ res.multicast = false; // multicast disable -+ -+ odtone::mih::qos qos; // Class Of Service -+ qos.value = 56; -+ res.qos_val = qos; -+ res.fid = 555 + _current_link_action_request; -+ -+// // Flow identifier -+// res.fid.src.ip = _mihf_ip; -+// res.fid.src.port_val = _mihf_lport; -+// -+// if (mih_user::_current_link_action_request == 0) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 1) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -+// } -+// else if (mih_user::_current_link_action_request == 2) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -+// res.multicast = true; -+// } -+// else if (mih_user::_current_link_action_request == 3) { -+// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -+// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -+// } -+// res.fid.dst.port_val = 1235; // DUMMY -+// res.fid.transport = odtone::mih::proto_udp; -+ -+ link_act_req.action.param.param = res; -+ -+ link_act_req.ex_time = 0; -+ -+ lal.push_back(link_act_req); -+ -+ m << odtone::mih::request(odtone::mih::request::link_actions) -+ & odtone::mih::tlv_link_action_list(lal); -+ m.source(_mihuserid); -+ m.destination(_mihfid); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); -+ -+ log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); -+ log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); -+ log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -+//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); -+ log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); -+ -+ log_(0, "MIH_Link_Actions.request - SENT\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); -+ -+ odtone::mih::status st; -+ boost::optional larl; -+ -+ msg >> odtone::mih::confirm() -+ & odtone::mih::tlv_status(st) -+ & odtone::mih::tlv_link_action_rsp_list(larl); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ -+ "\\nstatus="+status2string(st).c_str()+ -+ " --->]["+msg.destination().to_string()+"]\n"); -+ -+ // Display message parameters -+ log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -+ if (larl) { -+ log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -+ for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -+ { -+ log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -+ ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -+ } -+ } -+ log_(0, ""); -+ -+ // 1st scenario: Sequentially activate and deactivate each resource -+#ifdef SCENARIO_1 -+ if (larl) { -+ odtone::mih::link_action_rsp *rsp = &larl->front(); -+ if (_current_link_action_request < _nb_of_link_action_requests) { -+ if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ if (rsp->result.get() == odtone::mih::link_ac_success) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ _current_link_action_request += 1; -+ } -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+ } -+ } -+ else { // Ends the scenario -+ mih_user::send_MIH_Event_Unsubscribe_request(); -+ } -+ } -+#endif // SCENARIO_1 -+ -+#ifdef SCENARIO_2 -+ // 2nd scenario: Activate all resources, then deactivate all resources -+ if (larl.get().size() > 0) { -+ odtone::mih::link_action_rsp *rsp = &larl->front(); -+ if (++_current_link_action_request < _nb_of_link_action_requests) { -+ if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ } -+ } -+ else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -+ _current_link_action_request = 0; -+ mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -+ } -+ else { // Ends the scenario -+ mih_user::send_MIH_Event_Unsubscribe_request(); -+ } -+ } -+#endif // SCENARIO_2 -+ -+ log_(0, "MIH_Link_Actions.confirm - End\n"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ odtone::mih::message m; -+ odtone::mih::threshold th; -+ std::vector thl; -+ odtone::mih::link_tuple_id lti; -+ odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -+ //List of the link threshold parameters -+ odtone::mih::link_cfg_param_list lcpl; -+ odtone::mih::link_cfg_param lcp; -+ odtone::mih::link_param_lte lp; -+ //odtone::mih::link_param_gen lp; -+ -+ odtone::mih::link_param_type typr; -+ -+ log_(0,""); -+ log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -+ -+ //link_tuple_id -+ lti.type = rcv_link_id.type; -+ lti.addr = rcv_link_id.addr; -+ -+ //local_l2_3gpp_addr = boost::get(lti.addr); -+ -+ //link_param_gen_data_rate = 0, /**< Data rate. */ -+ //link_param_gen_signal_strength = 1, /**< Signal strength. */ -+ //link_param_gen_sinr = 2, /**< SINR. */ -+ //link_param_gen_throughput = 3, /**< Throughput. */ -+ //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -+ //lp = odtone::mih::link_param_lte_bandwidth; -+ lp = odtone::mih::link_param_lte_rsrp; -+ lcp.type = lp; -+ -+ link_measures_request = 0; -+ if ( link_measures_request ==0){ -+ // Set Timer Interval (in ms) -+ lcp.timer_interval = 3000; -+ //th_action_normal = 0, /**< Set normal threshold. */ -+ //th_action_one_shot = 1, /**< Set one-shot threshold. */ -+ //th_action_cancel = 2 /**< Cancel threshold. */ -+ lcp.action = odtone::mih::th_action_normal; -+ link_measures_request = 1; -+ } else if ( link_measures_request==1){ -+ // Set Timer Interval (in ms) -+ lcp.timer_interval = 0; -+ lcp.action = odtone::mih::th_action_cancel; -+ link_measures_request = 0; -+ } -+ -+ //above_threshold = 0, /**< Above threshold. */ -+ //below_threshold = 1, /**< Below threshold. */ -+ th.threshold_val = -105; -+ th.threshold_x_dir = odtone::mih::threshold::above_threshold; -+ -+ thl.push_back(th); -+ lcp.threshold_list = thl; -+ lcpl.push_back(lcp); -+ -+ m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -+ & odtone::mih::tlv_link_identifier(lti) -+ & odtone::mih::tlv_link_cfg_param_list(lcpl); -+ -+ m.destination(msg.source()); -+ -+ log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -+ // link_tupple_id2string(lti).c_str() + -+ link_id2string(lti).c_str()+ -+ " --->]["+_mihfid.to_string()+"]\n"); -+ -+ _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); -+ -+ log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); -+ -+ log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); -+ -+ //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} -+ //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} -+ //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} -+ //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} -+ //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} -+ if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} -+ -+ log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); -+ -+ if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} -+ if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} -+ if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} -+ -+ log_(0, "\t Threshold value: ", th.threshold_val); -+ -+ if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} -+ if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} -+ -+ log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -+} -+ -+//----------------------------------------------------------------------------- -+void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -+//----------------------------------------------------------------------------- -+{ -+ log_(0, ""); -+ log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); -+ -+ // T odtone::uint iter; -+ // T odtone::mih::status st; -+ -+ //boost::optional lcsl; -+ // Todtone::mih::link_cfg_status_list lcsl; -+ // Todtone::mih::link_cfg_status lcp; -+ //odtone::mih::link_param_gen lp; -+ -+ // T odtone::mih::link_tuple_id lti; -+ -+ //msg >> odtone::mih::confirm() -+ // & odtone::mih::tlv_status(st) -+ // & odtone::mih::tlv_link_identifier(lti) -+ // & odtone::mih::tlv_link_cfg_status_list(lcsl); -+ -+ -+ log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); -+ log_(0,""); -+} -+ -+//----------------------------------------------------------------------------- -+int main(int argc, char** argv) -+//----------------------------------------------------------------------------- -+{ -+ odtone::setup_crash_handler(); -+ -+ try { -+ boost::asio::io_service ios; -+ -+ // declare MIH Usr available options -+ po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); -+ desc.add_options() -+ ("help", "Display configuration options") -+ (odtone::sap::kConf_File, po::value()->default_value("ue_lte_user.conf"), "Configuration file") -+ (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") -+ (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") -+ (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") -+ (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") -+ (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") -+ (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") -+ (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf2_ue"), "MIHF destination"); -+ -+ odtone::mih::config cfg(desc); -+ cfg.parse(argc, argv, odtone::sap::kConf_File); -+ -+ if (cfg.help()) { -+ std::cerr << desc << std::endl; -+ return EXIT_SUCCESS; -+ } -+ -+ mih_user usr(cfg, ios); -+ -+ ios.run(); -+ -+ } catch(std::exception& e) { -+ log_(0, "exception: ", e.what()); -+ } -+} -+ -+// EOF //////////////////////////////////////////////////////////////////////// -+ -diff --git a/boost-build.jam b/boost-build.jam -new file mode 100644 -index 0000000..f5b963e ---- /dev/null -+++ b/boost-build.jam -@@ -0,0 +1 @@ -+boost-build /home/nikaia/DEMO_SPECTRA/boost_1_49_0//tools/build/v2 ; -diff --git a/inc/odtone/conf.hpp b/inc/odtone/conf.hpp -new file mode 100644 -index 0000000..61b773c ---- /dev/null -+++ b/inc/odtone/conf.hpp -@@ -0,0 +1,670 @@ -+//======================================================================================================= -+// Brief : Configuration DSL -+// Authors : Bruno Santos -+// ------------------------------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2013 Universidade Aveiro -+// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//======================================================================================================= -+ -+#ifndef ODTONE_PMIP_CONF__HPP_ -+#define ODTONE_PMIP_CONF__HPP_ -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+namespace odtone { namespace conf { -+ -+namespace qi = boost::spirit::qi; -+namespace ph = boost::phoenix; -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+enum error_reason { -+ invalid_syntax, -+ invalid_command, -+ invalid_arg_type, -+ to_many_args, -+ invalid_prop, -+ invalid_prop_arg_type, -+ to_many_prop_args, -+ -+ error_reason_size -+}; -+ -+static char const* const error_reason_string[error_reason_size] = { -+ "invalid syntax", -+ "invalid command", -+ "invalid argument type", -+ "to many arguments", -+ "invalid property", -+ "invalid property argument type", -+ "to many property arguments" -+}; -+ -+typedef boost::variant arg_type; -+ -+typedef std::vector args_type; -+typedef std::pair prop_type; -+typedef std::map pset_type; -+ -+template -+class type_id_ { -+ typedef typename boost::remove_cv::type>::type tt; -+ typedef typename boost::mpl::find::type ft; -+ typedef typename boost::mpl::distance::type, ft>::type tp; -+ -+ ODTONE_STATIC_ASSERT( -+ (!boost::is_same::type, ft>::value), -+ "Type not supported" -+ ); -+ -+public: -+ static const uint value = tp::value; -+}; -+ -+struct property_class { -+ const char* name; //property name -+ uint type_id; //property argument type -+ uint count; //maximum number of arguments it can take -+}; -+ -+class function { -+ template -+ class at_ { -+ typedef typename boost::function_types::parameter_types::type ps; -+ typedef typename boost::mpl::at_c::type tp; -+ -+ public: -+ typedef typename boost::remove_cv::type>::type type; -+ }; -+ -+ template -+ static const typename at_::type& get_(arg_type const& arg) -+ { -+ typedef typename at_::type type; -+ -+ return boost::get(arg); -+ } -+ -+ template -+ struct adaptor_; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), pset); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0])); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), pset); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1])); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2]), pset); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2])); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2]), -+ get_(args[3]), pset); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2]), -+ get_(args[3])); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2]), -+ get_(args[3]), get_(args[4]), pset); -+ } -+ }; -+ -+ template -+ struct adaptor_ { -+ F f; -+ -+ adaptor_(F f_) : f(f_) -+ { } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ f(get_(args[0]), get_(args[1]), get_(args[2]), -+ get_(args[3]), get_(args[4])); -+ } -+ }; -+ -+ template -+ class traits_; -+ -+ template -+ class traits_ { -+ typedef typename boost::function_types::parameter_types::type tmp; -+ typedef typename boost::mpl::prior::type>::type last; -+ -+ ODTONE_STATIC_ASSERT( -+ (boost::is_same::type>::value), -+ "Result type must be void" -+ ); -+ -+ ODTONE_STATIC_ASSERT( -+ (boost::is_same::type>::value), -+ "Last argument must a const reference to a pset_type" -+ ); -+ -+ public: -+ typedef typename boost::mpl::erase::type arg_types; -+ -+ static const size_t arg_count = boost::mpl::size::value; -+ }; -+ -+ template -+ class traits_ { -+ ODTONE_STATIC_ASSERT( -+ (boost::is_same::type>::value), -+ "Result type must be void" -+ ); -+ -+ public: -+ typedef typename boost::function_types::parameter_types::type arg_types; -+ -+ static const size_t arg_count = boost::mpl::size::value; -+ }; -+ -+ struct push_arg_id_ { -+ push_arg_id_(std::vector& ais) -+ : args_id(ais) -+ { } -+ -+ template -+ void operator()(T) -+ { -+ const uint id = type_id_::value; -+ -+ args_id.push_back(id); -+ } -+ -+ std::vector& args_id; -+ }; -+ -+public: -+ function() -+ : _pclass(0), _pcsize(0) -+ {} -+ -+ template -+ function(F f) -+ : _pclass(0), _pcsize(0) -+ { -+ typedef typename traits_::arg_types types; -+ -+ boost::mpl::for_each< -+ types, -+ boost::remove_cv< boost::remove_reference > -+ >(push_arg_id_(_args)); -+ -+ _func = adaptor_::arg_count>(f); -+ } -+ -+ template -+ function(F f, property_class const (&pc)[N]) -+ : _pclass(pc), _pcsize(N) -+ { -+ typedef typename traits_::arg_types types; -+ -+ boost::mpl::for_each< -+ types, -+ boost::remove_cv< boost::remove_reference > -+ >(push_arg_id_(_args)); -+ -+ _func = adaptor_::arg_count>(f); -+ } -+ -+ void operator()(args_type const& args, pset_type const& pset) const -+ { -+ _func(args, pset); -+ } -+ -+ size_t max_args() const -+ { -+ return _args.size(); -+ } -+ -+ uint arg_id(uint n) const -+ { -+ return _args[n]; -+ } -+ -+ property_class const* get_prop_class(std::string const& name) const -+ { -+ return std::find_if(_pclass, _pclass + _pcsize, -+ !ph::bind(&std::strcmp, name.c_str(), -+ ph::bind(&property_class::name, ph::arg_names::arg1))); -+ } -+ -+private: -+ std::vector _args; -+ property_class const* _pclass; -+ size_t _pcsize; -+ -+ boost::function _func; -+}; -+ -+typedef std::map functions; -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+template -+struct skipper_grammar : qi::grammar { -+ skipper_grammar() -+ : skipper_grammar::base_type(sk, "skipper") -+ { -+ sk = -+ qi::blank -+ | ('#' >> *(qi::standard::char_ - qi::eol) > &qi::eol) -+ | ('\\' >> qi::eol) -+ ; -+ } -+ -+ qi::rule sk; -+}; -+ -+template -+struct string_grammar : qi::grammar { -+ string_grammar() -+ : string_grammar::base_type(str, "string") -+ { -+ esc.add("\\\"", '\"') -+ ("\\\\", '\\') -+ ("\\t", '\t') -+ ("\\n", '\n') -+ ("\\r", '\r') -+ ; -+ -+ str = -+ '"' -+ >> qi::as_string[*((esc | qi::standard::char_) - '"')][qi::_val = qi::_1] -+ > '"' -+ ; -+ } -+ -+ qi::symbols esc; -+ qi::rule str; -+}; -+ -+template -+struct ip4_grammar : qi::grammar { -+ -+ static net::ip::address_v4 conv(std::string const& str) -+ { -+ return net::ip::address_v4::from_string(str); -+ } -+ -+ ip4_grammar() -+ : ip4_grammar::base_type(ip4, "ip4") -+ { -+ ip4 = qi::as_string -+ [ -+ qi::raw -+ [ -+ qi::repeat(3)[u8 >> '.'] >> u8 -+ ] -+ ] -+ [qi::_val = ph::bind(&ip4_grammar::conv, qi::_1)]; -+ } -+ -+ qi::rule ip4; -+ qi::uint_parser u8; -+}; -+ -+template -+struct ip6_grammar : qi::grammar, net::ip::address_v6()> { -+ typedef qi::locals locals; -+ -+ static net::ip::address_v6 conv(std::string const& str) -+ { -+ return net::ip::address_v6::from_string(str); -+ } -+ -+ ip6_grammar() -+ : ip6_grammar::base_type(ip6, "ip6") -+ { -+ ip6 = qi::as_string -+ [ -+ qi::raw -+ [ -+ ( qi::repeat(1, 6)[h16 >> ':'] >> ((h16 >> (':' >> (h16 | ':'))) | ':' | ip4) ) -+ | ( "::" >> -(qi::repeat(0, 5)[h16 >> ':'] >> ((h16 >> -(':' >> (h16 ))) | ip4)) ) -+ | ( -+ qi::eps[qi::_a = 0] -+ >> +(h16[qi::_pass = ++qi::_a < 7u] >> ':') -+ >> +(':' >> h16[qi::_pass = ++qi::_a < 8u]) -+ ) -+ ] -+ ] -+ [qi::_val = ph::bind(&ip6_grammar::conv, qi::_1)]; -+ } -+ -+ qi::rule ip6; -+ qi::uint_parser h16; -+ ip4_grammar ip4; -+}; -+ -+template -+struct parser_grammar : qi::grammar -+ > { -+ typedef skipper_grammar skipper; -+ -+ struct act_on_name_ { -+ template -+ struct result { typedef bool type; }; -+ -+ bool operator()(function const*& f, functions const& cm, std::string const& name, error_reason& er) const -+ { -+ functions::const_iterator it = cm.find(name); -+ -+ if (it == cm.end()) { -+ er = invalid_command; -+ return false; -+ } -+ -+ f = &it->second; -+ return true; -+ } -+ }; -+ -+ struct act_on_arg_ { -+ template -+ struct result { typedef bool type; }; -+ -+ bool operator()(function const& f, args_type& args, arg_type& arg, error_reason& er) const -+ { -+ const uint n = args.size(); -+ -+ if (n >= f.max_args()) { -+ er = to_many_args; -+ return false; -+ } -+ -+ if (static_cast(arg.which()) != f.arg_id(n)) { -+ er = invalid_arg_type; -+ return false; -+ } -+ -+ args.push_back(arg); -+ return true; -+ } -+ }; -+ -+ struct act_on_prop_ { -+ template -+ struct result { typedef bool type; }; -+ -+ bool operator()(property_class const*& pc, function const& f, std::string const& name, error_reason& er) const -+ { -+ pc = f.get_prop_class(name); -+ -+ if (!pc) { -+ er = invalid_prop; -+ return false; -+ } -+ return true; -+ } -+ -+ bool operator()(property_class const* pc, arg_type const& arg, uint& count, error_reason& er) const -+ { -+ if (++count > pc->count) { -+ er = to_many_prop_args; -+ return false; -+ } -+ if (pc->type_id != uint(arg.which())) { -+ er = invalid_prop_arg_type; -+ return false; -+ } -+ return true; -+ } -+ }; -+ -+ struct run_cmd_ { -+ template -+ struct result { typedef void type; }; -+ -+ void operator()(function const& f, args_type const& args, pset_type const& pset) const -+ { -+ f(args, pset); -+ } -+ }; -+ -+ struct error_handler_ { -+ template -+ struct result { typedef void type; }; -+ -+ void operator()(Iterator begin, Iterator end, Iterator pos, qi::info const& what, error_reason er) const -+ { -+ Iterator eol = std::find(begin, end, '\n'); -+ -+ std::cout << "error: " -+ << error_reason_string[er] -+ << ", expecting \'" -+ << what -+ << "\':\n" -+ << std::string(begin, eol) -+ << std::endl -+ << std::string(std::distance(begin, pos), '~') -+ << '^' -+ << std::string(std::distance(pos, eol), '~') -+ << std::endl; -+ } -+ }; -+ -+ parser_grammar(functions const& cm) -+ : parser_grammar::base_type(start), cmds(cm), ereason(invalid_syntax) -+ { -+ start = qi::eol | cmd; -+ -+ cmd = ( -+ name [qi::_pass = act_on_name(qi::_a, ph::cref(cmds), qi::_1, ph::ref(ereason))] -+ > *arg [qi::_pass = act_on_arg(*qi::_a, qi::_b, qi::_1, ph::ref(ereason))] -+ > -pset(*qi::_a) [qi::_c = qi::_1] -+ > qi::eol -+ ) -+ [run_cmd(*qi::_a, qi::_b, qi::_c)]; -+ -+ name %= qi::lexeme[qi::alpha >> *(qi::alnum | '-')]; -+ -+ arg %= -+ ip4 -+ | ip6 -+ | qi::uint_ -+ | qi::int_ -+ | qi::double_ -+ | str -+ ; -+ -+ pset = -+ qi::lit('{') -+ > qi::eol -+ > +prop(qi::_r1) -+ > qi::lit('}') -+ ; -+ -+ prop = -+ name[qi::_val = qi::_1, qi::_a = 0, -+ qi::_pass = act_on_prop(qi::_a, qi::_r1, qi::_1, ph::ref(ereason))] -+ > (*arg[qi::_val = qi::_1, -+ qi::_pass = act_on_prop(qi::_a, qi::_1, qi::_b, ph::ref(ereason))]) -+ > qi::eol -+ ; -+ -+ cmd.name("command"); -+ name.name("identifier"); -+ arg.name("argument"); -+ pset.name("property-set"); -+ prop.name("property"); -+ -+ qi::on_error(start, error_handler(qi::_1, qi::_2, qi::_3, qi::_4, ph::ref(ereason))); -+ } -+ -+ typedef qi::locals cmd_locals; -+ typedef qi::locals prop_locals; -+ -+ qi::rule start; -+ qi::rule cmd; -+ qi::rule name; -+ qi::rule arg; -+ qi::rule pset; -+ qi::rule prop; -+ -+ string_grammar str; -+ ip4_grammar ip4; -+ ip6_grammar ip6; -+ -+ functions const& cmds; -+ error_reason ereason; -+ -+ ph::function act_on_name; -+ ph::function act_on_arg; -+ ph::function act_on_prop; -+ ph::function run_cmd; -+ ph::function error_handler; -+}; -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+bool exec(std::string::const_iterator& begin, std::string::const_iterator end, functions const& cm); -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+} /* namespace conf */ } /* namespace odtone */ -+ -+// EOF ////////////////////////////////////////////////////////////////////////////////////////////////// -+#endif /* ODTONE_PMIP_CONF__HPP_ */ -diff --git a/inc/odtone/mih/detail/archive.hpp b/inc/odtone/mih/detail/archive.hpp -index 42925f1..f2225b9 100644 ---- a/inc/odtone/mih/detail/archive.hpp -+++ b/inc/odtone/mih/detail/archive.hpp -@@ -1146,6 +1146,148 @@ struct serialize -+struct serialize > { -+ void operator()(iarchive& ar, boost::variant& val) const -+ { -+ octet selector; -+ -+ ar & selector; -+ switch (selector) { -+ case 0: -+ val = T1(); -+ ar & boost::get(val); -+ break; -+ -+ case 1: -+ val = T2(); -+ ar & boost::get(val); -+ break; -+ -+ case 2: -+ val = T3(); -+ ar & boost::get(val); -+ break; -+ -+ case 3: -+ val = T4(); -+ ar & boost::get(val); -+ break; -+ -+ case 4: -+ val = T5(); -+ ar & boost::get(val); -+ break; -+ -+ case 5: -+ val = T6(); -+ ar & boost::get(val); -+ break; -+ -+ case 6: -+ val = T7(); -+ ar & boost::get(val); -+ break; -+ -+ case 7: -+ val = T8(); -+ ar & boost::get(val); -+ break; -+ -+ case 8: -+ val = T9(); -+ ar & boost::get(val); -+ break; -+ -+ case 9: -+ val = T10(); -+ ar & boost::get(val); -+ break; -+ -+ case 10: -+ val = T11(); -+ ar & boost::get(val); -+ break; -+ -+ case 11: -+ val = T12(); -+ ar & boost::get(val); -+ break; -+ -+ case 12: -+ val = T13(); -+ ar & boost::get(val); -+ break; -+ -+ // default: -+ // ODTONE_NEVER_HERE; -+ } -+ } -+ -+ void operator()(oarchive& ar, boost::variant& val) const -+ { -+ octet selector = val.which(); -+ -+ ar & selector; -+ switch (selector) { -+ case 0: -+ ar & boost::get(val); -+ break; -+ -+ case 1: -+ ar & boost::get(val); -+ break; -+ -+ case 2: -+ ar & boost::get(val); -+ break; -+ -+ case 3: -+ ar & boost::get(val); -+ break; -+ -+ case 4: -+ ar & boost::get(val); -+ break; -+ -+ case 5: -+ ar & boost::get(val); -+ break; -+ -+ case 6: -+ ar & boost::get(val); -+ break; -+ -+ case 7: -+ ar & boost::get(val); -+ break; -+ -+ case 8: -+ ar & boost::get(val); -+ break; -+ -+ case 9: -+ ar & boost::get(val); -+ break; -+ -+ case 10: -+ ar & boost::get(val); -+ break; -+ -+ case 11: -+ ar & boost::get(val); -+ break; -+ -+ case 12: -+ ar & boost::get(val); -+ break; -+ -+ // default: -+ // ODTONE_NEVER_HERE; -+ } -+ } -+}; -+ - /////////////////////////////////////////////////////////////////////////////// - } /* namspace detail */ - -diff --git a/inc/odtone/mih/types/address.hpp b/inc/odtone/mih/types/address.hpp -index 18e586c..18fac4c 100644 ---- a/inc/odtone/mih/types/address.hpp -+++ b/inc/odtone/mih/types/address.hpp -@@ -20,6 +20,7 @@ - - /////////////////////////////////////////////////////////////////////////////// - #include -+#include - - /////////////////////////////////////////////////////////////////////////////// - namespace odtone { namespace mih { -@@ -236,6 +237,7 @@ struct l2_3gpp_2g_cell_id { - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_2g_cell_id& addr) - { -+ out << "l2_3gpp_2g_cell_id: CI:" << addr._ci << " LAC:" << addr._lac << " PLMN id:" << addr.plmn_id[0]<< addr.plmn_id[1]<< addr.plmn_id[2]; - return out; - } - -@@ -247,6 +249,12 @@ struct l2_3gpp_2g_cell_id { - */ - bool operator==(const l2_3gpp_2g_cell_id& other) const - { -+ std::cerr << "l2_3gpp_2g_cell_id()==" << std::endl; -+ std::cerr << "_lac " << _lac << " " << other._lac << std::endl; -+ std::cerr << "_ci " << _ci << " " << other._ci << std::endl; -+ std::cerr << "plmn_id " << plmn_id[0] << " " << other.plmn_id[0] << std::endl; -+ std::cerr << "plmn_id " << plmn_id[1] << " " << other.plmn_id[1] << std::endl; -+ std::cerr << "plmn_id " << plmn_id[2] << " " << other.plmn_id[2] << std::endl; - return ((_lac == other._lac) - && (_ci == other._ci) - && (plmn_id[0] == other.plmn_id[0]) -@@ -285,6 +293,7 @@ struct l2_3gpp_3g_cell_id { - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_3g_cell_id& addr) - { -+ out << "l2_3gpp_3g_cell_id: Cell id:" << addr._cell_id << " PLMN id:" << addr.plmn_id[0]<< addr.plmn_id[1]<< addr.plmn_id[2]; - return out; - } - -@@ -296,6 +305,11 @@ struct l2_3gpp_3g_cell_id { - */ - bool operator==(const l2_3gpp_3g_cell_id& other) const - { -+ std::cerr << "l2_3gpp_3g_cell_id()==" << std::endl; -+ std::cerr << "_cell_id " << _cell_id << " " << other._cell_id << std::endl; -+ std::cerr << "plmn_id " << plmn_id[0] << " " << other.plmn_id[0] << std::endl; -+ std::cerr << "plmn_id " << plmn_id[1] << " " << other.plmn_id[1] << std::endl; -+ std::cerr << "plmn_id " << plmn_id[2] << " " << other.plmn_id[2] << std::endl; - return ((_cell_id == other._cell_id) - && (plmn_id[0] == other.plmn_id[0]) - && (plmn_id[1] == other.plmn_id[1]) -@@ -328,6 +342,7 @@ struct l2_3gpp_addr { - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_addr& addr) - { -+ out << "l2_3gpp_addr " << addr.value; - return out; - } - -@@ -339,7 +354,7 @@ struct l2_3gpp_addr { - */ - bool operator==(const l2_3gpp_addr& other) const - { -- return ((value == other.value)); -+ return ((value.compare(other.value) == 0)); - } - - octet_string value; /**< L2_3GPP_ADDR data type. */ -@@ -370,6 +385,7 @@ struct l2_3gpp2_addr { - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp2_addr& addr) - { -+ out << "l2_3gpp2_addr:" << addr.value; - return out; - } - -@@ -412,6 +428,7 @@ struct other_l2_addr { - */ - friend std::ostream& operator<<(std::ostream& out, const other_l2_addr& addr) - { -+ out << "other_l2_addr"; - return out; - } - -diff --git a/inc/odtone/mih/types/bin_query.hpp b/inc/odtone/mih/types/bin_query.hpp -index f418acf..06e6c6b 100644 ---- a/inc/odtone/mih/types/bin_query.hpp -+++ b/inc/odtone/mih/types/bin_query.hpp -@@ -50,6 +50,7 @@ enum net_type_inc_enum { - net_type_inc_ieee802_16 = 9, /**< IEEE 802.16 */ - net_type_inc_ieee802_20 = 10, /**< IEEE 802.20 */ - net_type_inc_ieee802_22 = 11, /**< IEEE 802.22 */ -+ net_type_inc_lte = 12, /**< LTE */ - }; - - /** -diff --git a/inc/odtone/mih/types/link.hpp b/inc/odtone/mih/types/link.hpp -index 80381b4..f9c8718 100644 ---- a/inc/odtone/mih/types/link.hpp -+++ b/inc/odtone/mih/types/link.hpp -@@ -73,6 +73,74 @@ typedef boost::variant sig_strength; - */ - typedef bool link_res_status; - -+/** -+ * MAX_DELAY data type. -+ */ -+typedef uint16 max_delay; -+ -+/** -+ * BITRATE data type. -+ */ -+typedef uint32 bitrate; -+ -+/** -+ * JITTER data type. -+ */ -+typedef uint16 jitter; -+ -+/** -+ * PKT_LOSS_RATE data type. -+ */ -+typedef uint16 pkt_loss_rate; -+ -+/** -+ * COS data type. -+ */ -+typedef uint16 cos; -+ -+/** -+ * DROP_ELIGIBILITY data type. -+ */ -+typedef bool drop_eligibility; -+ -+/** -+ * MULTICAST_ENABLE data type. -+ */ -+typedef bool multicast_enable; -+ -+/** -+ * JUMBO_ENABLE data type. -+ */ -+typedef bool jumbo_enable; -+ -+/** -+ * PORT data type. -+ */ -+typedef uint16 port; -+ -+/** -+ * MARK data type. -+ */ -+typedef uint8 mark; -+ -+/** -+ * FLOW_ID data type. -+ */ -+typedef uint32 flow_id; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * PROTO data type enumeration. -+ */ -+enum proto_enum { -+ proto_tcp = 0, /**< TCP. */ -+ proto_udp = 1 /**< UDP. */ -+}; -+ -+/** -+ * PROTO data type. -+ */ -+typedef enumeration proto; - /////////////////////////////////////////////////////////////////////////////// - /** - * OP_MODE data type enumeration. -@@ -181,6 +249,248 @@ struct threshold { - uint16 threshold_val; /**< Threshold value. */ - enumeration threshold_x_dir; /**< Threshold Direction. */ - }; -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * LINK_TYPE data type enumeration. -+ */ -+enum link_type_enum { -+ link_type_gsm = 1, /**< Wireless - GSM. */ -+ link_type_gprs = 2, /**< Wireless - GPRS. */ -+ link_type_edge = 3, /**< Wireless - EDGE. */ -+ -+ link_type_ethernet = 15, /**< Ethernet. */ -+ -+ link_type_wireless_other = 18, /**< Wireless - Other. */ -+ link_type_802_11 = 19, /**< Wireless - IEEE 802.11. */ -+ -+ link_type_cdma2000 = 22, /**< Wireless - CDMA-2000. */ -+ link_type_umts = 23, /**< Wireless - UMTS. */ -+ link_type_cdma2000_hrpd = 24, /**< Wireless - CDMA-2000-HRPD. */ -+ link_type_lte = 25, /**< Wireless - LTE. */ -+ -+ link_type_802_16 = 27, /**< Wireless - IEEE 802.16. */ -+ link_type_802_20 = 28, /**< Wireless - IEEE 802.20. */ -+ link_type_802_22 = 29 /**< Wireless - IEEE 802.22. */ -+}; -+ -+/** -+ * LINK_TYPE data type. -+ */ -+typedef enumeration link_type; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * LINK_ID data type. -+ */ -+struct link_id { -+ /** -+ * Construct an empty LINK_ID data type. -+ */ -+ link_id() : type(link_type_enum(0)) -+ { } -+ -+ /** -+ * Serialize/deserialize the LINK_ID data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & type; -+ ar & addr; -+ } -+ -+ /** -+ * Check if the LINK_ID data type is equal to another LINK_ID. -+ * -+ * @param other The LINK_ID to compare to. -+ * @return True if they are equal or false otherwise. -+ */ -+ bool operator==(const link_id& other) const -+ { -+ return ((type == other.type) && (addr == other.addr)); -+ } -+ -+ /** -+ * LINK_ID data type output. -+ * -+ * @param out ostream. -+ * @param addr LINK_ID data type. -+ * @return ostream reference. -+ */ friend std::ostream& operator<<(std::ostream& out, const link_id& lid) -+ { -+ out << "link id " << lid.type << " " << lid.addr; -+ return out; -+ } -+ -+ -+ link_type type; /**< Link address type. */ -+ link_addr addr; /**< Link address. */ -+}; -+ -+/** -+ * LIST(LINK_ID) data type. -+ */ -+typedef std::vector link_id_list; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * IP_TUPLE data type. -+ */ -+struct ip_tuple { -+ /** -+ * Serialize/deserialize the IP_TUPLE data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & ip; -+ ar & port_val; -+ } -+ -+ ip_addr ip; /**< IP address.*/ -+ port port_val; /**< Port. */ -+}; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * Auxiliar QOS data type. -+ */ -+struct qos_sequence { -+ /** -+ * Serialize/deserialize the auxiliar QOS data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & delay_val; -+ ar & bitrate_val; -+ ar & jitter_val; -+ ar & pkt_loss_val; -+ } -+ -+ max_delay delay_val; /**< Maximum delay. */ -+ bitrate bitrate_val; /**< Bitrate. */ -+ jitter jitter_val; /**< Jitter. */ -+ pkt_loss_rate pkt_loss_val; /**< Packet loss. */ -+}; -+ -+/** -+ * QOS data type. -+ */ -+struct qos { -+ /** -+ * Serialize/deserialize the QOS data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & value; -+ } -+ -+ boost::variant value; /**< QoS value. */ -+}; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * Auxiliar MARK_QoS data type. -+ */ -+struct mark_qos_sequence { -+ /** -+ * Serialize/deserialize the auxiliar FLOW_ATTRIBUTE data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & mark_val; -+ ar & qos_val; -+ } -+ -+ mark mark_val; /**< Mark value. */ -+ qos qos_val; /**< QoS value. */ -+}; -+ -+/** -+ * Auxiliar MARK_DROP_ELIG data type. -+ */ -+struct mark_drop_elig_sequence { -+ /** -+ * Serialize/deserialize the auxiliar FLOW_ATTRIBUTE data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & mark_val; -+ ar & drop_val; -+ } -+ -+ mark mark_val; /**< Mark value. */ -+ drop_eligibility drop_val; /**< Drop eligibility value. */ -+}; -+ -+/** -+ * FLOW_ATTRIBUTE data type. -+ */ -+struct flow_attribute { -+ /** -+ * Serialize/deserialize the FLOW_ATTRIBUTE data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & id; -+ ar & multicast; -+ ar & qos_val; -+ ar & drop_elig_val; -+ } -+ -+ flow_id id; /**< Flow ID. */ -+ boost::variant multicast; /**< Multicast enable. */ -+ boost::variant qos_val; /**< Mask/QoS value. */ -+ boost::variant drop_elig_val; /**< Mask/drop eligibility value. */ -+}; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** -+ * RESOURCE_DESC data type. -+ */ -+struct resource_desc { -+ /** -+ * Serialize/deserialize the RESOURCE_DESC data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & lid; -+ ar & fid; -+ ar & data_rate; -+ ar & qos_val; -+ ar & jumbo; -+ ar & multicast; -+ } -+ -+ link_id lid; /**< Link ID. */ -+ flow_id fid; /**< Flow ID. */ -+ boost::variant data_rate; /**< Link data rate. */ -+ boost::variant qos_val; /**< QoS value. */ -+ boost::variant jumbo; /**< Jumbo enable. */ -+ boost::variant multicast; /**< Multicast enable. */ -+}; - - /////////////////////////////////////////////////////////////////////////////// - /** -@@ -208,6 +518,9 @@ enum link_ac_type_enum { - link_ac_type_low_power = 2, /**< Link low power. */ - link_ac_type_power_down = 3, /**< Link power down. */ - link_ac_type_power_up = 4, /**< Link power up. */ -+ link_ac_type_flow_attr = 5, /**< Flow Attribute. */ -+ link_ac_type_link_activate_resources = 6, /**< Link Activate Resources. */ -+ link_ac_type_link_deactivate_resources = 7, /**< Link Deactivate Resources. */ - }; - - /** -@@ -232,11 +545,31 @@ typedef bitmap<8, link_ac_attr_enum> link_ac_attr; - - /////////////////////////////////////////////////////////////////////////////// - /** -+ * LINK_AC_PARAM data type. -+ */ -+struct link_ac_param { -+ /** -+ * Serialize/deserialize the LINK_AC_PARAM data type. -+ * -+ * @param ar The archive to/from where serialize/deserialize the data type. -+ */ -+ template -+ void serialize(ArchiveT& ar) -+ { -+ ar & param; -+ } -+ -+ boost::variant param; /**< Link action parameter.*/ -+}; -+ -+/////////////////////////////////////////////////////////////////////////////// -+/** - * LINK_ACTION data type. - */ - struct link_action { - link_ac_type type; /**< Link action type. */ - link_ac_attr attr; /**< Link action attribute. */ -+ link_ac_param param;/**< Link action parameter. */ - - /** - * Serialize/deserialize the LINK_ACTION data type. -@@ -248,6 +581,7 @@ struct link_action { - {; - ar & type; - ar & attr; -+ ar & param; - } - }; - -@@ -266,33 +600,6 @@ enum th_action_enum { - */ - typedef enumeration th_action; - --/////////////////////////////////////////////////////////////////////////////// --/** -- * LINK_TYPE data type enumeration. -- */ --enum link_type_enum { -- link_type_gsm = 1, /**< Wireless - GSM. */ -- link_type_gprs = 2, /**< Wireless - GPRS. */ -- link_type_edge = 3, /**< Wireless - EDGE. */ -- -- link_type_ethernet = 15, /**< Ethernet. */ -- -- link_type_wireless_other = 18, /**< Wireless - Other. */ -- link_type_802_11 = 19, /**< Wireless - IEEE 802.11. */ -- -- link_type_cdma2000 = 22, /**< Wireless - CDMA-2000. */ -- link_type_umts = 23, /**< Wireless - UMTS. */ -- link_type_cdma2000_hrpd = 24, /**< Wireless - CDMA-2000-HRPD. */ -- -- link_type_802_16 = 27, /**< Wireless - IEEE 802.16. */ -- link_type_802_20 = 28, /**< Wireless - IEEE 802.20. */ -- link_type_802_22 = 29 /**< Wireless - IEEE 802.22. */ --}; -- --/** -- * LINK_TYPE data type. -- */ --typedef enumeration link_type; - - /////////////////////////////////////////////////////////////////////////////// - /** -@@ -505,46 +812,29 @@ typedef enumeration link_param_802_22; - - /////////////////////////////////////////////////////////////////////////////// - /** -- * LINK_ID data type. -- */ --struct link_id { -- /** -- * Construct an empty LINK_ID data type. -- */ -- link_id() : type(link_type_enum(0)) -- { } -- -- /** -- * Serialize/deserialize the LINK_ID data type. -- * -- * @param ar The archive to/from where serialize/deserialize the data type. -- */ -- template -- void serialize(ArchiveT& ar) -- { -- ar & type; -- ar & addr; -- } -- -- /** -- * Check if the LINK_ID data type is equal to another LINK_ID. -- * -- * @param other The LINK_ID to compare to. -- * @return True if they are equal or false otherwise. -- */ -- bool operator==(const link_id& other) const -- { -- return ((type == other.type) && (addr == other.addr)); -- } -- -- link_type type; /**< Link address type. */ -- link_addr addr; /**< Link address. */ -+ * LINK_PARAM_lte data type enumeration. -+ */ -+enum link_param_lte_enum { -+ link_param_lte_rsrp = 0, /**< RSSI. */ -+ link_param_lte_rsrq = 1, /**< No QoS resource available. */ -+ link_param_lte_cqi = 2, /**< Multicast packet loss rate.*/ -+ link_param_lte_bandwidth = 3, /**< System Load. */ -+ link_param_lte_pkt_delay = 4, /**< Number of registered users. */ -+ link_param_lte_pkt_loss = 5, /**< Number of active users. */ -+ link_param_lte_l2_buffer = 6, /**< Congestion windows of users. */ -+ link_param_lte_MN_cap = 7, /**< Congestion windows of users. */ -+ link_param_lte_embms = 8, /**< Congestion windows of users. */ -+ link_param_lte_jumbo_feasibility = 9, /**< Congestion windows of users. */ -+ link_param_lte_jumbo_setup = 10, /**< Congestion windows of users. */ -+ link_param_lte_active_embms = 11, /**< Transmission rate of users. */ -+ link_param_lte_link_congestion = 12, /**< Link congestion. */ - }; - -+/////////////////////////////////////////////////////////////////////////////// - /** -- * LIST(LINK_ID) data type. -+ * LINK_PARAM_LTE data type. - */ --typedef std::vector link_id_list; -+typedef enumeration link_param_lte; - - /////////////////////////////////////////////////////////////////////////////// - /** -@@ -746,7 +1036,8 @@ typedef boost::variant link_param_type; -+ link_param_802_22, -+ link_param_lte> link_param_type; - - /** - * LIST(LINK_PARAM_TYPE) data type. -diff --git a/lib/odtone/CMakeLists.txt b/lib/odtone/CMakeLists.txt -index 0023be9..8cd9f73 100644 ---- a/lib/odtone/CMakeLists.txt -+++ b/lib/odtone/CMakeLists.txt -@@ -10,6 +10,7 @@ set(libodtone_SOVERSION "${libodtone_MAJOR_VERSION}.${libodtone_MINOR_VERSION}") - - set(libodtone_SRC - strutil.cpp -+conf.cpp - mih/types/address.cpp - mih/config.cpp - mih/archive.cpp -diff --git a/lib/odtone/Jamfile b/lib/odtone/Jamfile -index 341d777..3f37d29 100644 ---- a/lib/odtone/Jamfile -+++ b/lib/odtone/Jamfile -@@ -32,7 +32,8 @@ odtone.explicit-alias source-list - ; - - lib odtone -- : debug.cpp -+ : conf.cpp -+ debug.cpp - strutil.cpp - logger.cpp - win32.cpp -diff --git a/lib/odtone/conf.cpp b/lib/odtone/conf.cpp -new file mode 100644 -index 0000000..e99fd91 ---- /dev/null -+++ b/lib/odtone/conf.cpp -@@ -0,0 +1,43 @@ -+//======================================================================================================= -+// Brief : Configuration DSL -+// Authors : Bruno Santos -+// ------------------------------------------------------------------------------------------------------ -+// ODTONE - Open Dot Twenty One -+// -+// Copyright (C) 2009-2013 Universidade Aveiro -+// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -+// -+// This software is distributed under a license. The full license -+// agreement can be found in the file LICENSE in this distribution. -+// This software may not be copied, modified, sold or distributed -+// other than expressed in the named license agreement. -+// -+// This software is distributed without any warranty. -+//======================================================================================================= -+ -+#include -+#include -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+namespace odtone { namespace conf { -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+bool exec(std::string::const_iterator& begin, std::string::const_iterator end, functions const& cm) -+{ -+ skipper_grammar skipper; -+ parser_grammar parser(cm); -+ std::string::const_iterator pos = begin; -+ -+ while (begin != end) { -+ if (!qi::phrase_parse(begin, end, parser, skipper) || pos == begin) -+ return false; -+ pos = begin; -+ } -+ -+ return true; -+} -+ -+///////////////////////////////////////////////////////////////////////////////////////////////////////// -+} /* namespace conf */ } /* namespace odtone */ -+ -+// EOF ////////////////////////////////////////////////////////////////////////////////////////////////// -diff --git a/src/mihf/command_service.cpp b/src/mihf/command_service.cpp -index 84557a0..516801b 100644 ---- a/src/mihf/command_service.cpp -+++ b/src/mihf/command_service.cpp -@@ -614,6 +614,7 @@ bool command_service::link_actions_request(meta_message_ptr &in, - // For each Link_ID in request message - std::vector::iterator lar; - for(lar = lal.begin(); lar != lal.end(); lar++) { -+ std::cout<<"ADDR in MIHF "<<(*lar).id.addr<destination(mih::id(_link_abook.search_interface((*lar).id.type, (*lar).id.addr))); - // If the Link SAP it is known send message - if (out->destination().to_string().compare("") != 0) { -diff --git a/src/mihf/dst_transaction.cpp b/src/mihf/dst_transaction.cpp -index 692f1ea..f6d7d86 100644 ---- a/src/mihf/dst_transaction.cpp -+++ b/src/mihf/dst_transaction.cpp -@@ -16,6 +16,7 @@ - //============================================================================== - - /////////////////////////////////////////////////////////////////////////////// -+#include "log.hpp" - #include "dst_transaction.hpp" - #include "utils.hpp" - /////////////////////////////////////////////////////////////////////////////// -@@ -50,6 +51,7 @@ void dst_transaction_t::run() - - _init_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) init tid ", in->tid()); - transaction_status = ONGOING; - opcode = in->opcode(); - tid = in->tid(); -@@ -75,6 +77,7 @@ void dst_transaction_t::run() - - _wait_response_prm_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) wait response tid ", tid); - state = DST_WAIT_RESPONSE_PRM; - - if (transaction_stop_when == 0) -@@ -88,6 +91,7 @@ void dst_transaction_t::run() - - _send_response_begin_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) send response begin tid ", tid); - state = DST_SEND_RESPONSE; - - start_ack_requestor = out->ackreq(); -@@ -100,6 +104,7 @@ void dst_transaction_t::run() - - _send_response_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) send response tid ", tid); - if (!start_ack_requestor || ack_requestor_status == SUCCESS) - goto _success_lbl_; - else if (ack_requestor_status == FAILURE) -@@ -110,6 +115,7 @@ void dst_transaction_t::run() - - _failure_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) failure tid ", tid); - state = DST_FAILURE; - transaction_status = FAILURE; - -@@ -118,6 +124,7 @@ void dst_transaction_t::run() - - _success_lbl_: - { -+ ODTONE_LOG(1, "(dst_transaction_t) success tid ", tid); - state = DST_SUCCESS; - transaction_status = SUCCESS; - } -diff --git a/src/mihf/event_service.cpp b/src/mihf/event_service.cpp -index fc4d08d..9c021ea 100644 ---- a/src/mihf/event_service.cpp -+++ b/src/mihf/event_service.cpp -@@ -40,6 +40,9 @@ extern odtone::uint16 kConf_MIHF_Link_Delete_Value; - - namespace odtone { namespace mihf { - -+ -+ -+ - /** - * Construct the event service. - * -@@ -306,7 +309,9 @@ bool event_service::event_subscribe_response(meta_message_ptr &in, - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); -- -+ -+ -+ std::cout<< "(mies) The link received is "<destination().to_string()), link, events.get()); -@@ -659,6 +664,9 @@ void event_service::msg_forward(meta_message_ptr &msg, - for(it = _event_subscriptions.begin(); - it != _event_subscriptions.end(); - it++, i++) { -+ ODTONE_LOG(3, "(mies) msg_forward() comparing event ", event, " with event_subscription it->event ", it->event); -+ ODTONE_LOG(3, "(mies) msg_forward() comparing link_tuple_id.type ", li.type, " with event_subscription it->link.type ", it->link.type); -+ ODTONE_LOG(3, "(mies) msg_forward() comparing link_tuple_id.addr ", li.addr, " with event_subscription it->link.addr ", it->link.addr); - if ((it->event == event) && (it->link == li)) { - ODTONE_LOG(3, "(mies) found registration of user: ", - it->user, " for event type ", event); -@@ -666,6 +674,7 @@ void event_service::msg_forward(meta_message_ptr &msg, - _transmit(msg); - } - } -+ ODTONE_LOG(3, "(mies) msg_forward() end"); - } - - -@@ -680,6 +689,7 @@ void event_service::link_event_forward(meta_message_ptr &msg, - mih::mih_evt_list_enum event) - { - mih::link_tuple_id li; -+ ODTONE_LOG(1, "(mies) link_event_forward()"); - *msg >> mih::indication() - & mih::tlv_link_identifier(li); - -@@ -699,8 +709,10 @@ bool event_service::link_up_indication(meta_message_ptr &in, meta_message_ptr &o - ODTONE_LOG(1, "(mies) received Link_Up.indication from ", - in->source().to_string()); - -- if(in->is_local()) -+ if(in->is_local()) { -+ ODTONE_LOG(1, "(mies) link_up_indication() reset ", in->source().to_string() ," in link_abook"); - _link_abook.reset(in->source().to_string()); -+ } - - link_event_forward(in, mih::mih_evt_link_up); - -diff --git a/src/mihf/link_book.cpp b/src/mihf/link_book.cpp -index 89c7ef1..271112e 100644 ---- a/src/mihf/link_book.cpp -+++ b/src/mihf/link_book.cpp -@@ -23,6 +23,38 @@ - - namespace odtone { namespace mihf { - -+//----------------------------------------------------------------------------- -+static std::string evt2string(mih::link_evt_list evtP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(evtP.get(mih::evt_link_detected)) s += "DETECTED "; -+ if(evtP.get(mih::evt_link_up)) s += "UP "; -+ if(evtP.get(mih::evt_link_down)) s += "DOWN "; -+ if(evtP.get(mih::evt_link_parameters_report)) s += "PARAMETERS_REPORT "; -+ if(evtP.get(mih::evt_link_going_down)) s += "GOING_DOWN "; -+ if(evtP.get(mih::evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; -+ if(evtP.get(mih::evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; -+ if(evtP.get(mih::evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; -+ return s; -+} -+enum link_cmd_list_enum { -+ cmd_link_event_subscribe = 1, /**< Event subscribe. */ -+ cmd_link_event_unsubscribe = 2, /**< Event unsubscribe. */ -+ cmd_link_get_parameters = 3, /**< Get parameters. */ -+ cmd_link_configure_thresholds = 4, /**< Configure thresholds. */ -+ cmd_link_action = 5, /**< Action. */ -+}; -+//----------------------------------------------------------------------------- -+static std::string cmd2string(mih::link_cmd_list cmdP){ -+//----------------------------------------------------------------------------- -+ std::string s=std::string(" "); -+ if(cmdP.get(mih::cmd_link_event_subscribe)) s += "EVENT_SUBSCRIBE "; -+ if(cmdP.get(mih::cmd_link_event_unsubscribe)) s += "EVENT_UNSUBSCRIBE"; -+ if(cmdP.get(mih::cmd_link_get_parameters)) s += "GET_PARAMETERS "; -+ if(cmdP.get(mih::cmd_link_configure_thresholds)) s += "CONFIGURE_THRESHOLDS "; -+ if(cmdP.get(mih::cmd_link_action)) s += "ACTION "; -+ return s; -+} - /** - * Add a new Link SAP entry in the link book. - * -@@ -47,7 +79,7 @@ void link_book::add(const mih::octet_string &id, - a.status = true; - - _lbook[id] = a; -- ODTONE_LOG(4, "(link_book) added: ", id, " ", ip, " ", port); -+ ODTONE_LOG(4, "(link_book) added: ", id, " ", ip, " ", port, " ", link_id); - } - - /** -@@ -102,8 +134,11 @@ void link_book::update_capabilities(const mih::octet_string &id, - it = _lbook.find(id); - - if (it != _lbook.end()) { -+ ODTONE_LOG(4, "(link_book) update_capabilities() FOUND: ", id, " ", evt2string(event_list), " ", cmd2string(cmd_list)); - it->second.event_list = event_list; - it->second.cmd_list = cmd_list; -+ } else { -+ ODTONE_LOG(4, "(link_book) update_capabilities() NOT FOUND: ", id, " ", evt2string(event_list), " ", cmd2string(cmd_list)); - } - } - -@@ -131,8 +166,10 @@ void link_book::inactive(mih::octet_string &id) - std::map::iterator it; - it = _lbook.find(id); - -- if (it != _lbook.end()) -+ if (it != _lbook.end()) { -+ ODTONE_LOG(4, "(link_book) inactive() : ", id); - it->second.status = false; -+ } - } - - /** -@@ -183,10 +220,21 @@ const mih::octet_string link_book::search_interface(mih::link_type lt, mih::link - boost::mutex::scoped_lock lock(_mutex); - - mih::octet_string id; -- for(std::map::iterator it = _lbook.begin(); it != _lbook.end(); it++) { -+ std::map::iterator it; -+ for(it = _lbook.begin(); it != _lbook.end(); it++) { -+ -+ ODTONE_LOG(4, "(link_book) ID LINK TYPE : ", it->first, " ADDRESS ", it->second.link_id.addr, " STATUS", it->second.status); -+ } -+ -+ for(/*std::map::iterator*/ it = _lbook.begin(); it != _lbook.end(); it++) { -+ -+ ODTONE_LOG(4, "(link_book) search 1st step ID LINK TYPE comparison type:",it->second.link_id.type, "LT", lt); - if(it->second.link_id.type == lt) { -+ ODTONE_LOG(4, "(link_book) search 2nd step ID LINK TYPE comparison addr:",it->second.link_id.addr, "LA", la); - if(it->second.link_id.addr == la) { -- if(it->second.status) { -+ ODTONE_LOG(4, "(link_book) search 3rd step ID LINK TYPE check status:",it->second.status); -+ if(it->second.status) { -+ ODTONE_LOG(4, "(link_book) search 3rd step ID LINK TYPE : ", it->first, " ADDRESS ", it->second.link_id.addr, " STATUS", it->second.status); - id = it->first; - break; - } -@@ -194,6 +242,7 @@ const mih::octet_string link_book::search_interface(mih::link_type lt, mih::link - } - } - -+ ODTONE_LOG(4, "(link_book) search_interface() : ", lt, " ", la, " Found:", id); - return id; - } - -@@ -214,6 +263,7 @@ uint16 link_book::fail(const mih::octet_string &id) - boost::throw_exception(unknown_link_sap()); - - (it->second.fail)++; -+ ODTONE_LOG(4, "(link_book) fail() : ", id ," num fails:",it->second.fail); - return it->second.fail; - } - -@@ -232,6 +282,7 @@ void link_book::reset(const mih::octet_string &id) - if (it == _lbook.end()) - boost::throw_exception(unknown_link_sap()); - -+ ODTONE_LOG(4, "(link_book) reset() : ", id); - it->second.fail = 0; - it->second.status = true; - } -diff --git a/src/mihf/main.cpp b/src/mihf/main.cpp -index 244d38e..46a9db9 100644 ---- a/src/mihf/main.cpp -+++ b/src/mihf/main.cpp -@@ -289,6 +289,7 @@ void set_links(mih::octet_string &list, link_book &lbook) - enum_map["CDMA2000"] = odtone::mih::link_type_cdma2000; - enum_map["UMTS"] = odtone::mih::link_type_umts; - enum_map["CDMA2000-HRPD"] = odtone::mih::link_type_cdma2000_hrpd; -+ enum_map["LTE"] = odtone::mih::link_type_lte; - enum_map["802_16"] = odtone::mih::link_type_802_16; - enum_map["802_20"] = odtone::mih::link_type_802_20; - enum_map["802_22"] = odtone::mih::link_type_802_22; -@@ -323,7 +324,35 @@ void set_links(mih::octet_string &list, link_book &lbook) - throw "not supported yet"; - break; - -+ case 25: { -+ ++it; -+ mih::octet_string plmn = *it; -+ ++it; -+ mih::octet_string cell_id = *it; -+ -+ char_separator plmn_sep(":"); -+ tokenizer< char_separator > list_tokens(plmn, plmn_sep); -+ -+ mih::l2_3gpp_3g_cell_id lte; -+ uint8 pos = 0; -+ BOOST_FOREACH(mih::octet_string str, list_tokens) { -+ uint8 byte = 0; -+ std::istringstream iss(str); -+ iss >> std::hex >> byte; -+ -+ lte.plmn_id[pos] = byte % 0x100; -+ ++pos; -+ } -+ -+ std::istringstream iss(port); -+ if ((iss >> lte._cell_id).fail()) { -+ throw "invalid cell_id"; -+ } -+ -+ lid.addr = lte; -+ } break; - default: { -+ ODTONE_LOG(0, "Error: Invalid technology! Aborting...") ; - throw "invalid technology"; - } break; - } -@@ -605,7 +634,7 @@ int main(int argc, char **argv) - (kConf_MIHF_Users_List, po::value()->default_value(""), "List of local MIH-Users") - (kConf_MIHF_Links_List, po::value()->default_value(""), "List of local Links SAPs") - (kConf_MIHF_Transport_List, po::value()->default_value("udp"), "List of supported transport protocols") -- (kConf_MIHF_Link_Response_Time, po::value()->default_value(3000), "Link SAP response time (milliseconds)") -+ (kConf_MIHF_Link_Response_Time, po::value()->default_value(7000), "Link SAP response time (milliseconds)") - (kConf_MIHF_Link_Delete, po::value()->default_value(2), "Link SAP response fails to forget") - (kConf_MIHF_Discover, po::value()->default_value(""), "MIHF Discovery Mechanisms Order") - (kConf_MIHF_Multicast, "Allows multicast messages") -@@ -716,6 +745,7 @@ int main(int argc, char **argv) - mies_register_callbacks(mies); - mics_register_callbacks(mics); - miis_register_callbacks(miis); -+ std::cout << "Boot complete" << std::endl << std::flush; - - io.run(); - -diff --git a/src/mihf/service_access_controller.cpp b/src/mihf/service_access_controller.cpp -index 7660d50..2528fca 100644 ---- a/src/mihf/service_access_controller.cpp -+++ b/src/mihf/service_access_controller.cpp -@@ -44,6 +44,7 @@ static std::map _callbacks; /**< Callback map of the supported - */ - void sac_register_callback(uint mid, handler_t func) - { -+ ODTONE_LOG(1, "(sac) sac_register_callback(): mid ", mid, " handler ", func); - _callbacks[mid] = func; - } - -@@ -85,8 +86,11 @@ void sac_dispatch::operator()(meta_message_ptr& in) - // send response if it was generated - try { - -- if (process_message(in, out)) -+ if (process_message(in, out)) { - _transmit(out); -+ } else { -+ ODTONE_LOG(1, "sac_dispatch::operator() Message not transmitted out."); -+ } - - } catch(mih::bad_tlv) { - ODTONE_LOG(1, "Discarding malformed message."); -diff --git a/src/mihf/service_management.cpp b/src/mihf/service_management.cpp -index 6a75f82..9c31b2c 100644 ---- a/src/mihf/service_management.cpp -+++ b/src/mihf/service_management.cpp -@@ -638,6 +638,7 @@ bool service_management::link_register_indication(meta_message_ptr &in, - *in >> odtone::mih::indication() - & odtone::mih::tlv_interface_type_addr(link_id); - -+ ODTONE_LOG(4, "((mism) received Link_Register.indication: link_id", link_id); - // Add Link SAP to the list of known Link SAPs - _link_abook.add(in->source().to_string(), in->ip(), in->port(), link_id); - -diff --git a/src/mihf/src_transaction.cpp b/src/mihf/src_transaction.cpp -index af6a468..ef132d8 100644 ---- a/src/mihf/src_transaction.cpp -+++ b/src/mihf/src_transaction.cpp -@@ -16,6 +16,7 @@ - //============================================================================== - - /////////////////////////////////////////////////////////////////////////////// -+#include "log.hpp" - #include "src_transaction.hpp" - #include "utils.hpp" - /////////////////////////////////////////////////////////////////////////////// -@@ -51,6 +52,7 @@ void src_transaction_t::run() - - _init_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) init tid ", out->tid()); - transaction_status = ONGOING; - response_received = false; - transaction_stop_when = 15; // FIXME: read from config -@@ -84,6 +86,7 @@ void src_transaction_t::run() - - _wait_ack_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) wait ack tid ", tid); - state = SRC_WAIT_ACK; - - if (ack_requestor_status == SUCCESS) -@@ -96,6 +99,7 @@ void src_transaction_t::run() - - _wait_response_msg_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) wait response tid ", tid); - state = SRC_WAIT_RESPONSE_MSG; - - if (transaction_stop_when == 0) { -@@ -111,6 +115,7 @@ void src_transaction_t::run() - - _process_msg_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) process msg tid ", tid); - state = SRC_PROCESS_MSG; - - start_ack_responder = in->ackreq(); -@@ -132,6 +137,7 @@ void src_transaction_t::run() - - _failure_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) failure tid ", tid); - transaction_status = FAILURE; - state = SRC_FAILURE; - return; -@@ -139,6 +145,7 @@ void src_transaction_t::run() - - _success_lbl_: - { -+ ODTONE_LOG(1, "(src_transaction_t) success tid ", tid); - transaction_status = SUCCESS; - state = SRC_SUCCESS; - } -diff --git a/src/mihf/transaction_pool.cpp b/src/mihf/transaction_pool.cpp -index f60d125..204e5a1 100644 ---- a/src/mihf/transaction_pool.cpp -+++ b/src/mihf/transaction_pool.cpp -@@ -16,6 +16,7 @@ - //============================================================================== - - /////////////////////////////////////////////////////////////////////////////// -+#include "log.hpp" - #include "transaction_pool.hpp" - /////////////////////////////////////////////////////////////////////////////// - -@@ -58,6 +59,7 @@ void transaction_pool::dec(Set &set, - - for(it = set.begin(); it != set.end(); it++) { - (*it)->transaction_stop_when--; -+ ODTONE_LOG(1, "(transaction_pool) decrementing tid ", (*it)->tid, " counter down to ", (*it)->transaction_stop_when); - if ((*it)->transaction_stop_when == 0) { - (*it)->run(); - -@@ -88,6 +90,7 @@ void transaction_pool::dec(Set &set, - */ - void transaction_pool::tick() - { -+ //ODTONE_LOG(1, "(transaction_pool) tick"); - _timer.expires_from_now(boost::posix_time::seconds(1)); - _timer.async_wait(boost::bind(&transaction_pool::tick, this)); - -@@ -107,6 +110,7 @@ void transaction_pool::tick() - */ - void transaction_pool::add(src_transaction_ptr &t) - { -+ ODTONE_LOG(1, "(transaction_pool) add src tid ", t->tid); - boost::mutex::scoped_lock lock(_src_mutex); - _src.insert(t); - } -@@ -118,6 +122,7 @@ void transaction_pool::add(src_transaction_ptr &t) - */ - void transaction_pool::add(dst_transaction_ptr &t) - { -+ ODTONE_LOG(1, "(transaction_pool) add dst tid ", t->tid); - boost::mutex::scoped_lock lock(_dst_mutex); - _dst.insert(t); - } -@@ -129,6 +134,7 @@ void transaction_pool::add(dst_transaction_ptr &t) - */ - void transaction_pool::del(const src_transaction_ptr &t) - { -+ ODTONE_LOG(1, "(transaction_pool) del src tid ", t->tid); - boost::mutex::scoped_lock lock(_src_mutex); - _src.erase(t); - } -@@ -140,6 +146,7 @@ void transaction_pool::del(const src_transaction_ptr &t) - */ - void transaction_pool::del(const dst_transaction_ptr &t) - { -+ ODTONE_LOG(1, "(transaction_pool) del dst tid ", t->tid); - boost::mutex::scoped_lock lock(_dst_mutex); - _dst.erase(t); - } --- -1.7.9.5 - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/CMakeLists.txt b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/CMakeLists.txt deleted file mode 100644 index 8cd9f732aa..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -project(libodtone) - -find_package(Boost 1.46 COMPONENTS system program_options thread REQUIRED) - -set(libodtone_MAJOR_VERSION ${odtone_MAJOR_VERSION}) -set(libodtone_MINOR_VERSION ${odtone_MINOR_VERSION}) -set(libodtone_MICRO_VERSION ${odtone_MICRO_VERSION}) -set(libodtone_VERSION "${libodtone_MAJOR_VERSION}.${libodtone_MINOR_VERSION}.${libodtone_MICRO_VERSION}") -set(libodtone_SOVERSION "${libodtone_MAJOR_VERSION}.${libodtone_MINOR_VERSION}") - -set(libodtone_SRC -strutil.cpp -conf.cpp -mih/types/address.cpp -mih/config.cpp -mih/archive.cpp -mih/message.cpp -net/dns/message.cpp -net/dns/resolver.cpp -net/dns/utils.cpp -net/link/address_mac.cpp -net/ip/icmp/icmp_parser.cpp -net/ip/prefix.cpp -debug.cpp -sap/link.cpp -sap/sap.cpp -sap/user.cpp -logger.cpp -win32.cpp -) - -if(MSVC) - LIST(APPEND libodtone_SRC debug_win32.cpp) -elseif(UNIX) - LIST(APPEND libodtone_SRC debug_linux.cpp) -endif() - -set(libodtone_base_FILE_HEADERS -../../inc/odtone/base.hpp -../../inc/odtone/bind_rv.hpp -../../inc/odtone/buffer.hpp -../../inc/odtone/cast.hpp -../../inc/odtone/conf.hpp -../../inc/odtone/debug.hpp -../../inc/odtone/exception.hpp -../../inc/odtone/list_node.hpp -../../inc/odtone/logger.hpp -../../inc/odtone/namespace.hpp -../../inc/odtone/random.hpp -../../inc/odtone/string.hpp -../../inc/odtone/strutil.hpp -) - -set(libodtone_mih_DIR_HEADERS ../../inc/odtone/mih) -set(libodtone_sap_DIR_HEADERS ../../inc/odtone/sap) -set(libodtone_net_DIR_HEADERS ../../inc/odtone/net) - -include_directories(${INCLUDE_DIRECTORIES} ${Boost_INCLUDE_DIRS} "../../inc") -add_library(libodtone SHARED ${libodtone_SRC}) -target_link_libraries(libodtone ${Boost_LIBRARIES}) -set_target_properties(libodtone PROPERTIES OUTPUT_NAME "odtone" - VERSION ${libodtone_VERSION} - SOVERSION ${libodtone_SOVERSION} - DEFINE_SYMBOL LIBODTONE_EXPORTS) - -# install libodtone -install(FILES ${libodtone_base_FILE_HEADERS} DESTINATION include/odtone) -install(DIRECTORY ${libodtone_mih_DIR_HEADERS} DESTINATION include/odtone) -install(DIRECTORY ${libodtone_sap_DIR_HEADERS} DESTINATION include/odtone) -install(DIRECTORY ${libodtone_net_DIR_HEADERS} DESTINATION include/odtone) -install(TARGETS libodtone EXPORT odtone - LIBRARY DESTINATION "${LIB_INSTALL_DIR}" - ARCHIVE DESTINATION "${LIB_INSTALL_DIR}" - RUNTIME DESTINATION bin) diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/Jamfile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/Jamfile deleted file mode 100644 index 3f37d29a7b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/Jamfile +++ /dev/null @@ -1,59 +0,0 @@ -#============================================================================== -# Brief : ODTONE Base Library Project Build -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------ -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#============================================================================== - -project libodtone - ; - -odtone.runtime-lib pthread ; - -odtone.explicit-alias source-list - : debug_linux.cpp - : linux - ; - -odtone.explicit-alias source-list - : debug_win32.cpp - : windows - ; - -lib odtone - : conf.cpp - debug.cpp - strutil.cpp - logger.cpp - win32.cpp - source-list - sap/sap.cpp - sap/user.cpp - sap/link.cpp - mih/archive.cpp - mih/config.cpp - mih/message.cpp - mih/types/address.cpp - net/link/address_mac.cpp - net/ip/prefix.cpp - net/ip/icmp/icmp_parser.cpp - net/dns/resolver.cpp - net/dns/message.cpp - net/dns/utils.cpp - /boost//system - /boost//thread - /boost//program_options - : 1024 - BOOST_ENABLE_ASSERT_HANDLER - ; diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/address.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/address.hpp deleted file mode 100644 index 18fac4cbe5..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/address.hpp +++ /dev/null @@ -1,561 +0,0 @@ -//============================================================================= -// Brief : MIH Address Types -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_MIH_TYPES_ADDRESS__HPP_ -#define ODTONE_MIH_TYPES_ADDRESS__HPP_ - -/////////////////////////////////////////////////////////////////////////////// -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace mih { - -/////////////////////////////////////////////////////////////////////////////// -typedef uint32 cell_id; /**< CELL_ID data type. */ -typedef uint16 lac; /**< LAC data type. */ -typedef uint16 ci; /**< CI data type. */ - -/////////////////////////////////////////////////////////////////////////////// -/** - * TRANSPORT_ADDR data type. - */ -class transport_addr { -protected: - /** - * Construct a TRANSPORT_ADDR data type. - * - * @param type Transport address type. - */ - transport_addr(uint16 type) : _type(type) - { } - - /** - * Construct a TRANSPORT_ADDR data type. - * - * @param type Transport address type. - * @param raw Raw bytes of the transport address. - * @param len Size of the transport address raw bytes. - */ - transport_addr(uint16 type, const void* raw, size_t len) - : _type(type), _addr(reinterpret_cast(raw), len) - { } - -public: - - /** - * Get the TRANSPORT_ADDR type. - * - * @return The transport address type. - */ - uint16 type() const - { - return _type; - } - - /** - * Set the TRANSPORT_ADDR type. - * - * @param type The transport address type. - */ - void type(const uint16 type) - { - _type = type; - } - - /** - * Get the pointer to an array of characters which contains the - * transport address. - * - * @return Pointer to an internal array containing the transport address. - */ - const void* get() const - { - return _addr.data(); - } - - /** - * Get the lenght of the transport address string. - * - * @return The lenght of the transport address string. - */ - size_t length() const - { - return _addr.length(); - } - - /** - * Serialize/deserialize the TRANSPORT_ADDR data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & _type; - ar & _addr; - } - -protected: - uint16 _type; /**< Transport address type. */ - octet_string _addr; /**< Transport address string. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * TRANSPORT_TYPE data type enumeration. - */ -enum transport_type_enum { - l2 = 0, /**< Layer 2 transport address. */ - l3_or_higher = 1, /**< Layer 3 or higher transport address. */ -}; - -/** - * TRANSPORT_TYPE data type. - */ -typedef enumeration transport_type; - -/////////////////////////////////////////////////////////////////////////////// -/** - * MAC_ADDR data type. - */ -class mac_addr : public transport_addr { -public: - /** - * Construct an empty MAC_ADDR data type. - * @note Transport address type = 6 - */ - mac_addr() : transport_addr(6) - { } - - /** - * Construct an empty MAC_ADDR data type. - * @note Transport address type = 6 - * - * @param addr address MAC address string (format: XX:XX:XX:XX:XX:XX). - */ - explicit mac_addr(const octet_string& addr) : transport_addr(6) - { - this->address(addr); - } - - /** - * Construct an empty MAC_ADDR data type. - * @note Transport address type = 6 - * - * @param raw Raw bytes of the MAC address. - * @param len Lenght of the MAC address raw bytes. - */ - mac_addr(const void* raw, size_t len) : transport_addr(6, raw, len) - { } - - /** - * Get the MAC address string (format: XX:XX:XX:XX:XX:XX). - * - * @return The MAC address string. - */ - octet_string address() const; - - /** - * Set the MAC address. - * - * @param addr The MAC address string (format: XX:XX:XX:XX:XX:XX). - */ - void address(const octet_string& addr); - - /** - * MAC_ADDR data type output. - * - * @param out ostream. - * @param tp MAC_ADDR data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const mac_addr& tp) - { - out << "\ntype: " << tp.type(); - out << "\naddress: " << tp.address(); - - return out; - } - - /** - * Check if the MAC_ADDR is equal to another MAC_ADDR. - * - * @param other The MAC_ADDR to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const mac_addr& other) const - { - return ((type() == other.type()) && (address().compare(other.address()) == 0)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * L2_3GPP_2G_CELL_ID data type. - */ -struct l2_3gpp_2g_cell_id { - uint8 plmn_id[3]; /**< PLMN_ID data type. */ - lac _lac; /**< LAC data type. */ - ci _ci; /**< CI data type. */ - - /** - * Serialize/deserialize the L2_3GPP_2G_CELL_ID data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & plmn_id[0]; - ar & plmn_id[1]; - ar & plmn_id[2]; - ar & _lac; - ar & _ci; - } - - /** - * L2_3GPP_2G_CELL_ID data type output. - * - * @param out ostream. - * @param addr L2_3GPP_2G_CELL_ID data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_2g_cell_id& addr) - { - out << "l2_3gpp_2g_cell_id: CI:" << addr._ci << " LAC:" << addr._lac << " PLMN id:" << addr.plmn_id[0]<< addr.plmn_id[1]<< addr.plmn_id[2]; - return out; - } - - /** - * Check if the L2_3GPP_2G_CELL_ID is equal to another L2_3GPP_2G_CELL_ID. - * - * @param other The L2_3GPP_2G_CELL_ID to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const l2_3gpp_2g_cell_id& other) const - { - std::cerr << "l2_3gpp_2g_cell_id()==" << std::endl; - std::cerr << "_lac " << _lac << " " << other._lac << std::endl; - std::cerr << "_ci " << _ci << " " << other._ci << std::endl; - std::cerr << "plmn_id " << plmn_id[0] << " " << other.plmn_id[0] << std::endl; - std::cerr << "plmn_id " << plmn_id[1] << " " << other.plmn_id[1] << std::endl; - std::cerr << "plmn_id " << plmn_id[2] << " " << other.plmn_id[2] << std::endl; - return ((_lac == other._lac) - && (_ci == other._ci) - && (plmn_id[0] == other.plmn_id[0]) - && (plmn_id[1] == other.plmn_id[1]) - && (plmn_id[2] == other.plmn_id[2])); - } -}; - -/** - * L2_3GPP_3G_CELL_ID data type. - */ -struct l2_3gpp_3g_cell_id { - uint8 plmn_id[3]; /**< PLMN_ID data type. */ - cell_id _cell_id; /**< CELL_ID data type. */ - - /** - * Serialize/deserialize the L2_3GPP_3G_CELL_ID data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & plmn_id[0]; - ar & plmn_id[1]; - ar & plmn_id[2]; - ar & _cell_id; - } - - /** - * L2_3GPP_3G_CELL_ID data type output. - * - * @param out ostream. - * @param addr L2_3GPP_3G_CELL_ID data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_3g_cell_id& addr) - { - out << "l2_3gpp_3g_cell_id: Cell id:" << addr._cell_id << " PLMN id:" << addr.plmn_id[0]<< addr.plmn_id[1]<< addr.plmn_id[2]; - return out; - } - - /** - * Check if the L2_3GPP_3G_CELL_ID is equal to another L2_3GPP_3G_CELL_ID. - * - * @param other The L2_3GPP_3G_CELL_ID to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const l2_3gpp_3g_cell_id& other) const - { - std::cerr << "l2_3gpp_3g_cell_id()==" << std::endl; - std::cerr << "_cell_id " << _cell_id << " " << other._cell_id << std::endl; - std::cerr << "plmn_id " << plmn_id[0] << " " << other.plmn_id[0] << std::endl; - std::cerr << "plmn_id " << plmn_id[1] << " " << other.plmn_id[1] << std::endl; - std::cerr << "plmn_id " << plmn_id[2] << " " << other.plmn_id[2] << std::endl; - return ((_cell_id == other._cell_id) - && (plmn_id[0] == other.plmn_id[0]) - && (plmn_id[1] == other.plmn_id[1]) - && (plmn_id[2] == other.plmn_id[2])); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * L2_3GPP_ADDR data type. - */ -struct l2_3gpp_addr { - /** - * Serialize/deserialize the L2_3GPP_ADDR data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & value; - } - - /** - * L2_3GPP_ADDR data type output. - * - * @param out ostream. - * @param addr L2_3GPP_ADDR data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp_addr& addr) - { - out << "l2_3gpp_addr " << addr.value; - return out; - } - - /** - * Check if the L2_3GPP_ADDR is equal to another L2_3GPP_ADDR. - * - * @param other The L2_3GPP_ADDR to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const l2_3gpp_addr& other) const - { - return ((value.compare(other.value) == 0)); - } - - octet_string value; /**< L2_3GPP_ADDR data type. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * Define L2_3GPP2_ADDR data type. - */ -struct l2_3gpp2_addr { - /** - * Serialize/deserialize the L2_3GPP2_ADDR data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & value; - } - - /** - * L2_3GPP2_ADDR data type output. - * - * @param out ostream. - * @param addr L2_3GPP2_ADDR data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const l2_3gpp2_addr& addr) - { - out << "l2_3gpp2_addr:" << addr.value; - return out; - } - - /** - * Check if the L2_3GPP2_ADDR is equal to another L2_3GPP2_ADDR. - * - * @param other The L2_3GPP2_ADDR to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const l2_3gpp2_addr& other) const - { - return ((value == other.value)); - } - - octet_string value; /**< L2_3GPP2_ADDR data type. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * Define OTHER_L2_ADDR data type. - */ -struct other_l2_addr { - /** - * Serialize/deserialize the OTHER_L2_ADDR data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & value; - } - - /** - * OTHER_L2_ADDR data type output. - * - * @param out ostream. - * @param addr OTHER_L2_ADDR data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const other_l2_addr& addr) - { - out << "other_l2_addr"; - return out; - } - - /** - * Check if the OTHER_L2_ADDR is equal to another OTHER_L2_ADDR. - * - * @param other The OTHER_L2_ADDR to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const other_l2_addr& other) const - { - return ((value == other.value)); - } - - octet_string value; /**< OTHER_L2_ADDR data type. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_ADDR data type. - */ -typedef boost::variant link_addr; - -/** - * LIST(LINK_ADDR) data type. - */ -typedef std::vector link_addr_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * IP_ADDR data type. - */ -class ip_addr : public transport_addr { -public: - /** - * IP_ADDR type enumeration. - */ - enum type_ip_enum { - none = 0, /**< None. */ - ipv4 = 1, /**< IP address version 4. */ - ipv6 = 2, /**< IP address version 6. */ - }; - - /** - * Construct a IP_ADDR data type. - * - * @param tp IP address type. - */ - ip_addr(type_ip_enum tp = none) : transport_addr(tp) - { } - - /** - * Construct a IP_ADDR data type. - * - * @param tp IP address type. - * @param raw Raw bytes of the IP address. - * @param len Size of the IP address raw bytes. - */ - ip_addr(type_ip_enum tp, const void* raw, size_t len) - : transport_addr(tp, raw, len) - { } - - /** - * Construct a IP_ADDR data type. - * - * @param tp IP address type. - * @param raw IP address string format. - */ - explicit ip_addr(type_ip_enum tp, const octet_string& addr) - : transport_addr(tp) - { - this->address(addr); - } - - /** - * Get the IP address string. - * - * @return The IP address string. - */ - octet_string address() const; - - /** - * Set the IP address. - * - * @param addr The IP address string. - */ - void address(const octet_string& addr); - - /** - * IP_ADDR data type output. - * - * @param out ostream. - * @param tp IP_ADDR data type. - * @return ostream reference. - */ - friend std::ostream& operator<<(std::ostream& out, const ip_addr& tp) - { - out << "\ntype: " << tp.type(); - out << "\naddress: " << tp.address(); - - return out; - } - - /** - * Check if the IP_ADDR is equal to another IP_ADDR. - * - * @param other The IP_ADDR to compare with. - * @return True if they are equal or false otherwise. - */ - bool operator==(const ip_addr& other) const - { - return ((type() == other.type()) && (address().compare(other.address()) == 0)); - } -}; - -typedef ip_addr dhcp_serv; /**< DHCP_SERV data type. */ -typedef ip_addr fn_agent; /**< FN_AGENT data type. */ -typedef ip_addr acc_rtr; /**< ACC_RTR data type. */ - -/////////////////////////////////////////////////////////////////////////////// -} /* namespace mih */ } /*namespace odtone */ - -// EOF //////////////////////////////////////////////////////////////////////// -#endif /* ODTONE_MIH_TYPES_ADDRESS__HPP_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/archive.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/archive.hpp deleted file mode 100644 index f2225b96f9..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/archive.hpp +++ /dev/null @@ -1,1313 +0,0 @@ -//============================================================================= -// Brief : Archive details -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_MIH_DETAIL_ARCHIVE__HPP_ -#define ODTONE_MIH_DETAIL_ARCHIVE__HPP_ - -/////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace mih { namespace detail { - -/////////////////////////////////////////////////////////////////////////////// -template -struct serialize { - template - void operator()(ArchiveT& ar, T& val) const - { - val.serialize(ar); - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, std::vector& val) const - { - uint pos = ar.position(); - uint len = ar.list_length(); - - val.resize(len); - try { - typename std::vector::iterator it = val.begin(); - - while (len--) { - ar & *it; - ++it; - } - - } catch (...) { - val.clear(); - ar.position(pos); - throw; - } - } - - void operator()(oarchive& ar, std::vector& val) const - { - typename std::vector::iterator it = val.begin(); - uint len = truncate_cast(val.size()); - uint pos = ar.position(); - - ar.list_length(len); - try { - while (len--) { - ar & *it; - ++it; - } - - } catch (...) { - ar.position(pos); - throw; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, std::list& val) const - { - uint pos = ar.position(); - uint len = ar.list_length(); - - val.resize(len); - try { - typename std::list::iterator it = val.begin(); - - while (len--) { - ar & *it; - ++it; - } - - } catch (...) { - val.clear(); - ar.position(pos); - throw; - } - } - - void operator()(oarchive& ar, std::list& val) const - { - typename std::list::iterator it = val.begin(); - uint len = truncate_cast(val.size()); - uint pos = ar.position(); - - ar.list_length(len); - try { - while (len--) { - ar & *it; - ++it; - } - - } catch (...) { - ar.position(pos); - throw; - } - } -}; - -template -struct serialize > { - typedef typename boost::array value_type; - - template - void operator()(Archive& ar, value_type& val) const - { - for (size_t i = 0; i < N; ++i) - ar & val.elems[i]; - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - case 8: - val = T9(); - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - case 8: - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - case 8: - val = T9(); - ar & boost::get(val); - break; - - case 9: - val = T10(); - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - case 8: - ar & boost::get(val); - break; - - case 9: - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - case 8: - val = T9(); - ar & boost::get(val); - break; - - case 9: - val = T10(); - ar & boost::get(val); - break; - - case 10: - val = T11(); - ar & boost::get(val); - break; - - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - case 8: - ar & boost::get(val); - break; - - case 9: - ar & boost::get(val); - break; - - case 10: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - case 8: - val = T9(); - ar & boost::get(val); - break; - - case 9: - val = T10(); - ar & boost::get(val); - break; - - case 10: - val = T11(); - ar & boost::get(val); - break; - - case 11: - val = T12(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - case 8: - ar & boost::get(val); - break; - - case 9: - ar & boost::get(val); - break; - - case 10: - ar & boost::get(val); - break; - - case 11: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - - -template -struct serialize > { - void operator()(iarchive& ar, boost::variant& val) const - { - octet selector; - - ar & selector; - switch (selector) { - case 0: - val = T1(); - ar & boost::get(val); - break; - - case 1: - val = T2(); - ar & boost::get(val); - break; - - case 2: - val = T3(); - ar & boost::get(val); - break; - - case 3: - val = T4(); - ar & boost::get(val); - break; - - case 4: - val = T5(); - ar & boost::get(val); - break; - - case 5: - val = T6(); - ar & boost::get(val); - break; - - case 6: - val = T7(); - ar & boost::get(val); - break; - - case 7: - val = T8(); - ar & boost::get(val); - break; - - case 8: - val = T9(); - ar & boost::get(val); - break; - - case 9: - val = T10(); - ar & boost::get(val); - break; - - case 10: - val = T11(); - ar & boost::get(val); - break; - - case 11: - val = T12(); - ar & boost::get(val); - break; - - case 12: - val = T13(); - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } - - void operator()(oarchive& ar, boost::variant& val) const - { - octet selector = val.which(); - - ar & selector; - switch (selector) { - case 0: - ar & boost::get(val); - break; - - case 1: - ar & boost::get(val); - break; - - case 2: - ar & boost::get(val); - break; - - case 3: - ar & boost::get(val); - break; - - case 4: - ar & boost::get(val); - break; - - case 5: - ar & boost::get(val); - break; - - case 6: - ar & boost::get(val); - break; - - case 7: - ar & boost::get(val); - break; - - case 8: - ar & boost::get(val); - break; - - case 9: - ar & boost::get(val); - break; - - case 10: - ar & boost::get(val); - break; - - case 11: - ar & boost::get(val); - break; - - case 12: - ar & boost::get(val); - break; - - // default: - // ODTONE_NEVER_HERE; - } - } -}; - -/////////////////////////////////////////////////////////////////////////////// -} /* namspace detail */ - -/////////////////////////////////////////////////////////////////////////////// -template -inline iarchive& operator&(iarchive& ar, T& val) -{ - detail::serialize()(ar, val); - return ar; -} - -template -inline oarchive& operator&(oarchive& ar, T& val) -{ - detail::serialize()(ar, val); - return ar; -} - -/////////////////////////////////////////////////////////////////////////////// -} /* namespace mih */ } /*namespace odtone */ - -// EOF //////////////////////////////////////////////////////////////////////// -#endif /* ODTONE_MIH_DETAIL_ARCHIVE__HPP_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/bin_query.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/bin_query.hpp deleted file mode 100644 index 06e6c6bcf5..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/bin_query.hpp +++ /dev/null @@ -1,164 +0,0 @@ -//============================================================================= -// Brief : MIH Binary Query Types -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_MIH_TYPES_BIN_QUERY__HPP_ -#define ODTONE_MIH_TYPES_BIN_QUERY__HPP_ - -/////////////////////////////////////////////////////////////////////////////// -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace mih { - -/////////////////////////////////////////////////////////////////////////////// -typedef cost_curr curr_pref; /**< CURR_PREG data type value. */ -typedef std::vector netwk_inc; /**< NETWK_INC data type value. */ -typedef uint32 nghb_radius;/**< NGHB_RADIUS data type value.*/ -typedef uint32 ie_type; /**< IE_TYPE data type value.*/ -typedef std::vector rpt_templ; /**< RTP_TEMPL data type value.*/ - -/////////////////////////////////////////////////////////////////////////////// -/** - * NET_TYPE_INC data type enumeration. - */ -enum net_type_inc_enum { - net_type_inc_gsm = 0, /**< GSM */ - net_type_inc_gprs = 1, /**< GPRS */ - net_type_inc_edge = 2, /**< EDGE */ - net_type_inc_ethernet = 3, /**< Ethernet */ - net_type_inc_wireless_other = 4, /**< Wireless other */ - net_type_inc_ieee802_11 = 5, /**< IEEE 802.11 */ - net_type_inc_cdma2000 = 6, /**< CDMA 2000 */ - net_type_inc_umts = 7, /**< UMTS */ - net_type_inc_cdma2000_hrpd = 8, /**< CDMA 2000 HRPD */ - net_type_inc_ieee802_16 = 9, /**< IEEE 802.16 */ - net_type_inc_ieee802_20 = 10, /**< IEEE 802.20 */ - net_type_inc_ieee802_22 = 11, /**< IEEE 802.22 */ - net_type_inc_lte = 12, /**< LTE */ -}; - -/** - * NET_TYPE_INC data type. - */ -typedef bitmap<32, net_type_inc_enum> net_type_inc; - -/////////////////////////////////////////////////////////////////////////////// -/** - * QUERIER_LOC data type. - */ -struct querier_loc { - /** - * Construct an empty QUERIER_LOC data type. - */ - querier_loc() : _location(null()), _link_addr(null()), _nghb_radius(null()) - { } - - /** - * Serialize/deserialize the QUERIER_LOC data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & _location; - ar & _link_addr; - ar & _nghb_radius; - } - - boost::variant _location; /**< Location information. */ - boost::variant _link_addr; /**< Link address. */ - boost::variant _nghb_radius; /**< Radius from the center point of - querier’s location. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * RPT_LIMIT data type. - */ -struct rpt_limit { - /** - * Construct an empty RPT_LIMIT data type. - */ - rpt_limit() : _max_ies(0), _start_entry(0) - { } - - /** - * Serialize/deserialize the RPT_LIMIT data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & _max_ies; - ar & _start_entry; - } - - uint16 _max_ies; /**< Maximum number of IEs. */ - uint16 _start_entry; /**< Start entry. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * IQ_BIN_DATA data type. - */ -struct iq_bin_data { - /** - * Construct an empty IQ_BIN_DATA data type. - */ - iq_bin_data() - : _querier_loc(null()), _net_type_inc(null()), _netwk_inc(null()), - _rpt_templ(null()), _rpt_limit(null()), _currency(null()) - { } - - /** - * Serialize/deserialize the IQ_BIN_DATA data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & _querier_loc; - ar & _net_type_inc; - ar & _netwk_inc; - ar & _rpt_templ; - ar & _rpt_limit; - ar & _currency; - } - - boost::variant _querier_loc; /**< Querier's location.*/ - boost::variant _net_type_inc; /**< Set of link types. */ - boost::variant _netwk_inc; /**< List of network identifiers.*/ - boost::variant _rpt_templ; /**< List of IEs types. */ - boost::variant _rpt_limit; /**< Report limitation. */ - boost::variant _currency; /**< Currency preference.*/ -}; - -/** - * LIST(IQ_BIN_DATA) data type. - */ -typedef std::vector iq_bin_data_list; - -/////////////////////////////////////////////////////////////////////////////// -} /* namespace mih */ } /*namespace odtone */ - -// EOF //////////////////////////////////////////////////////////////////////// -#endif /* ODTONE_MIH_TYPES_BIN_QUERY__HPP_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/command_service.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/command_service.cpp deleted file mode 100644 index 516801b491..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/command_service.cpp +++ /dev/null @@ -1,1081 +0,0 @@ -//============================================================================== -// Brief : Command Service -// Authors : Simao Reis -// Carlos Guimarães -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "command_service.hpp" - -#include "log.hpp" -#include "utils.hpp" -#include "mihfid.hpp" -#include "transmit.hpp" -#include "link_book.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -/////////////////////////////////////////////////////////////////////////////// - -extern odtone::uint16 kConf_MIHF_Link_Response_Time_Value; -extern odtone::uint16 kConf_MIHF_Link_Delete_Value; - -namespace odtone { namespace mihf { - -/** - * Construct the command service. - * - * @param io The io_service object that command service module will use to - * dispatch handlers for any asynchronous operations performed on - * the socket. - * @param lpool The local transaction pool module. - * @param t The transmit module. - * @param abook The address book module. - * @param link_abook The link book module. - * @param user_abook The user book module. - * @param lrpool The link response pool module. - */ -command_service::command_service(io_service &io, - local_transaction_pool &lpool, - transmit &t, - address_book &abook, - link_book &link_abook, - user_book &user_abook, - link_response_pool &lrpool) - : _io(io), - _lpool(lpool), - _transmit(t), - _abook(abook), - _link_abook(link_abook), - _user_abook(user_abook), - _lrpool(lrpool) -{ -} - -/** - * Handler responsible for processing the received Link Get Parameters - * responses from Link SAPs. - * - * @param ec Error code. - * @param in The input message. - */ -void command_service::link_get_parameters_response_handler(const boost::system::error_code &ec, meta_message_ptr &in) -{ - if(ec) - return; - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::status st = mih::status_failure; - mih::link_id lid; - mih::link_status_rsp lsr; - mih::status_rsp sr; - mih::status_rsp_list srl; - mih::dev_states_rsp_list dsrl; - meta_message_ptr out(new meta_message()); - - std::vector ids = _link_abook.get_ids(); - std::vector::iterator it_link; - for(it_link = ids.begin(); it_link != ids.end(); it_link++) { - if(_lrpool.check(in->tid(), *it_link)) { - // fill GetStatusResponseList - link_entry a; - mih::link_id lid; - - a = _link_abook.get(*it_link); - - lid.type = a.link_id.type; - lid.addr = a.link_id.addr; - - // fill capabilities - pending_link_response tmp = _lrpool.find(in->tid(), *it_link); - _lrpool.del(in->tid(), *it_link); - - mih::link_status_rsp& link_status = boost::get(tmp.response); - lsr = link_status; - - sr.id = lid; - sr.rsp = lsr; - - srl.push_back(sr); - - // If one or more responses are successful the status - // is set to success - st = mih::status_success; - } - } - - // Send Link_Get_Parameters.confirm to the user - if(st == mih::status_success) { - ODTONE_LOG(1, "(micm) setting response to Link_Get_Parameters.request"); - *out << mih::response(mih::response::link_get_parameters) - & mih::tlv_status(mih::status_success) - // & mih::tlv_dev_states_rsp_list(dsrl) - & mih::tlv_get_status_rsp_list(srl); - } else { - ODTONE_LOG(1, "(micm) setting failure response to Link_Get_Parameters.request"); - *out << mih::response(mih::response::link_get_parameters) - & mih::tlv_status(st); - } - - out->tid(in->tid()); - out->destination(in->source()); - out->source(mihfid); - - out->ip(in->ip()); - out->scope(in->scope()); - out->port(in->port()); - _transmit(out); -} - -/** - * Link Get Parameters Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_get_parameters_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received a Link_Get_Parameters.request from ", - in->source().to_string()); - - - if(utils::this_mihf_is_destination(in)) { - // - // Kick this message to MIH_Link SAP. - // - // local_transactions was made to handle request's - // from users to peer mihf's but in this case we add an - // entry to handle the MIH_Link_Get_Parameters and - // Link_Get_Parameters. - // - boost::optional dsr; - mih::link_id_list lil; - mih::link_status_req lsr; - - *in >> mih::request(mih::request::link_get_parameters) - & mih::tlv_dev_states_req(dsr) - & mih::tlv_link_id_list(lil) - & mih::tlv_get_status_req_set(lsr); - - *out << mih::request(mih::request::link_get_parameters) - & mih::tlv_link_parameters_req(lsr._param_type_list) - & mih::tlv_link_states_req(lsr._states_req) - & mih::tlv_link_descriptor_req(lsr._desc_req); - - out->tid(in->tid()); - out->source(mihfid); - - // For each Link_ID in request message - std::vector::iterator lid; - for(lid = lil.begin(); lid != lil.end(); lid++) { - out->destination(mih::id(_link_abook.search_interface((*lid).type, (*lid).addr))); - // If the Link SAP it is known send message - if (out->destination().to_string().compare("") != 0) { - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(out->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = out->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } else { - ODTONE_LOG(1, "(mics) forwarding Link_Get_Parameters.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - } - } - } - - // Set the timer that will be responsible for aggregate and - // response to this resquest - boost::shared_ptr timer = boost::make_shared(_io); - timer->expires_from_now(boost::posix_time::milliseconds(kConf_MIHF_Link_Response_Time_Value)); - timer->async_wait(boost::bind(&command_service::link_get_parameters_response_handler, this, _1, in)); - - { - boost::mutex::scoped_lock lock(_mutex); - _timer[in->tid()] = timer; - } - - // Do not respond to the request. The response handler will be - // responsible for that. - return false; - } else { - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Link Get Parameters Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_get_parameters_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Get_Parameters.response from ", - in->source().to_string()); - - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - ODTONE_LOG(1, "(mics) forwarding Link_Get_Parameters.response to ", - in->destination().to_string()); - - _transmit(in); - - return false; -} - -/** - * Link Get Parameters Confirm message handler. - * - * @param in input message. - * @param out output message. - * @return true if the response is sent immediately or false otherwise. - */ -bool command_service::link_get_parameters_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Get_Parameters.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - if(_lpool.set_user_tid(in)) { - mih::status st; - boost::optional lpl; - boost::optional lsrl; - boost::optional ldrl; - - *in >> mih::confirm(mih::confirm::link_get_parameters) - & mih::tlv_status(st) - & mih::tlv_link_parameters_status_list(lpl) - & mih::tlv_link_states_rsp(lsrl) - & mih::tlv_link_descriptor_rsp(ldrl); - - if(st == mih::status_success) { - mih::link_status_rsp link_status; - - link_status.states_rsp_list = lsrl.get(); - link_status.param_list = lpl.get(); - link_status.desc_rsp_list = ldrl.get(); - - _lrpool.add(in->source().to_string(), - in->tid(), - link_status); - } - - return false; - } - - ODTONE_LOG(1, "no pending transaction for this message, discarding"); - return false; -} - -/** - * Handler responsible for processing the received Link Get Parameters - * responses from Link SAPs. - * - * @param ec Error code. - * @param in The input message. - */ -void command_service::link_configure_thresholds_response_timeout(const boost::system::error_code &ec, meta_message_ptr &in) -{ - if(ec) - return; - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::link_tuple_id link; - meta_message_ptr out(new meta_message()); - - *in >> mih::request(mih::request::link_configure_thresholds) - & mih::tlv_link_identifier(link); - - // Send failure message to the user - ODTONE_LOG(1, "(mics) setting failure response to Link_Configure_Thresholds.request"); - *out << mih::response(mih::response::link_configure_thresholds) - & mih::tlv_status(mih::status_failure) - & mih::tlv_link_identifier(link); - - out->tid(in->tid()); - out->destination(in->source()); - out->source(mihfid); - - _transmit(out); -} - -/** - * Link Configure Thresholds Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_configure_thresholds_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received a Link_Configure_Thresholds.request from ", - in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - // - // Kick this message to MIH_Link SAP. - // - // local_transactions was made to handle request's - // from users to peer mihf's but in this case we add an - // entry to handle the MIH_Link_Get_Parameters and - // Link_Get_Parameters. - // - mih::link_tuple_id lti; - mih::link_cfg_param_list lcpl; - - *in >> mih::request(mih::request::link_configure_thresholds) - & mih::tlv_link_identifier(lti) - & mih::tlv_link_cfg_param_list(lcpl); - - *out << mih::request(mih::request::link_configure_thresholds) - & mih::tlv_link_cfg_param_list(lcpl); - - out->destination(mih::id(_link_abook.search_interface(lti.type, lti.addr))); - out->source(in->source()); - out->tid(in->tid()); - - // If the Link SAP it is known continue - if (out->destination().to_string().compare("") == 0) { - *out << mih::response(mih::response::link_configure_thresholds) - & mih::tlv_status(mih::status_failure) - & mih::tlv_link_identifier(lti); - - out->tid(in->tid()); - out->source(mihfid); - out->destination(in->source()); - - ODTONE_LOG(1, "(mies) forwarding Link_Configure_Thresholds.response to ", - out->destination().to_string()); - - return true; - } - - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(out->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = out->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } else { - ODTONE_LOG(1, "(mics) forwarding Link_Configure_Thresholds.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - - // Set the timer that will be responsible for sending a failure - // response if necessary - boost::shared_ptr timer = boost::make_shared(_io); - timer->expires_from_now(boost::posix_time::milliseconds(kConf_MIHF_Link_Response_Time_Value)); - timer->async_wait(boost::bind(&command_service::link_configure_thresholds_response_timeout, this, _1, in)); - - { - boost::mutex::scoped_lock lock(_mutex); - _timer[in->tid()] = timer; - } - } - - return false; - } else { - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Link Configure Thresholds Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_configure_thresholds_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Configure_Thresholds.response from ", - in->source().to_string()); - - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - ODTONE_LOG(1, "(mics) forwarding Link_Configure_Thresholds.response to ", in->destination().to_string()); - - _transmit(in); - - return false; -} - -/** - * Link Configure Thresholds Confirm message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_configure_thresholds_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Configure_Thresholds.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - out->source(in->source()); - if (!_lpool.set_user_tid(out)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::status st; - boost::optional lcsl; - - mih::link_tuple_id li; - li.type = _link_abook.get(in->source().to_string()).link_id.type; - li.addr = _link_abook.get(in->source().to_string()).link_id.addr; - - *in >> mih::confirm(mih::confirm::link_configure_thresholds) - & mih::tlv_status(st) - & mih::tlv_link_cfg_status_list(lcsl); - - *out << mih::response(mih::response::link_configure_thresholds) - & mih::tlv_status(st) - & mih::tlv_link_identifier(li) - & mih::tlv_link_cfg_status_list(lcsl); - - out->source(mihfid); - - ODTONE_LOG(1, "(mics) forwarding Link_Configure_Thresholds.confirm to ", out->destination().to_string()); - - _transmit(out); - - return false; -} - -/** - * Handler responsible for setting a failure Link Action - * responses. - * - * @param ec Error code. - * @param in The input message. - */ -void command_service::link_actions_response_handler(const boost::system::error_code &ec, - meta_message_ptr &in) -{ - if(ec) - return; - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::status st = mih::status_failure; - mih::link_action_rsp_list larl; - mih::link_action_rsp lar; - mih::link_ac_result laresult; - mih::link_scan_rsp_list lsrl; - meta_message_ptr out(new meta_message()); - - std::vector ids = _link_abook.get_ids(); - std::vector::iterator it_link; - for(it_link = ids.begin(); it_link != ids.end(); it_link++) { - if(_lrpool.check(in->tid(), *it_link)) { - // fill LinkActionsResultList - link_entry a; - mih::link_id lid; - - a = _link_abook.get(*it_link); - - lar.id.type = a.link_id.type; - lar.id.addr = a.link_id.addr; - - // fill action result - pending_link_response tmp = _lrpool.find(in->tid(), *it_link); - _lrpool.del(in->tid(), *it_link); - - action& ac = boost::get(tmp.response); - - if(ac.link_scan_rsp_list.is_initialized()) { - lar.scan_list = ac.link_scan_rsp_list.get(); - } - lar.result = ac.link_ac_result.get(); - larl.push_back(lar); - - // If one or more responses are successful the status - // is set to success - st = mih::status_success; - } - } - - // Send Link_Actions.confirm to the user - if(st == mih::status_success) { - ODTONE_LOG(1, "(mics) setting response to Link_Actions.request"); - *out << mih::response(mih::response::link_actions) - & mih::tlv_status(st) - & mih::tlv_link_action_rsp_list(larl); - } else { - ODTONE_LOG(1, "(mics) setting failure response to Link_Actions.request"); - *out << mih::response(mih::response::link_actions) - & mih::tlv_status(st); - } - - out->tid(in->tid()); - out->destination(in->source()); - out->source(mihfid); - - out->ip(in->ip()); - out->scope(in->scope()); - out->port(in->port()); - _transmit(out); -} - -/** - * Link Actions Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_actions_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received a Link_Actions.request from ", - in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - // - // Kick this message to MIH_Link SAP. - // - // The solution found to handle this corner case in the - // 802.21 standard was to send the message, as is, to the - // link sap. - // - mih::link_action_list lal; - - *in >> mih::request(mih::request::link_actions) - & mih::tlv_link_action_list(lal); - - // For each Link_ID in request message - std::vector::iterator lar; - for(lar = lal.begin(); lar != lal.end(); lar++) { - std::cout<<"ADDR in MIHF "<<(*lar).id.addr<destination(mih::id(_link_abook.search_interface((*lar).id.type, (*lar).id.addr))); - // If the Link SAP it is known send message - if (out->destination().to_string().compare("") != 0) { - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(out->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = out->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } else { - mih::link_addr* a = boost::get(&(*lar).addr); - if (a && ((*lar).action.attr.get(mih::link_ac_attr_data_fwd_req)) ) { - *out << mih::request(mih::request::link_actions) - & mih::tlv_link_action((*lar).action) - & mih::tlv_time_interval((*lar).ex_time) - & mih::tlv_poa(*a); - } else { - *out << mih::request(mih::request::link_actions) - & mih::tlv_link_action((*lar).action) - & mih::tlv_time_interval((*lar).ex_time); - } - - out->tid(in->tid()); - out->source(mihfid); - - ODTONE_LOG(1, "(mics) forwarding Link_Actions.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - } - } - } - - // Set the timer that will be responsible for aggregate and - // response to this resquest - boost::shared_ptr timer = boost::make_shared(_io); - timer->expires_from_now(boost::posix_time::milliseconds(kConf_MIHF_Link_Response_Time_Value)); - timer->async_wait(boost::bind(&command_service::link_actions_response_handler, this, _1, in)); - - { - boost::mutex::scoped_lock lock(_mutex); - _timer[in->tid()] = timer; - } - - // Do not respond to the request. The thread response handler will be - // responsible for that. - return false; - } else { - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Link Actions Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_actions_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Actions.response from ", - in->source().to_string()); - - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) no local pending transaction for this message, discarding"); - return false; - } - - ODTONE_LOG(1, "(mics) forwarding Link_Actions.response to ", in->destination().to_string()); - - _transmit(in); - - return false; -} - -/** - * Link Actions Confirm message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::link_actions_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mics) received Link_Actions.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - if(_lpool.set_user_tid(in)) { - mih::status st; - boost::optional lsrl; - boost::optional lar; - - *in >> mih::confirm(mih::confirm::link_actions) - & mih::tlv_status(st) - & mih::tlv_link_scan_rsp_list(lsrl) - & mih::tlv_link_ac_result(lar); - - if(st == mih::status_success) { - _lrpool.add(in->source().to_string(), - in->tid(), - lsrl, - lar.get()); - } - - return false; - } - - ODTONE_LOG(1, "no pending transaction for this message, discarding"); - return false; - -} - -/** - * Currently command service handover related messages are handled by - * a single MIH-user. If this MIHF is the destination of the message, - * forward it to the MIH-User with mobility role. - * - * @param recv_msg The receive message output. - * @param send_msg The send message output. - * @param in The input message. - * @param out The output message. - * @param cmd The command that the MIH-Users must support in order to - * receive an indication about the reception opf this message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::generic_command_request(const char *recv_msg, - const char *send_msg, - meta_message_ptr &in, - meta_message_ptr &out, - mih::mih_cmd_list_enum cmd) -{ - ODTONE_LOG(1, recv_msg, in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - // Forward this message to MIH-User for handover as an indication - in->opcode(mih::operation::indication); - std::vector user_list = _user_abook.get_ids(); - BOOST_FOREACH(mih::octet_string id, user_list) { - user_entry user = _user_abook.get(id); - if(user.supp_cmd.is_initialized()) { - if(user.supp_cmd->get(cmd)) { - in->destination(mih::id(id)); - _lpool.add(in); - - if(in->is_local()) - in->source(mihfid); - - ODTONE_LOG(1, send_msg , in->destination().to_string()); - _transmit(in); - } - } - } - - // Restore the original opcode after sending the indication message - in->opcode(mih::operation::request); - return false; - } else { - // try to forward the message, this is to handle the - // special case of the user handling MIH commands - // sending some MIH command request to a peer mihf - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Currently command service handover related messages are handled by - * a single MIH-user. If this MIHF is the destination of the message, - * check for a pending transaction and forwards the message. - * - * @param recv_msg The receive message output. - * @param send_msg The send message output. - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::generic_command_response(const char *recv_msg, - const char *send_msg, - meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, recv_msg, in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - ODTONE_LOG(1, send_msg , in->destination().to_string()); - in->opcode(mih::operation::confirm); - _transmit(in); - } else { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - ODTONE_LOG(1, send_msg , in->destination().to_string()); - in->source(mihfid); - _transmit(in); - } - - return false; -} - -/** - * Net Handover Candidate Query Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::net_ho_candidate_query_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received Net_HO_Candidate_Query.request from ", - "(mics) sending a Net_HO_Candidate_Query.indication to ", - in, out, mih::mih_cmd_net_ho_candidate_query); -} - -/** - * Net Handover Candidate Query Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::net_ho_candidate_query_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received Net_HO_Candidate_Query.response from ", - "(mics) sending a Net_HO_Candidate_Query.confirm to ", - in, out); -} - -/** - * MN Handover Query Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_candidate_query_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a MN_HO_Candidate_Query.request from ", - "(mics) sending a MN_HO_Candidate_Query.indication to ", - in, out, mih::mih_cmd_mn_ho_candidate_query); -} - -/** - * MN Handover Query Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_candidate_query_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received MN_HO_Candidate_Query.response from ", - "(mics) sending a MN_HO_Candidate_Query.confirm to ", - in, out); -} - -/** - * N2N Handover Query Resources Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_query_resources_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a MN_N2N_HO_Query_Resources.request from ", - "(mics) sending a MN_N2N_HO_Query_Resources.indication to ", - in, out, mih::mih_cmd_n2n_ho_query_resources); -} - -/** - * N2N Handover Query Resources Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_query_resources_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received MN_N2N_HO_Query_Resources.response from ", - "(mics) sending a MN_N2N_HO_Query_Resources.confirm to ", - in, out); -} - - -/** - * MN Handover Commit Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_commit_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a MN_HO_Commit.request from ", - "(mics) sending a MN_HO_Commit.indication to ", - in, out, mih::mih_cmd_mn_ho_commit); -} - -/** - * MN Handover Commit Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_commit_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received MN_HO_Commit.response from ", - "(mics) sending a MN_HO_Commit.confirm to ", - in, out); -} - -/** - * Net Handover Commit Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::net_ho_commit_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a Net_HO_Commit.request from ", - "(mics) sending a Net_HO_Commit.indication to ", - in, out, mih::mih_cmd_net_ho_commit); -} - -/** - * Net Handover Commit Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::net_ho_commit_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received Net_HO_Commit.response from ", - "(mics) sending a Net_HO_Commit.confirm to ", - in, out); -} - -/** - * MN Handover Complete Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_complete_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a MN_HO_Complete.request from ", - "(mics) sending a MN_HO_Complete.indication to ", - in, out, mih::mih_cmd_mn_ho_complete); -} - -/** - * MN Handover Complete Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::mn_ho_complete_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received MN_HO_Complete.response from ", - "(mics) sending a MN_HO_Complete.confirm to ", - in, out); -} - -/** - * N2N Handover Commit Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_commit_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a N2N_HO_Commit.request from ", - "(mics) sending a N2N_HO_Commit.indication to ", - in, out, mih::mih_cmd_n2n_ho_commit); -} - -/** - * N2N Handover Commit Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_commit_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received N2N_HO_Commit.response from ", - "(mics) sending a N2N_HO_Commit.confirm to ", - in, out); -} - - -/** - * N2N Handover Complete Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_complete_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_request("(mics) received a N2N_HO_Complete.request from ", - "(mics) sending a N2N_HO_Complete.indication to ", - in, out, mih::mih_cmd_n2n_ho_complete); -} - -/** - * N2N Handover Complete Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool command_service::n2n_ho_complete_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - return generic_command_response("(mics) received N2N_HO_Complete.response from ", - "(mics) sending a N2N_HO_Complete.confirm to ", - in, out); -} - - -} /* namespace mihf */ } /* namespace odtone */ - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.cpp deleted file mode 100644 index e99fd91498..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.cpp +++ /dev/null @@ -1,43 +0,0 @@ -//======================================================================================================= -// Brief : Configuration DSL -// Authors : Bruno Santos -// ------------------------------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//======================================================================================================= - -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace conf { - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -bool exec(std::string::const_iterator& begin, std::string::const_iterator end, functions const& cm) -{ - skipper_grammar skipper; - parser_grammar parser(cm); - std::string::const_iterator pos = begin; - - while (begin != end) { - if (!qi::phrase_parse(begin, end, parser, skipper) || pos == begin) - return false; - pos = begin; - } - - return true; -} - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -} /* namespace conf */ } /* namespace odtone */ - -// EOF ////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.hpp deleted file mode 100644 index 61b773c936..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/conf.hpp +++ /dev/null @@ -1,670 +0,0 @@ -//======================================================================================================= -// Brief : Configuration DSL -// Authors : Bruno Santos -// ------------------------------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//======================================================================================================= - -#ifndef ODTONE_PMIP_CONF__HPP_ -#define ODTONE_PMIP_CONF__HPP_ - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace conf { - -namespace qi = boost::spirit::qi; -namespace ph = boost::phoenix; - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -enum error_reason { - invalid_syntax, - invalid_command, - invalid_arg_type, - to_many_args, - invalid_prop, - invalid_prop_arg_type, - to_many_prop_args, - - error_reason_size -}; - -static char const* const error_reason_string[error_reason_size] = { - "invalid syntax", - "invalid command", - "invalid argument type", - "to many arguments", - "invalid property", - "invalid property argument type", - "to many property arguments" -}; - -typedef boost::variant arg_type; - -typedef std::vector args_type; -typedef std::pair prop_type; -typedef std::map pset_type; - -template -class type_id_ { - typedef typename boost::remove_cv::type>::type tt; - typedef typename boost::mpl::find::type ft; - typedef typename boost::mpl::distance::type, ft>::type tp; - - ODTONE_STATIC_ASSERT( - (!boost::is_same::type, ft>::value), - "Type not supported" - ); - -public: - static const uint value = tp::value; -}; - -struct property_class { - const char* name; //property name - uint type_id; //property argument type - uint count; //maximum number of arguments it can take -}; - -class function { - template - class at_ { - typedef typename boost::function_types::parameter_types::type ps; - typedef typename boost::mpl::at_c::type tp; - - public: - typedef typename boost::remove_cv::type>::type type; - }; - - template - static const typename at_::type& get_(arg_type const& arg) - { - typedef typename at_::type type; - - return boost::get(arg); - } - - template - struct adaptor_; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), pset); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0])); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), pset); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1])); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2]), pset); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2])); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2]), - get_(args[3]), pset); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2]), - get_(args[3])); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2]), - get_(args[3]), get_(args[4]), pset); - } - }; - - template - struct adaptor_ { - F f; - - adaptor_(F f_) : f(f_) - { } - - void operator()(args_type const& args, pset_type const& pset) const - { - f(get_(args[0]), get_(args[1]), get_(args[2]), - get_(args[3]), get_(args[4])); - } - }; - - template - class traits_; - - template - class traits_ { - typedef typename boost::function_types::parameter_types::type tmp; - typedef typename boost::mpl::prior::type>::type last; - - ODTONE_STATIC_ASSERT( - (boost::is_same::type>::value), - "Result type must be void" - ); - - ODTONE_STATIC_ASSERT( - (boost::is_same::type>::value), - "Last argument must a const reference to a pset_type" - ); - - public: - typedef typename boost::mpl::erase::type arg_types; - - static const size_t arg_count = boost::mpl::size::value; - }; - - template - class traits_ { - ODTONE_STATIC_ASSERT( - (boost::is_same::type>::value), - "Result type must be void" - ); - - public: - typedef typename boost::function_types::parameter_types::type arg_types; - - static const size_t arg_count = boost::mpl::size::value; - }; - - struct push_arg_id_ { - push_arg_id_(std::vector& ais) - : args_id(ais) - { } - - template - void operator()(T) - { - const uint id = type_id_::value; - - args_id.push_back(id); - } - - std::vector& args_id; - }; - -public: - function() - : _pclass(0), _pcsize(0) - {} - - template - function(F f) - : _pclass(0), _pcsize(0) - { - typedef typename traits_::arg_types types; - - boost::mpl::for_each< - types, - boost::remove_cv< boost::remove_reference > - >(push_arg_id_(_args)); - - _func = adaptor_::arg_count>(f); - } - - template - function(F f, property_class const (&pc)[N]) - : _pclass(pc), _pcsize(N) - { - typedef typename traits_::arg_types types; - - boost::mpl::for_each< - types, - boost::remove_cv< boost::remove_reference > - >(push_arg_id_(_args)); - - _func = adaptor_::arg_count>(f); - } - - void operator()(args_type const& args, pset_type const& pset) const - { - _func(args, pset); - } - - size_t max_args() const - { - return _args.size(); - } - - uint arg_id(uint n) const - { - return _args[n]; - } - - property_class const* get_prop_class(std::string const& name) const - { - return std::find_if(_pclass, _pclass + _pcsize, - !ph::bind(&std::strcmp, name.c_str(), - ph::bind(&property_class::name, ph::arg_names::arg1))); - } - -private: - std::vector _args; - property_class const* _pclass; - size_t _pcsize; - - boost::function _func; -}; - -typedef std::map functions; - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -template -struct skipper_grammar : qi::grammar { - skipper_grammar() - : skipper_grammar::base_type(sk, "skipper") - { - sk = - qi::blank - | ('#' >> *(qi::standard::char_ - qi::eol) > &qi::eol) - | ('\\' >> qi::eol) - ; - } - - qi::rule sk; -}; - -template -struct string_grammar : qi::grammar { - string_grammar() - : string_grammar::base_type(str, "string") - { - esc.add("\\\"", '\"') - ("\\\\", '\\') - ("\\t", '\t') - ("\\n", '\n') - ("\\r", '\r') - ; - - str = - '"' - >> qi::as_string[*((esc | qi::standard::char_) - '"')][qi::_val = qi::_1] - > '"' - ; - } - - qi::symbols esc; - qi::rule str; -}; - -template -struct ip4_grammar : qi::grammar { - - static net::ip::address_v4 conv(std::string const& str) - { - return net::ip::address_v4::from_string(str); - } - - ip4_grammar() - : ip4_grammar::base_type(ip4, "ip4") - { - ip4 = qi::as_string - [ - qi::raw - [ - qi::repeat(3)[u8 >> '.'] >> u8 - ] - ] - [qi::_val = ph::bind(&ip4_grammar::conv, qi::_1)]; - } - - qi::rule ip4; - qi::uint_parser u8; -}; - -template -struct ip6_grammar : qi::grammar, net::ip::address_v6()> { - typedef qi::locals locals; - - static net::ip::address_v6 conv(std::string const& str) - { - return net::ip::address_v6::from_string(str); - } - - ip6_grammar() - : ip6_grammar::base_type(ip6, "ip6") - { - ip6 = qi::as_string - [ - qi::raw - [ - ( qi::repeat(1, 6)[h16 >> ':'] >> ((h16 >> (':' >> (h16 | ':'))) | ':' | ip4) ) - | ( "::" >> -(qi::repeat(0, 5)[h16 >> ':'] >> ((h16 >> -(':' >> (h16 ))) | ip4)) ) - | ( - qi::eps[qi::_a = 0] - >> +(h16[qi::_pass = ++qi::_a < 7u] >> ':') - >> +(':' >> h16[qi::_pass = ++qi::_a < 8u]) - ) - ] - ] - [qi::_val = ph::bind(&ip6_grammar::conv, qi::_1)]; - } - - qi::rule ip6; - qi::uint_parser h16; - ip4_grammar ip4; -}; - -template -struct parser_grammar : qi::grammar - > { - typedef skipper_grammar skipper; - - struct act_on_name_ { - template - struct result { typedef bool type; }; - - bool operator()(function const*& f, functions const& cm, std::string const& name, error_reason& er) const - { - functions::const_iterator it = cm.find(name); - - if (it == cm.end()) { - er = invalid_command; - return false; - } - - f = &it->second; - return true; - } - }; - - struct act_on_arg_ { - template - struct result { typedef bool type; }; - - bool operator()(function const& f, args_type& args, arg_type& arg, error_reason& er) const - { - const uint n = args.size(); - - if (n >= f.max_args()) { - er = to_many_args; - return false; - } - - if (static_cast(arg.which()) != f.arg_id(n)) { - er = invalid_arg_type; - return false; - } - - args.push_back(arg); - return true; - } - }; - - struct act_on_prop_ { - template - struct result { typedef bool type; }; - - bool operator()(property_class const*& pc, function const& f, std::string const& name, error_reason& er) const - { - pc = f.get_prop_class(name); - - if (!pc) { - er = invalid_prop; - return false; - } - return true; - } - - bool operator()(property_class const* pc, arg_type const& arg, uint& count, error_reason& er) const - { - if (++count > pc->count) { - er = to_many_prop_args; - return false; - } - if (pc->type_id != uint(arg.which())) { - er = invalid_prop_arg_type; - return false; - } - return true; - } - }; - - struct run_cmd_ { - template - struct result { typedef void type; }; - - void operator()(function const& f, args_type const& args, pset_type const& pset) const - { - f(args, pset); - } - }; - - struct error_handler_ { - template - struct result { typedef void type; }; - - void operator()(Iterator begin, Iterator end, Iterator pos, qi::info const& what, error_reason er) const - { - Iterator eol = std::find(begin, end, '\n'); - - std::cout << "error: " - << error_reason_string[er] - << ", expecting \'" - << what - << "\':\n" - << std::string(begin, eol) - << std::endl - << std::string(std::distance(begin, pos), '~') - << '^' - << std::string(std::distance(pos, eol), '~') - << std::endl; - } - }; - - parser_grammar(functions const& cm) - : parser_grammar::base_type(start), cmds(cm), ereason(invalid_syntax) - { - start = qi::eol | cmd; - - cmd = ( - name [qi::_pass = act_on_name(qi::_a, ph::cref(cmds), qi::_1, ph::ref(ereason))] - > *arg [qi::_pass = act_on_arg(*qi::_a, qi::_b, qi::_1, ph::ref(ereason))] - > -pset(*qi::_a) [qi::_c = qi::_1] - > qi::eol - ) - [run_cmd(*qi::_a, qi::_b, qi::_c)]; - - name %= qi::lexeme[qi::alpha >> *(qi::alnum | '-')]; - - arg %= - ip4 - | ip6 - | qi::uint_ - | qi::int_ - | qi::double_ - | str - ; - - pset = - qi::lit('{') - > qi::eol - > +prop(qi::_r1) - > qi::lit('}') - ; - - prop = - name[qi::_val = qi::_1, qi::_a = 0, - qi::_pass = act_on_prop(qi::_a, qi::_r1, qi::_1, ph::ref(ereason))] - > (*arg[qi::_val = qi::_1, - qi::_pass = act_on_prop(qi::_a, qi::_1, qi::_b, ph::ref(ereason))]) - > qi::eol - ; - - cmd.name("command"); - name.name("identifier"); - arg.name("argument"); - pset.name("property-set"); - prop.name("property"); - - qi::on_error(start, error_handler(qi::_1, qi::_2, qi::_3, qi::_4, ph::ref(ereason))); - } - - typedef qi::locals cmd_locals; - typedef qi::locals prop_locals; - - qi::rule start; - qi::rule cmd; - qi::rule name; - qi::rule arg; - qi::rule pset; - qi::rule prop; - - string_grammar str; - ip4_grammar ip4; - ip6_grammar ip6; - - functions const& cmds; - error_reason ereason; - - ph::function act_on_name; - ph::function act_on_arg; - ph::function act_on_prop; - ph::function run_cmd; - ph::function error_handler; -}; - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -bool exec(std::string::const_iterator& begin, std::string::const_iterator end, functions const& cm); - -///////////////////////////////////////////////////////////////////////////////////////////////////////// -} /* namespace conf */ } /* namespace odtone */ - -// EOF ////////////////////////////////////////////////////////////////////////////////////////////////// -#endif /* ODTONE_PMIP_CONF__HPP_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/dst_transaction.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/dst_transaction.cpp deleted file mode 100644 index f6d7d86b61..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/dst_transaction.cpp +++ /dev/null @@ -1,136 +0,0 @@ -//============================================================================== -// Brief : Destination Transaction -// Authors : Simao Reis -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "log.hpp" -#include "dst_transaction.hpp" -#include "utils.hpp" -/////////////////////////////////////////////////////////////////////////////// - -namespace odtone { namespace mihf { - -/** - * Constructor a Destination State Machine transaction. - * - * @param f The transaction handler. - * @param netsap The netsap module. - */ -dst_transaction_t::dst_transaction_t(handler_t &f, net_sap &netsap) - : transaction_t(f, netsap) -{ - state = DST_INIT; -} - -/** - * Run Destination State Machine transaction. - */ -void dst_transaction_t::run() -{ - switch (state) - { - case DST_INIT: goto _init_lbl_; - case DST_WAIT_RESPONSE_PRM: goto _wait_response_prm_lbl_; - case DST_SEND_RESPONSE: goto _send_response_lbl_; - case DST_FAILURE: goto _failure_lbl_; - case DST_SUCCESS: goto _success_lbl_; - } - - _init_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) init tid ", in->tid()); - transaction_status = ONGOING; - opcode = in->opcode(); - tid = in->tid(); - transaction_stop_when = 15; // TODO: read from config - is_multicast = utils::is_multicast(in); - peer_mihf_id = in->source(); - my_mihf_id = in->destination(); - start_ack_responder = (in->ackreq() && !is_multicast); - msg_in_avail = false; - - out.reset(new meta_message); - msg_out_avail = process_message(in, out); - - if (start_ack_responder) - ack_responder(); - - if (opcode == mih::operation::request) - goto _wait_response_prm_lbl_; - else if ((opcode == mih::operation::indication) - || (opcode == mih::operation::response)) - goto _success_lbl_; - } - - _wait_response_prm_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) wait response tid ", tid); - state = DST_WAIT_RESPONSE_PRM; - - if (transaction_stop_when == 0) - goto _failure_lbl_; - - if (msg_out_avail && (!start_ack_responder || out->ackrsp())) - goto _send_response_begin_lbl_; - - return; - } - - _send_response_begin_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) send response begin tid ", tid); - state = DST_SEND_RESPONSE; - - start_ack_requestor = out->ackreq(); - if(start_ack_requestor) - ack_requestor(); - ack_requestor_status = ONGOING; - - _netsap.send(out); - } - - _send_response_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) send response tid ", tid); - if (!start_ack_requestor || ack_requestor_status == SUCCESS) - goto _success_lbl_; - else if (ack_requestor_status == FAILURE) - goto _failure_lbl_; - - return; - } - - _failure_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) failure tid ", tid); - state = DST_FAILURE; - transaction_status = FAILURE; - - return; - } - - _success_lbl_: - { - ODTONE_LOG(1, "(dst_transaction_t) success tid ", tid); - state = DST_SUCCESS; - transaction_status = SUCCESS; - } - - return; -} - - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/event_service.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/event_service.cpp deleted file mode 100644 index 9c021eac74..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/event_service.cpp +++ /dev/null @@ -1,956 +0,0 @@ -//============================================================================== -// Brief : Event Service -// Authors : Simao Reis -// Carlos Guimarães -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include "event_service.hpp" - -#include "log.hpp" -#include "link_book.hpp" -#include "mihfid.hpp" -#include "transmit.hpp" -#include "utils.hpp" - -#include -#include -#include -#include -#include -#include - -#include -#include -/////////////////////////////////////////////////////////////////////////////// - -extern odtone::uint16 kConf_MIHF_Link_Response_Time_Value; -extern odtone::uint16 kConf_MIHF_Link_Delete_Value; - -namespace odtone { namespace mihf { - - - - -/** - * Construct the event service. - * - * @param io The io_service object that event service module will use to - * dispatch handlers for any asynchronous operations performed on - * the socket. - * @param lpool The local transaction pool module. - * @param t The transmit module. - * @param abook The address book module. - * @param lbook The link book module. - * @param ubook The user book module. - */ -event_service::event_service(io_service &io, local_transaction_pool &lpool, - transmit &t, address_book &abook, link_book &lbook, - user_book &ubook) - : _io(io), - _lpool(lpool), - _transmit(t), - _abook(abook), - _link_abook(lbook), - _user_abook(ubook) -{ -} - -/** - * Handler responsible for setting a failure Link Event Subscribe - * response. - * - * @param ec Error code. - * @param in The input message. - */ -void event_service::link_event_subscribe_response_timeout(const boost::system::error_code &ec, meta_message_ptr &in) -{ - if(ec) - return; - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::link_tuple_id link; - meta_message_ptr out(new meta_message()); - - *in >> mih::request(mih::request::event_subscribe) - & mih::tlv_link_identifier(link); - - // Send failure message to the user - ODTONE_LOG(1, "(mism) setting failure response to Link_Event_Subscribe.request"); - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(mih::status_failure) - & mih::tlv_link_identifier(link); - - out->tid(in->tid()); - out->destination(in->source()); - out->source(mihfid); - - _transmit(out); -} - -/** - * Make a subscription for a given user. - * - * @param user The MIH-User/MIHF that request the subscription. - * @param link The link to make the subscription. - * @param events The events to subscribe. - * @return The status of the operation. - */ -mih::status event_service::subscribe(const mih::id &user, - mih::link_tuple_id &link, - mih::mih_evt_list &events) -{ - event_registration_t reg; - reg.user.assign(user.to_string()); - reg.link = link; - - boost::mutex::scoped_lock lock(_event_mutex); - - for(int i = 0; i < 32; i++) { - if (events.get((mih::mih_evt_list_enum) i)) { - reg.event = (mih::mih_evt_list_enum) i; - std::list::iterator tmp; - tmp = std::find(_event_subscriptions.begin(), _event_subscriptions.end(), reg); - if (tmp == _event_subscriptions.end()) { - _event_subscriptions.push_back(reg); - ODTONE_LOG(3, "(mies) added subscription ", reg.user, - ":", reg.link.addr, ":", reg.event); - } - } - } - - return mih::status_success; -} - -/** - * Deserialize the message, subscribe the user and send a response immediatly - * if the events are already subscribed with the Link SAP. Otherwise, the MIHF - * sends a request to the Link SAP to subscribe the desired events. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::local_event_subscribe_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - mih::mih_evt_list events; - mih::link_tuple_id link; - - // TODO: optional is not take in cosideration yet - *in >> mih::request(mih::request::event_subscribe) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - - mih::octet_string link_id = _link_abook.search_interface(link.type, link.addr); - - // Check if the Link SAP exists - // If not replies with a failure status - if(link_id.compare("") == 0) { - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(mih::status_failure) - & mih::tlv_link_identifier(link); - - out->tid(in->tid()); - out->source(mihfid); - out->destination(in->source()); - - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.response to ", - out->destination().to_string()); - - return true; - } - - // Check if requested events have been already subscribed - mih::mih_evt_list event_tmp; - { - boost::mutex::scoped_lock lock(_event_mutex); - - BOOST_FOREACH(event_registration_t item, _event_subscriptions) - { - if(item.link == link) - event_tmp.set(item.event); - } - } - - if(events == event_tmp) { - mih::status st = subscribe(in->source(), link, events); - - if(st == mih::status_success) { - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - } else { - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link); - } - - out->tid(in->tid()); - out->source(mihfid); - out->destination(in->source()); - - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.response to ", - out->destination().to_string()); - - return true; - } else { // Subscribe requested events with Link SAP - mih::link_evt_list evt; - // Since the two bitmaps have the same values - // we can assign them directly - for (size_t i = 0; i < 32; ++i) { - if(events.get((mih::mih_evt_list_enum)i)) { - evt.set((mih::link_evt_list_enum)i); - } - } - // - - *out << mih::request(mih::request::event_subscribe) - & mih::tlv_link_evt_list(evt); - - out->destination(mih::id(link_id)); - out->source(in->source()); - out->tid(in->tid()); - - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(out->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = out->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } else { - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - - // Set the timer that will be responsible for sending a failure - // response if necessary - boost::shared_ptr timer = boost::make_shared(_io); - timer->expires_from_now(boost::posix_time::milliseconds(kConf_MIHF_Link_Response_Time_Value)); - timer->async_wait(boost::bind(&event_service::link_event_subscribe_response_timeout, this, _1, in)); - - { - boost::mutex::scoped_lock lock(_mutex); - _timer[in->tid()] = timer; - } - } - - return false; - } -} - -/** - * Event Subscribe Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_subscribe_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Subscribe.request from ", - in->source().to_string()); - - if (utils::this_mihf_is_destination(in)) { - return local_event_subscribe_request(in, out); - } else { - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Event Subscribe Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_subscribe_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Subscribe.response from ", - in->source().to_string()); - - // do we have a request from a user? - if (!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mies) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - mih::status st; - mih::link_tuple_id link; - boost::optional events; - - // parse incoming message to (event_registration_t) reg - *in >> mih::response() - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - - - std::cout<< "(mies) The link received is "<destination().to_string()), link, events.get()); - } - - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.response to ", - in->destination().to_string()); - - // forward to user - _transmit(in); - - return false; -} - -/** - * Event Subscribe Confirm message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_subscribe_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Subscribe.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - // do we have a request from a user? - out->source(in->source()); - if (!_lpool.set_user_tid(out)) { - ODTONE_LOG(1, "(mies) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - { - boost::mutex::scoped_lock lock(_mutex); - _timer.erase(in->tid()); - } - - mih::status st; - boost::optional events; - - *in >> mih::confirm(mih::confirm::event_subscribe) - & mih::tlv_status(st) - & mih::tlv_link_evt_list(events); - - mih::link_tuple_id link; - link.type = _link_abook.get(in->source().to_string()).link_id.type; - link.addr = _link_abook.get(in->source().to_string()).link_id.addr; - - if(st == mih::status_success) { - mih::mih_evt_list evt; - - // Since the two bitmaps have the same values - // we can assign them directly - for (size_t i = 0; i < 32; ++i) { - if(events.get().get((mih::link_evt_list_enum)i)) { - evt.set((mih::mih_evt_list_enum)i); - } - } - // - - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(evt); - - st = subscribe(mih::id(out->destination().to_string()), link, evt); - } else { - *out << mih::response(mih::response::event_subscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link); - } - - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.confirm to ", - out->destination().to_string()); - - // forward to user - out->source(mihfid); - _transmit(out); - - return false; -} - -/** - * Check if there is events subscribed to a given Link SAP, which - * are not required anymore. - * - * @param in The input message. - * @param link The link to make the unsubscription. - * @param events The events to unsubscribed. - */ -void event_service::link_unsubscribe(meta_message_ptr &in, - mih::link_tuple_id &link, - mih::mih_evt_list &events) -{ - boost::mutex::scoped_lock lock(_event_mutex); - - // Check if requested events have been already subscribed - mih::mih_evt_list event_unsubscribe = events; - BOOST_FOREACH(event_registration_t item, _event_subscriptions) - { - if(item.link == link) { - if(item.user.compare(in->source().to_string()) != 0) { - event_unsubscribe.clear(item.event); - } - } - } - - // Only send message to Link SAP if there is any event to unsubscribed - // with it - mih::mih_evt_list empty; - if(!(empty == event_unsubscribe)) - { - mih::link_evt_list evt; - // Since the two bitmaps have the same values - // we can assign them directly - for (size_t i = 0; i < 32; ++i) { - if(event_unsubscribe.get((mih::mih_evt_list_enum)i)) { - evt.set((mih::link_evt_list_enum)i); - } - } - // - - *in << mih::request(mih::request::event_unsubscribe) - & mih::tlv_link_evt_list(evt); - - mih::octet_string link_id = _link_abook.search_interface(link.type, link.addr); - in->destination(mih::id(link_id)); - in->source(mihfid); - - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(in->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = in->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } - else { - ODTONE_LOG(1, "(mies) forwarding Event_Subscribe.request to ", - in->destination().to_string()); - utils::forward_request(in, _lpool, _transmit); - } - } -} - -/** - * Unsubscribe the events related to a given user. - * - * @param user The MIH-User/MIHF that request the unsubscription. - * @param link The link to make the unsubscription. - * @param events The events to unsubscribe. - * @return The status of the operation. - */ -mih::status event_service::unsubscribe(const mih::id &user, - mih::link_tuple_id &link, - mih::mih_evt_list &events) -{ - boost::mutex::scoped_lock lock(_event_mutex); - - std::list::iterator it; - - it = _event_subscriptions.begin(); - while (it != _event_subscriptions.end()) - { - if (it->link == link && - (it->user.compare(user.to_string()) == 0) && - events.get((mih::mih_evt_list_enum) it->event)) { - ODTONE_LOG(3, "(mies) removed subscription ", it->user, - ":", it->link.addr ,":", it->event); - _event_subscriptions.erase(it++); - } - else { - it++; - } - } - - return mih::status_success; -} - -/** - * Deserialize message, unsubscribe user and send a response to the - * requestor. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::local_event_unsubscribe_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - mih::status st; - mih::link_tuple_id link; - mih::mih_evt_list events; - - *in >> mih::request(mih::request::event_unsubscribe) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - - st = unsubscribe(in->source(), link, events); - - *out << mih::response(mih::response::event_unsubscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - - out->tid(in->tid()); - out->source(mihfid); - out->destination(in->source()); - - // Check if there is any request for the events - link_unsubscribe(in, link, events); - - ODTONE_LOG(1, "(mies) forwarding Event_Unsubscribe.response to ", - out->destination().to_string()); - - return true; -} - -/** - * Event Unsubscribe Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_unsubscribe_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Unsubscribe.request from ", - in->source().to_string()); - - if (utils::this_mihf_is_destination(in)) { - return local_event_unsubscribe_request(in, out); - } else { - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Event Unsubscribe Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_unsubscribe_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Unsubscribe.response from ", - in->source().to_string()); - - // do we have a request from a user? - if (!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - - return false; - } - - mih::status st; - mih::link_tuple_id link; - boost::optional events; - - // parse incoming message to (event_registration_t) reg - *in >> mih::response(mih::response::event_unsubscribe) - & mih::tlv_status(st) - & mih::tlv_link_identifier(link) - & mih::tlv_event_list(events); - - // remove subscription - if (st == mih::status_success) { - st = unsubscribe(mih::id(in->destination().to_string()), link, events.get()); - } - - ODTONE_LOG(1, "(mies) forwarding Event_Unsubscribe.response to ", - in->destination().to_string()); - - // forward to user - in->opcode(mih::operation::response); - _transmit(in); - - return false; -} - -/** - * Event Unsubscribe Confirm message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::event_unsubscribe_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Event_Unsubscribe.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - // do we have a request from a user? - if (!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mies) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - mih::status st; - boost::optional events; - - // parse incoming message to (event_registration_t) reg - *in >> mih::confirm(mih::confirm::event_unsubscribe) - & mih::tlv_status(st) - & mih::tlv_link_evt_list(events); - - if (st == mih::status_success) { - ODTONE_LOG(1, "(mies) Events successfully unsubscribed in Link SAP ", - in->source().to_string()); - } - - return false; -} - -/** - * Forward the message for all users subscribed to event from the - * Link SAP. - * - * @param msg The MIH Message. - * @param li The link identifier. - * @param event The related event. - */ -void event_service::msg_forward(meta_message_ptr &msg, - mih::link_tuple_id &li, - mih::mih_evt_list_enum event) -{ - std::list::iterator it; - int i = 0; // for logging purposes - - if(msg->is_local()) - msg->source(mihfid); - - for(it = _event_subscriptions.begin(); - it != _event_subscriptions.end(); - it++, i++) { - ODTONE_LOG(3, "(mies) msg_forward() comparing event ", event, " with event_subscription it->event ", it->event); - ODTONE_LOG(3, "(mies) msg_forward() comparing link_tuple_id.type ", li.type, " with event_subscription it->link.type ", it->link.type); - ODTONE_LOG(3, "(mies) msg_forward() comparing link_tuple_id.addr ", li.addr, " with event_subscription it->link.addr ", it->link.addr); - if ((it->event == event) && (it->link == li)) { - ODTONE_LOG(3, "(mies) found registration of user: ", - it->user, " for event type ", event); - msg->destination(mih::id(it->user)); - _transmit(msg); - } - } - ODTONE_LOG(3, "(mies) msg_forward() end"); -} - - -/** - * Parse the link identifier from incoming message and forwards the - * message to subscribed users - * - * @param msg The MIH Message. - * @param event The related event. - */ -void event_service::link_event_forward(meta_message_ptr &msg, - mih::mih_evt_list_enum event) -{ - mih::link_tuple_id li; - ODTONE_LOG(1, "(mies) link_event_forward()"); - *msg >> mih::indication() - & mih::tlv_link_identifier(li); - - msg_forward(msg, li, event); -} - - -/** - * Link Up Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_up_indication(meta_message_ptr &in, meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Up.indication from ", - in->source().to_string()); - - if(in->is_local()) { - ODTONE_LOG(1, "(mies) link_up_indication() reset ", in->source().to_string() ," in link_abook"); - _link_abook.reset(in->source().to_string()); - } - - link_event_forward(in, mih::mih_evt_link_up); - - return false; -} - - -/** - * Link Down Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_down_indication(meta_message_ptr &in, meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Down.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - link_event_forward(in, mih::mih_evt_link_down); - - return false; -} - - -/** - * Link Detected Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_detected_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Detected.indication from ", - in->source().to_string()); - - if(in->is_local()) { - _link_abook.reset(in->source().to_string()); - // link detected info from incoming message - mih::link_det_info link_info; - // link detected info on outgoing message - mih::link_det_info_list list_rsp; - - *in >> mih::indication() - & mih::tlv_link_det_info(link_info); - - list_rsp.push_back(link_info); - - *in << mih::indication(mih::indication::link_detected) - & mih::tlv_link_det_info_list(list_rsp); - } - - std::list::iterator it; - int i = 0; // for logging purposes - - if(in->is_local()) - in->source(mihfid); - - for(it = _event_subscriptions.begin(); - it != _event_subscriptions.end(); - it++, i++) { - if (it->event == mih::mih_evt_link_detected) { - ODTONE_LOG(3, i, " (mies) found registration of user: ", - it->user, " for event type ", mih::mih_evt_link_detected); - in->destination(mih::id(it->user)); - _transmit(in); - } - } - - return false; -} - -/** - * Link Going Down Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_going_down_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Going_Down.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - link_event_forward(in, mih::mih_evt_link_going_down); - - return false; -} - -/** - * Link Parameters Report Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_parameters_report_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Parameters_Report.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - link_event_forward(in, mih::mih_evt_link_parameters_report); - - return false; -} - -/** - * Link Handover Imminent Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_handover_imminent_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Handover_Imminent.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - std::list::iterator it; - int i = 0; // for logging purposes - - if(in->is_local()) - in->source(mihfid); - - for(it = _event_subscriptions.begin(); - it != _event_subscriptions.end(); - it++, i++) { - if (it->event == mih::mih_evt_link_handover_imminent) { - ODTONE_LOG(3, i, " (mies) found registration of user: ", - it->user, " for event type ", mih::mih_evt_link_handover_imminent); - in->destination(mih::id(it->user)); - _transmit(in); - } - } - - return false; -} - -/** - * Link Handover Complete Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_handover_complete_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_Handover_Complete.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - mih::link_tuple_id oli; - mih::link_tuple_id nli; - boost::optional oar; - boost::optional nar; - - if(in->is_local()) { - mih::status st; - *in >> mih::indication(mih::indication::link_handover_complete) - & mih::tlv_link_identifier(oli) - & mih::tlv_new_link_identifier(nli) - & mih::tlv_old_access_router(oar) - & mih::tlv_new_access_router(nar) - & mih::tlv_status(st); - } else { - *in >> mih::indication(mih::indication::link_handover_complete) - & mih::tlv_link_identifier(oli) - & mih::tlv_new_link_identifier(nli) - & mih::tlv_old_access_router(oar) - & mih::tlv_new_access_router(nar); - } - - *in << mih::indication(mih::indication::link_handover_complete) - & mih::tlv_link_identifier(oli) - & mih::tlv_new_link_identifier(nli) - & mih::tlv_old_access_router(oar) - & mih::tlv_new_access_router(nar); - - std::list::iterator it; - int i = 0; // for logging purposes - - if(in->is_local()) - in->source(mihfid); - - for(it = _event_subscriptions.begin(); - it != _event_subscriptions.end(); - it++, i++) { - if (it->event == mih::mih_evt_link_handover_complete) { - ODTONE_LOG(3, i, " (mies) found registration of user: ", - it->user, " for event type ", mih::mih_evt_link_handover_complete); - in->destination(mih::id(it->user)); - _transmit(in); - } - } - - return false; -} - -/** - * Link PDU Transmit Status Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool event_service::link_pdu_transmit_status_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mies) received Link_PDU_Transmit_Status.indication from ", - in->source().to_string()); - - if(in->is_local()) - _link_abook.reset(in->source().to_string()); - - link_event_forward(in, mih::mih_evt_link_pdu_transmit_status); - - return false; -} - -} /* namespace mihf */ } /* namespace odtone */ -// EOF //////////////////////////////////////////////////////////////////////// diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link.hpp deleted file mode 100644 index f9c8718250..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link.hpp +++ /dev/null @@ -1,1353 +0,0 @@ -//============================================================================= -// Brief : MIH Link Types -// Authors : Bruno Santos -// Simao Reis -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_MIH_TYPES_LINK__HPP_ -#define ODTONE_MIH_TYPES_LINK__HPP_ - -/////////////////////////////////////////////////////////////////////////////// -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -namespace odtone { namespace mih { - -/////////////////////////////////////////////////////////////////////////////// -/** - * BATT_LEVEL data type. - */ -typedef uint8 batt_level; - -/** - * NUM_COS data type. - */ -typedef uint8 num_cos; - -/** - * NUM_QUEUE data type. - */ -typedef uint8 num_queue; - -/** - * CHANNEL_ID data type. - */ -typedef uint16 channel_id; - -/** - * CONFIG_STATUS data type. - */ -typedef bool config_status; - -/** - * DEVICE_INFO data type. - */ -typedef octet_string device_info; - -/** - * LINK_AC_EX_TIME data type. - */ -typedef uint16 link_ac_ex_time; - -/** - * SIG_STRENGTH data type. - */ -typedef boost::variant sig_strength; - -/** - * LINK_RES_STATUS data type. - */ -typedef bool link_res_status; - -/** - * MAX_DELAY data type. - */ -typedef uint16 max_delay; - -/** - * BITRATE data type. - */ -typedef uint32 bitrate; - -/** - * JITTER data type. - */ -typedef uint16 jitter; - -/** - * PKT_LOSS_RATE data type. - */ -typedef uint16 pkt_loss_rate; - -/** - * COS data type. - */ -typedef uint16 cos; - -/** - * DROP_ELIGIBILITY data type. - */ -typedef bool drop_eligibility; - -/** - * MULTICAST_ENABLE data type. - */ -typedef bool multicast_enable; - -/** - * JUMBO_ENABLE data type. - */ -typedef bool jumbo_enable; - -/** - * PORT data type. - */ -typedef uint16 port; - -/** - * MARK data type. - */ -typedef uint8 mark; - -/** - * FLOW_ID data type. - */ -typedef uint32 flow_id; - -/////////////////////////////////////////////////////////////////////////////// -/** - * PROTO data type enumeration. - */ -enum proto_enum { - proto_tcp = 0, /**< TCP. */ - proto_udp = 1 /**< UDP. */ -}; - -/** - * PROTO data type. - */ -typedef enumeration proto; -/////////////////////////////////////////////////////////////////////////////// -/** - * OP_MODE data type enumeration. - */ -enum op_mode_enum { - op_mode_normal = 0, /**< Normal mode. */ - op_mode_power_saving = 1, /**< Power saving mode. */ - op_mode_powered_down = 2, /**< Powered Down. */ -}; - -/** - * OP_MODE data type. - */ -typedef enumeration op_mode; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_STATES_RSP data type. - */ -typedef boost::variant link_states_rsp; - -/** - * LIST(LINK_STATES_RSP) data type. - */ -typedef std::vector link_states_rsp_list; - -/** - * LINK_DESC_RSP data type. - */ -typedef boost::variant link_desc_rsp; - -/** - * LIST(LINK_DESC_RSP) data type. - */ -typedef std::vector link_desc_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * DEV_STATES_REQ data type enumeration. - */ -enum dev_states_req_enum { - dev_state_device_info = 0, /**< Device information. */ - dev_state_batt_level = 1, /**< Battery level. */ -}; - -/** - * DEV_STATES_REQ data type. - */ -typedef bitmap<16, dev_states_req_enum> dev_states_req; - -/////////////////////////////////////////////////////////////////////////////// -/** - * DEV_STATES_RSP data type. - */ -typedef boost::variant dev_states_rsp; - -/** - * LIST(DEV_STATES_RSP) data type. - */ -typedef std::vector dev_states_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_STATES_REQ data type enumeration. - */ -enum link_states_req_enum { - link_states_req_op_mode = 0, /**< Operation mode. */ - link_states_req_channel_id = 1, /**< Channel identifier. */ -}; - -/** - * LINK_STATES_REQ data type. - */ -typedef bitmap<16, link_states_req_enum> link_states_req; - -/** - * LIST(LINK_STATES_REQ) data type. - */ -typedef std::vector link_states_req_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * THRESHOLD data type. - */ -struct threshold { - /** - * Threshold direction enumeration. - */ - enum type_ip_enum { - above_threshold = 0, /**< Above threshold. */ - below_threshold = 1, /**< Below threshold. */ - }; - - /** - * Serialize/deserialize the THRESHOLD data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & threshold_val; - ar & threshold_x_dir; - } - - uint16 threshold_val; /**< Threshold value. */ - enumeration threshold_x_dir; /**< Threshold Direction. */ -}; -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_TYPE data type enumeration. - */ -enum link_type_enum { - link_type_gsm = 1, /**< Wireless - GSM. */ - link_type_gprs = 2, /**< Wireless - GPRS. */ - link_type_edge = 3, /**< Wireless - EDGE. */ - - link_type_ethernet = 15, /**< Ethernet. */ - - link_type_wireless_other = 18, /**< Wireless - Other. */ - link_type_802_11 = 19, /**< Wireless - IEEE 802.11. */ - - link_type_cdma2000 = 22, /**< Wireless - CDMA-2000. */ - link_type_umts = 23, /**< Wireless - UMTS. */ - link_type_cdma2000_hrpd = 24, /**< Wireless - CDMA-2000-HRPD. */ - link_type_lte = 25, /**< Wireless - LTE. */ - - link_type_802_16 = 27, /**< Wireless - IEEE 802.16. */ - link_type_802_20 = 28, /**< Wireless - IEEE 802.20. */ - link_type_802_22 = 29 /**< Wireless - IEEE 802.22. */ -}; - -/** - * LINK_TYPE data type. - */ -typedef enumeration link_type; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_ID data type. - */ -struct link_id { - /** - * Construct an empty LINK_ID data type. - */ - link_id() : type(link_type_enum(0)) - { } - - /** - * Serialize/deserialize the LINK_ID data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & type; - ar & addr; - } - - /** - * Check if the LINK_ID data type is equal to another LINK_ID. - * - * @param other The LINK_ID to compare to. - * @return True if they are equal or false otherwise. - */ - bool operator==(const link_id& other) const - { - return ((type == other.type) && (addr == other.addr)); - } - - /** - * LINK_ID data type output. - * - * @param out ostream. - * @param addr LINK_ID data type. - * @return ostream reference. - */ friend std::ostream& operator<<(std::ostream& out, const link_id& lid) - { - out << "link id " << lid.type << " " << lid.addr; - return out; - } - - - link_type type; /**< Link address type. */ - link_addr addr; /**< Link address. */ -}; - -/** - * LIST(LINK_ID) data type. - */ -typedef std::vector link_id_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * IP_TUPLE data type. - */ -struct ip_tuple { - /** - * Serialize/deserialize the IP_TUPLE data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & ip; - ar & port_val; - } - - ip_addr ip; /**< IP address.*/ - port port_val; /**< Port. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * Auxiliar QOS data type. - */ -struct qos_sequence { - /** - * Serialize/deserialize the auxiliar QOS data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & delay_val; - ar & bitrate_val; - ar & jitter_val; - ar & pkt_loss_val; - } - - max_delay delay_val; /**< Maximum delay. */ - bitrate bitrate_val; /**< Bitrate. */ - jitter jitter_val; /**< Jitter. */ - pkt_loss_rate pkt_loss_val; /**< Packet loss. */ -}; - -/** - * QOS data type. - */ -struct qos { - /** - * Serialize/deserialize the QOS data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & value; - } - - boost::variant value; /**< QoS value. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * Auxiliar MARK_QoS data type. - */ -struct mark_qos_sequence { - /** - * Serialize/deserialize the auxiliar FLOW_ATTRIBUTE data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & mark_val; - ar & qos_val; - } - - mark mark_val; /**< Mark value. */ - qos qos_val; /**< QoS value. */ -}; - -/** - * Auxiliar MARK_DROP_ELIG data type. - */ -struct mark_drop_elig_sequence { - /** - * Serialize/deserialize the auxiliar FLOW_ATTRIBUTE data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & mark_val; - ar & drop_val; - } - - mark mark_val; /**< Mark value. */ - drop_eligibility drop_val; /**< Drop eligibility value. */ -}; - -/** - * FLOW_ATTRIBUTE data type. - */ -struct flow_attribute { - /** - * Serialize/deserialize the FLOW_ATTRIBUTE data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & multicast; - ar & qos_val; - ar & drop_elig_val; - } - - flow_id id; /**< Flow ID. */ - boost::variant multicast; /**< Multicast enable. */ - boost::variant qos_val; /**< Mask/QoS value. */ - boost::variant drop_elig_val; /**< Mask/drop eligibility value. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * RESOURCE_DESC data type. - */ -struct resource_desc { - /** - * Serialize/deserialize the RESOURCE_DESC data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & lid; - ar & fid; - ar & data_rate; - ar & qos_val; - ar & jumbo; - ar & multicast; - } - - link_id lid; /**< Link ID. */ - flow_id fid; /**< Flow ID. */ - boost::variant data_rate; /**< Link data rate. */ - boost::variant qos_val; /**< QoS value. */ - boost::variant jumbo; /**< Jumbo enable. */ - boost::variant multicast; /**< Multicast enable. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_AC_RESULT data type enumeration. - */ -enum link_ac_result_enum { - link_ac_success = 0, /**< Success. */ - link_ac_failure = 1, /**< Failure. */ - link_ac_refused = 2, /**< Refused. */ - link_ac_incapable = 3, /**< Incapable. */ -}; - -/** - * LINK_AC_RESULT data type. - */ -typedef enumeration link_ac_result; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_AC_TYPE data type enumeration. - */ -enum link_ac_type_enum { - link_ac_type_none = 0, /**< None. */ - link_ac_type_disconnect = 1, /**< Link disconnect. */ - link_ac_type_low_power = 2, /**< Link low power. */ - link_ac_type_power_down = 3, /**< Link power down. */ - link_ac_type_power_up = 4, /**< Link power up. */ - link_ac_type_flow_attr = 5, /**< Flow Attribute. */ - link_ac_type_link_activate_resources = 6, /**< Link Activate Resources. */ - link_ac_type_link_deactivate_resources = 7, /**< Link Deactivate Resources. */ -}; - -/** - * LINK_AC_TYPE data type. - */ -typedef enumeration link_ac_type; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_AC_ATTR data type enumeration. - */ -enum link_ac_attr_enum { - link_ac_attr_scan = 0, /**< Link scan. */ - link_ac_attr_res_retain = 1, /**< Link resource retain. */ - link_ac_attr_data_fwd_req = 2, /**< Link data forward. */ -}; - -/** - * LINK_AC_ATTR data type. - */ -typedef bitmap<8, link_ac_attr_enum> link_ac_attr; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_AC_PARAM data type. - */ -struct link_ac_param { - /** - * Serialize/deserialize the LINK_AC_PARAM data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & param; - } - - boost::variant param; /**< Link action parameter.*/ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_ACTION data type. - */ -struct link_action { - link_ac_type type; /**< Link action type. */ - link_ac_attr attr; /**< Link action attribute. */ - link_ac_param param;/**< Link action parameter. */ - - /** - * Serialize/deserialize the LINK_ACTION data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - {; - ar & type; - ar & attr; - ar & param; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * TH_ACTION data type enumeration. - */ -enum th_action_enum { - th_action_normal = 0, /**< Set normal threshold. */ - th_action_one_shot = 1, /**< Set one-shot threshold. */ - th_action_cancel = 2 /**< Cancel threshold. */ -}; - -/** - * TH_ACTION data type. - */ -typedef enumeration th_action; - - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_DN_REASON data type enumeration. - */ -enum link_dn_reason_enum { - link_dn_reason_explicit_disconnect = 0, /**< Explicit disconnect. */ - link_dn_reason_packet_timeout = 1, /**< Packet timeout. */ - link_dn_reason_no_resource = 2, /**< No resource. */ - link_dn_reason_no_broadcast = 3, /**< No broadcast. */ - link_dn_reason_authentication_failure = 4, /**< Authentication failure. */ - link_dn_reason_billing_failure = 5, /**< Billing failure. */ -}; - -/** - * LINK_DN_REASON data type. - */ -typedef enumeration link_dn_reason; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_GD_REASON data type enumeration. - */ -enum link_gd_reason_enum { - link_gd_reason_explicit_disconnect = 0, /**< Explicit disconnect. */ - link_gd_reason_link_parameter_degrading = 1, /**< Link parameter degrading. */ - link_gd_reason_low_power = 2, /**< Low power. */ - link_gd_reason_no_resource = 3, /**< No resource. */ -}; - -/** - * LINK_GD_REASON data type. - */ -typedef enumeration link_gd_reason; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_MIHCAP_FLAG data type enumeration. - */ -enum link_mihcap_flag_enum { - link_mihcap_event_service = 1, /**< Event service. */ - link_mihcap_command_service = 2, /**< Command service. */ - link_mihcap_information_service = 3, /**< Information service. */ -}; - -/** - * LINK_MIHCAP_FLAG data type. - */ -typedef bitmap<8, link_mihcap_flag_enum> link_mihcap_flag; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_GEN data type enumeration. - */ -enum link_param_gen_enum { - link_param_gen_data_rate = 0, /**< Data rate. */ - link_param_gen_signal_strength = 1, /**< Signal strength. */ - link_param_gen_sinr = 2, /**< SINR. */ - link_param_gen_throughput = 3, /**< Throughput. */ - link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -}; - -/** - * LINK_PARAM_GEM data type. - */ -typedef enumeration link_param_gen; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_QOS data type. - */ -typedef uint8 link_param_qos; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_GG data type enumeration. - */ -enum link_param_gg_enum { - link_param_gg_rx_qual = 0, /**< RxQual. */ - link_param_gg_rs_lev = 1, /**< RsLev. */ - link_param_gg_mean_bep = 2, /**< Mean BEP. */ - link_param_gg_st_dev_bep = 3, /**< StDev BEP. */ -}; - -/** - * LINK_PARAM_GG data type. - */ -typedef enumeration link_param_gg; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_EDGE data type enumeration. - */ -enum link_param_edge_enum { -}; - -/** - * LINK_PARAM_EDGE data type. - */ -typedef enumeration link_param_edge; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_ETH data type enumeration. - */ -enum link_param_eth_enum { -}; - -/** - * LINK_PARAM_ETH data type. - */ -typedef enumeration link_param_eth; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_802_11 data type enumeration. - */ -enum link_param_802_11_enum { - link_param_802_11_rssi = 0, /**< RSSI. */ - link_param_802_11_no_qos = 1, /**< No QoS resource available. */ - link_param_802_11_multicast_packet_loss_rate = 2, /**< Multicast packet loss rate.*/ -}; - -/** - * LINK_PARAM_802_11 data type. - */ -typedef enumeration link_param_802_11; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_C2K data type enumeration. - */ -enum link_param_c2k_enum { - link_param_c2k_pilot_strength = 0, /**< Pilot strength. */ -}; - -/** - * LINK_PARAM_C2K data type. - */ -typedef enumeration link_param_c2k; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_FFD data type enumeration. - */ -enum link_param_ffd_enum { - link_param_ffd_cpich_rscp = 0, /**< CPICH RSCP. */ - link_param_ffd_pccpch_rscp = 1, /**< PCCPCH RSCP. */ - link_param_ffd_ultra_carrie_rssi = 2, /**< UTRA carrier RSSI. */ - link_param_ffd_gsm_carrie_rssi = 3, /**< GSM carrier RSSI. */ - link_param_ffd_cpich_ec_no = 4, /**< CPICH Ec/No. */ - link_param_ffd_transport_channel_bler = 5, /**< Transport channel BLER.*/ - link_param_ffd_ue = 6, /**< UE transmitted power. */ -}; - -/** - * LINK_PARAM_FFD data type. - */ -typedef enumeration link_param_ffd; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_HRPD data type enumeration. - */ -enum link_param_hrpd_enum { - link_param_hrpd_pilot_strength = 0, /**< HRPD pilot strength. */ -}; - -/** - * LINK_PARAM_HRPD data type. - */ -typedef enumeration link_param_hrpd; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_802_16 data type enumeration. - */ -enum link_param_802_16_enum { -}; - -/** - * LINK_PARAM_802_16 data type. - */ -typedef enumeration link_param_802_16; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_802_20 data type enumeration. - */ -enum link_param_802_20_enum { -}; - -/** - * LINK_PARAM_802_20 data type. - */ -typedef enumeration link_param_802_20; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_802_22 data type enumeration. - */ -enum link_param_802_22_enum { -}; - -/** - * LINK_PARAM_802_22 data type. - */ -typedef enumeration link_param_802_22; - - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_lte data type enumeration. - */ -enum link_param_lte_enum { - link_param_lte_rsrp = 0, /**< RSSI. */ - link_param_lte_rsrq = 1, /**< No QoS resource available. */ - link_param_lte_cqi = 2, /**< Multicast packet loss rate.*/ - link_param_lte_bandwidth = 3, /**< System Load. */ - link_param_lte_pkt_delay = 4, /**< Number of registered users. */ - link_param_lte_pkt_loss = 5, /**< Number of active users. */ - link_param_lte_l2_buffer = 6, /**< Congestion windows of users. */ - link_param_lte_MN_cap = 7, /**< Congestion windows of users. */ - link_param_lte_embms = 8, /**< Congestion windows of users. */ - link_param_lte_jumbo_feasibility = 9, /**< Congestion windows of users. */ - link_param_lte_jumbo_setup = 10, /**< Congestion windows of users. */ - link_param_lte_active_embms = 11, /**< Transmission rate of users. */ - link_param_lte_link_congestion = 12, /**< Link congestion. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_LTE data type. - */ -typedef enumeration link_param_lte; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_TUPLE_ID data type. - */ -class link_tuple_id : public link_id { -public: - /** - * Construct an empty LINK_TUPLE_ID data type. - */ - link_tuple_id() : poa_addr(null()) - { } - - /** - * Serialize/deserialize the LINK_TUPLE_ID data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - link_id::serialize(ar); - ar & poa_addr; - } - - /** - * Check if the LINK_TUPLE_ID data type is equal to another LINK_TUPLE_ID. - * - * @param other The LINK_TUPLE_ID to compare to. - * @return True if they are equal or false otherwise. - */ - bool operator==(const link_tuple_id& other) const - { - return ((static_cast(*this) == static_cast(other)) - && (addr == other.addr)); - } - - boost::variant poa_addr; /**< PoA link address. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_SCAN_RSP data type. - */ -struct link_scan_rsp { - link_addr id; /**< Link address. */ - octet_string net_id; /**< Network identifier. */ - sig_strength signal; /**< Signal strength. */ - - /** - * Serialize/deserialize the LINK_SCAN_RSP data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & net_id; - ar & signal; - } -}; - -/** - * LIST(LINK_SCAN_RSP) data type. - */ -typedef std::vector link_scan_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_ACTION_REQ data type. - */ -struct link_action_req { - link_id id; /**< Link identifier. */ - boost::variant addr; /**< PoA link address. */ - link_action action; /**< Link action. */ - link_ac_ex_time ex_time; /**< Link action execution time.*/ - - /** - * Serialize/deserialize the LINK_ACTION_REQ data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & addr; - ar & action; - ar & ex_time; - } -}; - -/** - * LIST(LINK_ACTION_REQ) data type. - */ -typedef std::vector link_action_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_ACTION_RSP data type. - */ -struct link_action_rsp { - link_id id; /**< Link identifier. */ - link_ac_result result; /**< Link action result.*/ - boost::variant scan_list; /**< Link action response list.*/ - - /** - * Serialize/deserialize the LINK_ACTION_RSP data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & result; - ar & scan_list; - } -}; - -/** - * LIST(LINK_ACTION_RSP) data type. - */ -typedef std::vector link_action_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_EVT_LIST data type enumeration. - */ -enum link_evt_list_enum { - evt_link_detected = 0, /**< Link detected */ - evt_link_up = 1, /**< Link up */ - evt_link_down = 2, /**< Link down */ - evt_link_parameters_report = 3, /**< Link parameters report */ - evt_link_going_down = 4, /**< Link doing down */ - evt_link_handover_imminent = 5, /**< Link handover imminent */ - evt_link_handover_complete = 6, /**< Link handover complete */ - evt_link_pdu_transmit_status = 7, /**< Link PDU transmit status */ -}; - -/** - * LINK_EVT_LIST data type. - */ -typedef bitmap<32, link_evt_list_enum> link_evt_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_CMD_LIST data type enumeration. - */ -enum link_cmd_list_enum { - cmd_link_event_subscribe = 1, /**< Event subscribe. */ - cmd_link_event_unsubscribe = 2, /**< Event unsubscribe. */ - cmd_link_get_parameters = 3, /**< Get parameters. */ - cmd_link_configure_thresholds = 4, /**< Configure thresholds. */ - cmd_link_action = 5, /**< Action. */ -}; - -/** - * LINK_CMD_LIST data type. - */ -typedef bitmap<32, link_cmd_list_enum> link_cmd_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_DET_CFG data type. - */ -struct link_det_cfg { - /** - * Serialize/deserialize the LINK_DET_CFG data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & network_id; - ar & signal; - ar & link_data_rate; - } - - boost::variant network_id; /**< Network identifier.*/ - boost::variant signal; /**< Signal strength. */ - boost::variant link_data_rate; /**< Link data rate. */ -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_TYPE data type. - */ -typedef boost::variant link_param_type; - -/** - * LIST(LINK_PARAM_TYPE) data type. - */ -typedef std::vector link_param_type_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_DESC_REQ_LIST data type enumeration. - */ -enum link_desc_req_enum { - link_desc_req_classes_of_service_supported = 0, /**< Number of classes of services supported.*/ - link_desc_req_queues_supported = 1, /**< Number of queues supported.*/ -}; - -/** - * LINK_DESC_REQ data type. - */ -typedef bitmap<16, link_desc_req_enum> link_desc_req; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_STATUS_REQ data type. - */ -struct link_status_req { - link_states_req _states_req; /**< Link states to be requested.*/ - link_param_type_list _param_type_list; /**< Link parameter type list. */ - link_desc_req _desc_req; /**< Link dsecriptors. */ - - /** - * Serialize/deserialize the LINK_STATUS_REQ data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & _states_req; - ar & _param_type_list; - ar & _desc_req; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_VAL data type. - */ -typedef uint16 link_param_val; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM data type. - */ -struct link_param { - /** - * Serialize/deserialize the LINK_PARAM data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & type; - ar & value; - } - - link_param_type type; /**< Link parameter type. */ - boost::variant value; /**< Link parameter value. */ -}; - -/** - * LINK_PARAM_LIST data type. - */ -typedef std::vector link_param_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_PARAM_RPT data type. - */ -struct link_param_report { - /** - * Construct a LINK_PARAM_RPT data type. - */ - link_param_report() : thold(null()) - { } - - /** - * Serialize/deserialize the LINK_PARAM_RPT data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & param; - ar & thold; - } - - - link_param param; /**< Link parameter. */ - boost::variant thold; /**< Threshold. */ -}; - -/** - * LIST(LINK_PARAM_RPT) data type. - */ -typedef std::vector link_param_rpt_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_CFG_PARAM data type. - */ -struct link_cfg_param { - /** - * Serialize/deserialize the LINK_CFG_PARAM data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & type; - ar & timer_interval; - ar & action; - ar & threshold_list; - } - - link_param_type type; /**< Link parameter type.*/ - boost::variant timer_interval; /**< Timer interval. */ - th_action action; /**< Action to apply to the listed thresholds.*/ - std::vector threshold_list; /**< Thresholds. */ -}; - -/** - * LIST(LINK_CFG_PARAM) data type. - */ -typedef std::vector link_cfg_param_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_CFG_STATUS data type. - */ -struct link_cfg_status { - link_param_type type; /**< Link parameter type. */ - threshold thold; /**< Threshold. */ - config_status status; /**< Link parameter configuration status. */ - - /** - * Serialize/deserialize the LINK_CFG_STATUS data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & type; - ar & thold; - ar & status; - } -}; - -/** - * LIST(LINK_CFG_STATUS) data type. - */ -typedef std::vector link_cfg_status_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * NET_CAPS data type enumeration. - */ -enum net_caps_enum { - net_caps_security = 0, /**< Security. */ - net_caps_qos_0 = 1, /**< QoS Class 0. */ - net_caps_qos_1 = 2, /**< QoS Class 1. */ - net_caps_qos_2 = 3, /**< QoS Class 2. */ - net_caps_qos_3 = 4, /**< QoS Class 3. */ - net_caps_qos_4 = 5, /**< QoS Class 4. */ - net_caps_qos_5 = 6, /**< QoS Class 5. */ - net_caps_internet = 7, /**< Internet access. */ - net_caps_emergency_services = 8, /**< Emergency services. */ - net_caps_mih = 9, /**< MIH capability. */ -}; - -/** - * NET_CAPS data type. - */ -typedef bitmap<32, net_caps_enum> net_caps; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_DET_INFO data type. - */ -struct link_det_info { - /** - * Serialize/deserialize the LINK_DET_INFO data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & network_id; - ar & net_aux_id; - ar & signal; - ar & sinr; - ar & data_rate; - ar & mih_capabilities; - ar & net_capabilities; - } - - link_tuple_id id; /**< Link tuple identifier. */ - octet_string network_id; /**< Network identifier. */ - octet_string net_aux_id; /**< Auxiliar network identifier. */ - sig_strength signal; /**< Signal strength. */ - uint16 sinr; /**< SINR. */ - uint32 data_rate; /**< Link data rate. */ - link_mihcap_flag mih_capabilities; /**< MIH capabilities. */ - net_caps net_capabilities; /**< Network capabilities. */ -}; - -/** - * LIST(LINK_DET_INFO) data type. - */ -typedef std::vector link_det_info_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_POA_LIST data type. - */ -struct link_poa_list { - /** - * Serialize/deserialize the LINK_POA_LIST data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & addr_list; - } - - link_id id; /**< Link identifier. */ - link_addr_list addr_list; /**< Link address list. */ -}; - -/** - * LIST(LINK_POA_LIST) data type. - */ -typedef std::vector list_of_link_poa_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * LINK_STATUS_RSP data type. - */ -struct link_status_rsp { - /** - * Serialize/deserialize the LINK_STATUS_RSP data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & states_rsp_list; - ar & param_list; - ar & desc_rsp_list; - } - - - link_states_rsp_list states_rsp_list; /**< Link states response list. */ - link_param_list param_list; /**< Link parameter list. */ - link_desc_rsp_list desc_rsp_list; /**< Link descriptors response list.*/ -}; - -/** - * LIST(LINK_STATUS_RSP) data type. - */ -typedef std::vector link_status_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -/** - * SEQUENCE(LINK_ID,LINK_STATUS_RSP) data type. - */ -struct status_rsp { - /** - * Serialize/deserialize the SEQUENCE(LINK_ID,LINK_STATUS_RSP) data type. - * - * @param ar The archive to/from where serialize/deserialize the data type. - */ - template - void serialize(ArchiveT& ar) - { - ar & id; - ar & rsp; - } - - link_id id; /**< Link identifier. */ - link_status_rsp rsp; /**< Link status response. */ -}; - -/** - * LIST(SEQUENCE(LINK_ID,LINK_STATUS_RSP)) data type. - */ -typedef std::vector status_rsp_list; - -/////////////////////////////////////////////////////////////////////////////// -} /* namespace mih */ } /*namespace odtone */ - -// EOF //////////////////////////////////////////////////////////////////////// -#endif /* ODTONE_MIH_TYPES_LINK__HPP_ */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link_book.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link_book.cpp deleted file mode 100644 index 271112ece2..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/link_book.cpp +++ /dev/null @@ -1,290 +0,0 @@ -//============================================================================== -// Brief : Link Book -// Authors : Carlos Guimarães -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "link_book.hpp" -#include "log.hpp" - -/////////////////////////////////////////////////////////////////////////////// - -namespace odtone { namespace mihf { - -//----------------------------------------------------------------------------- -static std::string evt2string(mih::link_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(mih::evt_link_detected)) s += "DETECTED "; - if(evtP.get(mih::evt_link_up)) s += "UP "; - if(evtP.get(mih::evt_link_down)) s += "DOWN "; - if(evtP.get(mih::evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(mih::evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(mih::evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(mih::evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(mih::evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -enum link_cmd_list_enum { - cmd_link_event_subscribe = 1, /**< Event subscribe. */ - cmd_link_event_unsubscribe = 2, /**< Event unsubscribe. */ - cmd_link_get_parameters = 3, /**< Get parameters. */ - cmd_link_configure_thresholds = 4, /**< Configure thresholds. */ - cmd_link_action = 5, /**< Action. */ -}; -//----------------------------------------------------------------------------- -static std::string cmd2string(mih::link_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(mih::cmd_link_event_subscribe)) s += "EVENT_SUBSCRIBE "; - if(cmdP.get(mih::cmd_link_event_unsubscribe)) s += "EVENT_UNSUBSCRIBE"; - if(cmdP.get(mih::cmd_link_get_parameters)) s += "GET_PARAMETERS "; - if(cmdP.get(mih::cmd_link_configure_thresholds)) s += "CONFIGURE_THRESHOLDS "; - if(cmdP.get(mih::cmd_link_action)) s += "ACTION "; - return s; -} -/** - * Add a new Link SAP entry in the link book. - * - * @param id Link SAP MIH Identifier. - * @param ip Link SAP IP address. - * @param port Link SAP listening port. - * @param link_id interfaces that Link SAP manages. - */ -void link_book::add(const mih::octet_string &id, - mih::octet_string& ip, - uint16 port, - mih::link_id link_id) -{ - boost::mutex::scoped_lock lock(_mutex); - // TODO: add thread safety - link_entry a; - - a.ip.assign(ip); - a.port = port; - a.link_id = link_id; - a.fail = 0; - a.status = true; - - _lbook[id] = a; - ODTONE_LOG(4, "(link_book) added: ", id, " ", ip, " ", port, " ", link_id); -} - -/** - * Set the IP address of an existing Link SAP entry. - * - * @param id Link SAP MIH Identifier. - * @param ip The IP address to set. - */ -void link_book::set_ip(const mih::octet_string &id, std::string ip) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it != _lbook.end()) - it->second.ip = ip; -} - -/** - * Set the port of an existing Link SAP entry. - * - * @param id Link SAP MIH Identifier. - * @param port The port to set. - */ -void link_book::set_port(const mih::octet_string &id, uint16 port) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it != _lbook.end()) - it->second.port = port; -} - -/** - * Update the events and commands supported by a Link SAP. - * - * @param id Link SAP MIH Identifier. - * @param event_list Supported event list. - * @param cmd_list Supported command list. - */ -void link_book::update_capabilities(const mih::octet_string &id, - mih::link_evt_list event_list, - mih::link_cmd_list cmd_list) - -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it != _lbook.end()) { - ODTONE_LOG(4, "(link_book) update_capabilities() FOUND: ", id, " ", evt2string(event_list), " ", cmd2string(cmd_list)); - it->second.event_list = event_list; - it->second.cmd_list = cmd_list; - } else { - ODTONE_LOG(4, "(link_book) update_capabilities() NOT FOUND: ", id, " ", evt2string(event_list), " ", cmd2string(cmd_list)); - } -} - -/** - * Remove an existing Link SAP entry. - * - * @param id Link SAP MIH Identifier. - */ -void link_book::del(mih::octet_string &id) -{ - boost::mutex::scoped_lock lock(_mutex); - - _lbook.erase(id); -} - -/** - * Inactive an existing Link SAP entry. - * - * @param id Link SAP MIH Identifier. - */ -void link_book::inactive(mih::octet_string &id) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it != _lbook.end()) { - ODTONE_LOG(4, "(link_book) inactive() : ", id); - it->second.status = false; - } -} - -/** - * Get the record for a given Link SAP. - * - * @param id Link SAP MIH Identifier. - * @return The record for a given Link SAP. - */ -const link_entry& link_book::get(const mih::octet_string &id) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::const_iterator it; - it = _lbook.find(id); - - if (it == _lbook.end()) - boost::throw_exception(unknown_link_sap()); - - return it->second; -} - -/** - * Get the list of all known Link SAPs. - * - * @return The list of all known Link SAPs. - */ -const std::vector link_book::get_ids() -{ - boost::mutex::scoped_lock lock(_mutex); - - std::vector ids; - for(std::map::iterator it = _lbook.begin(); it != _lbook.end(); it++) { - ids.push_back(it->first); - } - - return ids; -} - -/** - * Search for the Link SAP MIH Identifier of a given interface. - * - * @param lt The link type of the Link SAP to search for. - * @param la The link address of the Link SAP to search for. - * @return The Link SAP MIH Identifier. - */ -const mih::octet_string link_book::search_interface(mih::link_type lt, mih::link_addr la) -{ - boost::mutex::scoped_lock lock(_mutex); - - mih::octet_string id; - std::map::iterator it; - for(it = _lbook.begin(); it != _lbook.end(); it++) { - - ODTONE_LOG(4, "(link_book) ID LINK TYPE : ", it->first, " ADDRESS ", it->second.link_id.addr, " STATUS", it->second.status); - } - - for(/*std::map::iterator*/ it = _lbook.begin(); it != _lbook.end(); it++) { - - ODTONE_LOG(4, "(link_book) search 1st step ID LINK TYPE comparison type:",it->second.link_id.type, "LT", lt); - if(it->second.link_id.type == lt) { - ODTONE_LOG(4, "(link_book) search 2nd step ID LINK TYPE comparison addr:",it->second.link_id.addr, "LA", la); - if(it->second.link_id.addr == la) { - ODTONE_LOG(4, "(link_book) search 3rd step ID LINK TYPE check status:",it->second.status); - if(it->second.status) { - ODTONE_LOG(4, "(link_book) search 3rd step ID LINK TYPE : ", it->first, " ADDRESS ", it->second.link_id.addr, " STATUS", it->second.status); - id = it->first; - break; - } - } - } - } - - ODTONE_LOG(4, "(link_book) search_interface() : ", lt, " ", la, " Found:", id); - return id; -} - -/** - * Update and return the number of fail responses of a given Link SAP. - * - * @param id Link SAP MIH Identifier. - * @return The number of fails responses. - */ -uint16 link_book::fail(const mih::octet_string &id) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it == _lbook.end()) - boost::throw_exception(unknown_link_sap()); - - (it->second.fail)++; - ODTONE_LOG(4, "(link_book) fail() : ", id ," num fails:",it->second.fail); - return it->second.fail; -} - -/** - * Reset the number of fail responses of a given Link SAP. - * - * @param id Link SAP MIH Identifier. - */ -void link_book::reset(const mih::octet_string &id) -{ - boost::mutex::scoped_lock lock(_mutex); - - std::map::iterator it; - it = _lbook.find(id); - - if (it == _lbook.end()) - boost::throw_exception(unknown_link_sap()); - - ODTONE_LOG(4, "(link_book) reset() : ", id); - it->second.fail = 0; - it->second.status = true; -} - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/main.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/main.cpp deleted file mode 100644 index 46a9db9dc5..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/main.cpp +++ /dev/null @@ -1,753 +0,0 @@ -//============================================================================== -// Brief : ODTONE MIHF -// Authors : Simao Reis -// Carlos Guimarães -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// - -#include "mihfid.hpp" -#include "log.hpp" -// #include "transaction_ack_service.hpp" -// #include "transaction_manager.hpp" -#include "address_book.hpp" -#include "link_book.hpp" -#include "user_book.hpp" -#include "local_transaction_pool.hpp" -#include "transaction_pool.hpp" - -#include "net_sap.hpp" -#include "message_out.hpp" -#include "transmit.hpp" -#include "service_management.hpp" -#include "event_service.hpp" -#include "command_service.hpp" -#include "information_service.hpp" -#include "service_access_controller.hpp" - -#include "message_in.hpp" -#include "udp_listener.hpp" -#include "tcp_listener.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -/////////////////////////////////////////////////////////////////////////////// -// using namespace odtone::mihf; -using namespace odtone; -using namespace odtone::mihf; - - -namespace po = boost::program_options; - -// available config options -static const char* const kConf_File = "conf.file"; -static const char* const kConf_Receive_Buffer_Len = "conf.recv_buff_len"; -static const char* const kConf_MIHF_Id = "mihf.id"; -static const char* const kConf_MIHF_Ip = "mihf.ip"; -static const char* const kConf_MIHF_Peer_List = "mihf.peers"; -static const char* const kConf_MIHF_Users_List = "mihf.users"; -static const char* const kConf_MIHF_Links_List = "mihf.links"; -static const char* const kConf_MIHF_Transport_List = "mihf.transport"; -static const char* const kConf_MIHF_Remote_Port = "mihf.remote_port"; -static const char* const kConf_MIHF_Local_Port = "mihf.local_port"; -static const char* const kConf_MIHF_Link_Response_Time = "mihf.link_response_time"; -static const char* const kConf_MIHF_Link_Delete = "mihf.link_delete"; -static const char* const kConf_MIHF_Discover = "mihf.discover"; -static const char* const kConf_MIHF_Multicast = "enable_multicast"; -static const char* const kConf_MIHF_Unsolicited = "enable_unsolicited"; -static const char* const kConf_MIHF_Verbosity = "log"; - -uint16 kConf_MIHF_Link_Response_Time_Value; -uint16 kConf_MIHF_Link_Delete_Value; - -/** - * Remove a character from the string. - */ -void __trim(mih::octet_string &str, const char chr) -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} - -// -// list is a comma separated list of mihf id ip and port -// -// example: mihf2 192.168.0.1 4551 -// -void set_list_peer_mihfs(mih::octet_string &list, address_book &abook) -{ - using namespace boost; - - char_separator sep1(","); - char_separator sep2(" "); - tokenizer< char_separator > list_tokens(list, sep1); - - BOOST_FOREACH(mih::octet_string str, list_tokens) - { - tokenizer< char_separator > tokens(str, sep2); - tokenizer< char_separator >::iterator it = tokens.begin(); - - mih::octet_string id = *it; - ++it; - mih::octet_string ip = *it; - ++it; - mih::octet_string port = *it; - - uint16 port_; - std::istringstream iss(port); - if ((iss >> port_).fail()) - throw "invalid port"; - - mih::transport_list trans; - - std::map enum_map; - enum_map["udp"] = odtone::mih::transport_udp; - enum_map["tcp"] = odtone::mih::transport_tcp; - - while(it != tokens.end()) { - if(enum_map.find(*it) != enum_map.end()) - trans.set(odtone::mih::transport_list_enum(enum_map[*it])); - ++it; - } - - address_entry entry; - entry.ip = ip; - entry.port = port_; - entry.capabilities_trans_list = trans; - - abook.add(id, entry); - } -} - -void set_users(mih::octet_string &list, user_book &ubook) -{ - using namespace boost; - - char_separator sep1(","); - char_separator sep2(" "); - tokenizer< char_separator > list_tokens(list, sep1); - - BOOST_FOREACH(mih::octet_string str, list_tokens) { - tokenizer< char_separator > tokens(str, sep2); - tokenizer< char_separator >::iterator it = tokens.begin(); - - mih::octet_string id = *it; - ++it; - mih::octet_string ip("127.0.0.1"); - mih::octet_string port = *it; - ++it; - - uint16 port_; - std::istringstream iss_port(port); - if ((iss_port >> port_).fail()) - throw "invalid port"; - - mih::mih_cmd_list supp_cmd_tmp; - mih::iq_type_list supp_iq_tmp; - bool has_cmd = false; - bool has_iq = false; - if(it != tokens.end()) { - std::map enum_map_cmd; - enum_map_cmd["mih_link_get_parameters"] = mih::mih_cmd_link_get_parameters; - enum_map_cmd["mih_link_configure_thresholds"] = mih::mih_cmd_link_configure_thresholds; - enum_map_cmd["mih_link_actions"] = mih::mih_cmd_link_actions; - enum_map_cmd["mih_net_ho_candidate_query"] = mih::mih_cmd_net_ho_candidate_query; - enum_map_cmd["mih_net_ho_commit"] = mih::mih_cmd_net_ho_commit; - enum_map_cmd["mih_n2n_ho_query_resources"] = mih::mih_cmd_n2n_ho_query_resources; - enum_map_cmd["mih_n2n_ho_commit"] = mih::mih_cmd_n2n_ho_commit; - enum_map_cmd["mih_n2n_ho_complete"] = mih::mih_cmd_n2n_ho_complete; - enum_map_cmd["mih_mn_ho_candidate_query"] = mih::mih_cmd_mn_ho_candidate_query; - enum_map_cmd["mih_mn_ho_commit"] = mih::mih_cmd_mn_ho_commit; - enum_map_cmd["mih_mn_ho_complete"] = mih::mih_cmd_mn_ho_complete; - - std::map enum_map_iq; - enum_map_iq["iq_type_binary_data"] = mih::iq_type_binary_data; - enum_map_iq["iq_type_rdf_data"] = mih::iq_type_rdf_data; - enum_map_iq["iq_type_rdf_schema_url"] = mih::iq_type_rdf_schema_url; - enum_map_iq["iq_type_rdf_schema"] = mih::iq_type_rdf_schema; - enum_map_iq["iq_type_ie_network_type"] = mih::iq_type_ie_network_type; - enum_map_iq["iq_type_ie_operator_id"] = mih::iq_type_ie_operator_id; - enum_map_iq["iq_type_ie_service_provider_id"] = mih::iq_type_ie_service_provider_id; - enum_map_iq["iq_type_ie_country_code"] = mih::iq_type_ie_country_code; - enum_map_iq["iq_type_ie_network_id"] = mih::iq_type_ie_network_id; - enum_map_iq["iq_type_ie_network_aux_id"] = mih::iq_type_ie_network_aux_id; - enum_map_iq["iq_type_ie_roaming_parteners"] = mih::iq_type_ie_roaming_parteners; - enum_map_iq["iq_type_ie_cost"] = mih::iq_type_ie_cost; - enum_map_iq["iq_type_ie_network_qos"] = mih::iq_type_ie_network_qos; - enum_map_iq["iq_type_ie_network_data_rate"] = mih::iq_type_ie_network_data_rate; - enum_map_iq["iq_type_ie_net_regult_domain"] = mih::iq_type_ie_net_regult_domain; - enum_map_iq["iq_type_ie_net_frequency_bands"] = mih::iq_type_ie_net_frequency_bands; - enum_map_iq["iq_type_ie_net_ip_cfg_methods"] = mih::iq_type_ie_net_ip_cfg_methods; - enum_map_iq["iq_type_ie_net_capabilities"] = mih::iq_type_ie_net_capabilities; - enum_map_iq["iq_type_ie_net_supported_lcp"] = mih::iq_type_ie_net_supported_lcp; - enum_map_iq["iq_type_ie_net_mob_mgmt_prot"] = mih::iq_type_ie_net_mob_mgmt_prot; - enum_map_iq["iq_type_ie_net_emserv_proxy"] = mih::iq_type_ie_net_emserv_proxy; - enum_map_iq["iq_type_ie_net_ims_proxy_cscf"] = mih::iq_type_ie_net_ims_proxy_cscf; - enum_map_iq["iq_type_ie_net_mobile_network"] = mih::iq_type_ie_net_mobile_network; - enum_map_iq["iq_type_ie_poa_link_addr"] = mih::iq_type_ie_poa_link_addr; - enum_map_iq["iq_type_ie_poa_location"] = mih::iq_type_ie_poa_location; - enum_map_iq["iq_type_ie_poa_channel_range"] = mih::iq_type_ie_poa_channel_range; - enum_map_iq["iq_type_ie_poa_system_info"] = mih::iq_type_ie_poa_system_info; - enum_map_iq["iq_type_ie_poa_subnet_info"] = mih::iq_type_ie_poa_subnet_info; - enum_map_iq["iq_type_ie_poa_ip_addr"] = mih::iq_type_ie_poa_ip_addr; - - while(it != tokens.end()) { - if(enum_map_cmd.find(*it) != enum_map_cmd.end()) { - supp_cmd_tmp.set((mih::mih_cmd_list_enum) enum_map_cmd[*it]); - has_cmd = true; - } else if(enum_map_iq.find(*it) != enum_map_iq.end()) { - supp_iq_tmp.set((mih::iq_type_list_enum) enum_map_iq[*it]); - has_iq = true; - } - - ++it; - } - } - - boost::optional supp_cmd; - boost::optional supp_iq; - - if(has_cmd) { - supp_cmd = supp_cmd_tmp; - } else { - supp_cmd_tmp.full(); - supp_cmd = supp_cmd_tmp; - } - - if(has_iq) - supp_iq = supp_iq_tmp; - - ubook.add(id, ip, port_, supp_cmd, supp_iq); - } -} - -void set_links(mih::octet_string &list, link_book &lbook) -{ - using namespace boost; - - char_separator sep1(","); - char_separator sep2(" "); - tokenizer< char_separator > list_tokens(list, sep1); - - BOOST_FOREACH(mih::octet_string str, list_tokens) { - tokenizer< char_separator > tokens(str, sep2); - tokenizer< char_separator >::iterator it = tokens.begin(); - - mih::octet_string id = *it; - ++it; - mih::octet_string port = *it; - ++it; - mih::octet_string tec = *it; - ++it; - mih::octet_string address = *it; - mih::octet_string ip("127.0.0.1"); - - uint16 port_; - std::istringstream iss(port); - if ((iss >> port_).fail()) { - throw "invalid port"; - } - - if(tec == "" || address == "") { - throw "invalid technology and/or address"; - } - - // Extract technology - std::map enum_map; - enum_map["GSM"] = odtone::mih::link_type_gsm; - enum_map["GPRS"] = odtone::mih::link_type_gprs; - enum_map["EDGE"] = odtone::mih::link_type_edge; - enum_map["802_3"] = odtone::mih::link_type_ethernet; - enum_map["Other"] = odtone::mih::link_type_wireless_other; - enum_map["802_11"] = odtone::mih::link_type_802_11; - enum_map["CDMA2000"] = odtone::mih::link_type_cdma2000; - enum_map["UMTS"] = odtone::mih::link_type_umts; - enum_map["CDMA2000-HRPD"] = odtone::mih::link_type_cdma2000_hrpd; - enum_map["LTE"] = odtone::mih::link_type_lte; - enum_map["802_16"] = odtone::mih::link_type_802_16; - enum_map["802_20"] = odtone::mih::link_type_802_20; - enum_map["802_22"] = odtone::mih::link_type_802_22; - - mih::link_id lid; - if(enum_map.find(tec) != enum_map.end()) - lid.type = odtone::mih::link_type(enum_map[tec]); - - // TODO: Parse the link address for all link types. - switch(lid.type.get()) { - case 1: - case 2: - case 3: { - throw "not supported yet"; - } - break; - - case 15: - case 19: - case 27: - case 28: - case 29: { - mih::mac_addr mac; - mac.address(address); - lid.addr = mac; - } break; - - case 18: - case 22: - case 23: - case 24: - throw "not supported yet"; - break; - - case 25: { - ++it; - mih::octet_string plmn = *it; - ++it; - mih::octet_string cell_id = *it; - - char_separator plmn_sep(":"); - tokenizer< char_separator > list_tokens(plmn, plmn_sep); - - mih::l2_3gpp_3g_cell_id lte; - uint8 pos = 0; - BOOST_FOREACH(mih::octet_string str, list_tokens) { - uint8 byte = 0; - std::istringstream iss(str); - iss >> std::hex >> byte; - - lte.plmn_id[pos] = byte % 0x100; - ++pos; - } - - std::istringstream iss(port); - if ((iss >> lte._cell_id).fail()) { - throw "invalid cell_id"; - } - - lid.addr = lte; - } break; - default: { - ODTONE_LOG(0, "Error: Invalid technology! Aborting...") ; - throw "invalid technology"; - } break; - } - - lbook.add(id, ip, port_, lid); - } -} - -void parse_mihf_information(mih::config &cfg, address_book &abook) -{ - using namespace boost; - - // Insert the MIHF itself in the address book - mih::octet_string id = cfg.get(kConf_MIHF_Id); - mih::octet_string ip = cfg.get(kConf_MIHF_Ip); - uint16 port = cfg.get(kConf_MIHF_Remote_Port); - mih::transport_list trans; - - mih::octet_string tmp = cfg.get(kConf_MIHF_Transport_List); - boost::algorithm::to_lower(tmp); - - char_separator sep(","); - tokenizer< char_separator > list_tokens(tmp, sep); - - std::map enum_map; - enum_map["udp"] = odtone::mih::transport_udp; - enum_map["tcp"] = odtone::mih::transport_tcp; - - BOOST_FOREACH(mih::octet_string str, list_tokens) { - __trim(str, ' '); - if(enum_map.find(str) != enum_map.end()) - trans.set(odtone::mih::transport_list_enum(enum_map[str])); - } - - address_entry entry; - entry.ip = ip; - entry.port = port; - entry.capabilities_trans_list = trans; - - abook.add(id, entry); -} - -void parse_peer_registrations(mih::config &cfg, address_book &abook) -{ - mih::octet_string mihfs = cfg.get(kConf_MIHF_Peer_List); - - set_list_peer_mihfs(mihfs, abook); -} - -void parse_sap_registrations(mih::config &cfg, user_book &ubook, link_book &lbook) -{ - mih::octet_string users = cfg.get(kConf_MIHF_Users_List); - mih::octet_string lsaps = cfg.get(kConf_MIHF_Links_List); - - set_users(users, ubook); - set_links(lsaps, lbook); -} - -std::vector parse_discover_order(mih::config &cfg) -{ - using namespace boost; - - mih::octet_string order = cfg.get(kConf_MIHF_Discover); - std::vector list; - - char_separator sep(","); - tokenizer< char_separator > list_tokens(order, sep); - - BOOST_FOREACH(mih::octet_string str, list_tokens) { - list.push_back(str); - } - - return list; -} - -void sm_register_callbacks(service_management &sm) -{ - sac_register_callback(mih::request::capability_discover, - boost::bind(&service_management::capability_discover_request, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::response::capability_discover, - boost::bind(&service_management::capability_discover_response, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::confirm::capability_discover, - boost::bind(&service_management::capability_discover_confirm, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::request::mih_register, - boost::bind(&service_management::register_request, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::response::mih_register, - boost::bind(&service_management::register_response, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::request::mih_deregister, - boost::bind(&service_management::deregister_request, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::response::mih_deregister, - boost::bind(&service_management::deregister_response, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::indication::link_register, - boost::bind(&service_management::link_register_indication, - boost::ref(sm), _1, _2)); - - sac_register_callback(mih::indication::user_register, - boost::bind(&service_management::user_register_indication, - boost::ref(sm), _1, _2)); - -} - -void mies_register_callbacks(event_service &mies) -{ - sac_register_callback(mih::request::event_subscribe, - boost::bind(&event_service::event_subscribe_request, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::response::event_subscribe, - boost::bind(&event_service::event_subscribe_response, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::confirm::event_subscribe, - boost::bind(&event_service::event_subscribe_confirm, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_up, - boost::bind(&event_service::link_up_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_down, - boost::bind(&event_service::link_down_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_detected, - boost::bind(&event_service::link_detected_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_going_down, - boost::bind(&event_service::link_going_down_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_parameters_report, - boost::bind(&event_service::link_parameters_report_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_handover_imminent, - boost::bind(&event_service::link_handover_imminent_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::indication::link_handover_complete, - boost::bind(&event_service::link_handover_complete_indication, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::request::event_unsubscribe, - boost::bind(&event_service::event_unsubscribe_request, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::response::event_unsubscribe, - boost::bind(&event_service::event_unsubscribe_response, - boost::ref(mies), _1, _2)); - sac_register_callback(mih::confirm::event_unsubscribe, - boost::bind(&event_service::event_unsubscribe_confirm, - boost::ref(mies), _1, _2)); -} -// REGISTER(event_service::link_pdu_transmit_status_indication) - -void mics_register_callbacks(command_service &mics) -{ - sac_register_callback(mih::request::link_get_parameters, - boost::bind(&command_service::link_get_parameters_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::link_get_parameters, - boost::bind(&command_service::link_get_parameters_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::confirm::link_get_parameters, - boost::bind(&command_service::link_get_parameters_confirm, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::link_configure_thresholds, - boost::bind(&command_service::link_configure_thresholds_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::link_configure_thresholds, - boost::bind(&command_service::link_configure_thresholds_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::confirm::link_configure_thresholds, - boost::bind(&command_service::link_configure_thresholds_confirm, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::link_actions, - boost::bind(&command_service::link_actions_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::link_actions, - boost::bind(&command_service::link_actions_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::confirm::link_actions, - boost::bind(&command_service::link_actions_confirm, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::net_ho_candidate_query, - boost::bind(&command_service::net_ho_candidate_query_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::net_ho_candidate_query, - boost::bind(&command_service::net_ho_candidate_query_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::mn_ho_candidate_query, - boost::bind(&command_service::mn_ho_candidate_query_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::mn_ho_candidate_query, - boost::bind(&command_service::mn_ho_candidate_query_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::n2n_ho_query_resources, - boost::bind(&command_service::n2n_ho_query_resources_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::n2n_ho_query_resources, - boost::bind(&command_service::n2n_ho_query_resources_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::mn_ho_commit, - boost::bind(&command_service::mn_ho_commit_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::mn_ho_commit, - boost::bind(&command_service::mn_ho_commit_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::net_ho_commit, - boost::bind(&command_service::net_ho_commit_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::net_ho_commit, - boost::bind(&command_service::net_ho_commit_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::n2n_ho_commit, - boost::bind(&command_service::n2n_ho_commit_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::n2n_ho_commit, - boost::bind(&command_service::n2n_ho_commit_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::n2n_ho_commit, - boost::bind(&command_service::n2n_ho_commit_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::n2n_ho_commit, - boost::bind(&command_service::n2n_ho_commit_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::mn_ho_complete, - boost::bind(&command_service::mn_ho_complete_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::mn_ho_complete, - boost::bind(&command_service::mn_ho_complete_response, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::request::n2n_ho_complete, - boost::bind(&command_service::n2n_ho_complete_request, - boost::ref(mics), _1, _2)); - sac_register_callback(mih::response::n2n_ho_complete, - boost::bind(&command_service::n2n_ho_complete_response, - boost::ref(mics), _1, _2)); -} - -void miis_register_callbacks(information_service &miis) -{ - sac_register_callback(mih::request::get_information, - boost::bind(&information_service::get_information_request, - boost::ref(miis), _1, _2)); - sac_register_callback(mih::response::get_information, - boost::bind(&information_service::get_information_response, - boost::ref(miis), _1, _2)); - sac_register_callback(mih::request::push_information, - boost::bind(&information_service::push_information_request, - boost::ref(miis), _1, _2)); - sac_register_callback(mih::indication::push_information, - boost::bind(&information_service::push_information_indication, - boost::ref(miis), _1, _2)); -} - -int main(int argc, char **argv) -{ - odtone::setup_crash_handler(); - - boost::asio::io_service io; - - // declare MIHF supported options - po::options_description desc(mih::octet_string("MIHF Configuration Options")); - - desc.add_options() - ("help", "Display configuration options") - (kConf_File, po::value()->default_value("odtone.conf"), "Configuration file") - (kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (kConf_MIHF_Id, po::value()->default_value("mihf"), "MIHF ID") - (kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "MIHF IP") - (kConf_MIHF_Remote_Port, po::value()->default_value(4551), "Remote MIHF communication port") - (kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local SAPs communications port") - (kConf_MIHF_Peer_List, po::value()->default_value(""), "List of peer MIHFs") - (kConf_MIHF_Users_List, po::value()->default_value(""), "List of local MIH-Users") - (kConf_MIHF_Links_List, po::value()->default_value(""), "List of local Links SAPs") - (kConf_MIHF_Transport_List, po::value()->default_value("udp"), "List of supported transport protocols") - (kConf_MIHF_Link_Response_Time, po::value()->default_value(7000), "Link SAP response time (milliseconds)") - (kConf_MIHF_Link_Delete, po::value()->default_value(2), "Link SAP response fails to forget") - (kConf_MIHF_Discover, po::value()->default_value(""), "MIHF Discovery Mechanisms Order") - (kConf_MIHF_Multicast, "Allows multicast messages") - (kConf_MIHF_Unsolicited, "Allows unsolicited discovery") - (kConf_MIHF_Verbosity, po::value()->default_value(1), "Log level [0-4]") - ; - - odtone::mih::config cfg(desc); - if (!cfg.parse(argc, argv, kConf_File) && !cfg.help()) { - std::cerr << "Error: Couldn't open config file: " << cfg.get(kConf_File) << std::endl; - return EXIT_FAILURE; - } - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - // get command line parameters - bool enable_multicast = (cfg.count(kConf_MIHF_Multicast) == 1); - bool enable_unsolicited = (cfg.count(kConf_MIHF_Unsolicited) == 1); - - uint16 buff_size = cfg.get(kConf_Receive_Buffer_Len); - uint16 lport = cfg.get(kConf_MIHF_Local_Port); - uint16 rport = cfg.get(kConf_MIHF_Remote_Port); - mih::octet_string id = cfg.get(kConf_MIHF_Id); - uint16 loglevel = cfg.get(kConf_MIHF_Verbosity); - kConf_MIHF_Link_Response_Time_Value = cfg.get(kConf_MIHF_Link_Response_Time); - kConf_MIHF_Link_Delete_Value = cfg.get(kConf_MIHF_Link_Delete); - std::vector dscv_order = parse_discover_order(cfg); - // - - // set this mihf id - mihfid_t::instance()->assign(id.c_str()); - // set log level - ODTONE_LOG.level(loglevel); - - // create address books that stores info on how to contact mih - // saps and peer mihfs - address_book mihf_abook(io); - user_book user_abook; - link_book link_abook; - parse_mihf_information(cfg, mihf_abook); - parse_sap_registrations(cfg, user_abook, link_abook); - parse_peer_registrations(cfg, mihf_abook); - // - - // pool of pending transactions with peer mihfs - transaction_pool tpool(io); - - // pool of pending transactions with local mih saps (user and links) - local_transaction_pool lpool; - - // pool of pending capability discover requests - link_response_pool lrpool; - - // handler for remote messages - handler_t process_message = boost::bind(&sac_process_message, _1, _2); - - // wrapper for sending messages - net_sap netsap(io, mihf_abook, rport); - - // transaction manager for outgoing messages - message_out msgout(tpool, lpool, process_message, netsap); - transmit trnsmt(io, user_abook, link_abook, msgout, lport); - - // transaction manager for incoming messages - message_in msgin(tpool, process_message, netsap); - - // sac dispatch is for handling messages from local mih saps - // (users and links) - sac_dispatch sacd(trnsmt); - - // handler of messages received on local port - dispatch_t ldispatch = boost::bind(&sac_dispatch::operator(), sacd, _1); - // handler of messages received from peer mihfs - dispatch_t rdispatch = boost::bind(&message_in::operator(), msgin, _1); - - // create and bind to port 'lport' on loopback interface and - // call ldispatch when a message is received - udp_listener commhandv4(io, buff_size, ip::udp::v4(), "127.0.0.1", lport, ldispatch, true); - udp_listener commhandv6(io, buff_size, ip::udp::v6(), "::1", lport, ldispatch, true); - - // create and bind to port rport and call rdispatch when a - // message is received - udp_listener remotelistener_udp(io, buff_size, ip::udp::v6(), "::", rport, rdispatch, enable_multicast); - - // create and bind to port rport and call rdispatch when a - // message is received - tcp_listener remotelistener_tcp(io, buff_size, ip::tcp::v6(), "::", rport, rdispatch, enable_multicast); - - // start listening on local and remote ports - commhandv4.start(); - commhandv6.start(); - remotelistener_udp.start(); - - if(mihf_abook.get(mihfid_t::instance()->to_string()).capabilities_trans_list->get(mih::transport_tcp) == 1) - remotelistener_tcp.start(); - - // instantiate mihf services - event_service mies(io, lpool, trnsmt, mihf_abook, link_abook, user_abook); - command_service mics(io, lpool, trnsmt, mihf_abook, link_abook, user_abook, lrpool); - information_service miis(lpool, trnsmt, user_abook); - service_management sm(io, lpool, link_abook, user_abook, mihf_abook, trnsmt, lrpool, dscv_order, enable_unsolicited); - - // register callbacks with service access controller - sm_register_callbacks(sm); - mies_register_callbacks(mies); - mics_register_callbacks(mics); - miis_register_callbacks(miis); - std::cout << "Boot complete" << std::endl << std::flush; - - io.run(); - - return EXIT_SUCCESS; -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/patch.txt b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/patch.txt deleted file mode 100644 index bc19890ec1..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/patch.txt +++ /dev/null @@ -1,13 +0,0 @@ -ODTONE/inc/odtone/mih/types/address.hpp -ODTONE/inc/odtone/mih/types/link.hpp -ODTONE/lib/odtone/CMakeLists.txt -ODTONE/lib/odtone/Jamfile -ODTONE/src/mihf/command_service.cpp -ODTONE/src/mihf/dst_transaction.cpp -ODTONE/src/mihf/event_service.cpp -ODTONE/src/mihf/link_book.cpp -ODTONE/src/mihf/main.cpp -ODTONE/src/mihf/service_access_controller.cpp -ODTONE/src/mihf/service_management.cpp -ODTONE/src/mihf/src_transaction.cpp -ODTONE/src/mihf/transaction_pool.cpp diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_access_controller.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_access_controller.cpp deleted file mode 100644 index 2528fca8b6..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_access_controller.cpp +++ /dev/null @@ -1,174 +0,0 @@ -//============================================================================== -// Brief : Service Access Controller -// Authors : Simao Reis -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "service_access_controller.hpp" -#include "meta_message.hpp" -#include "log.hpp" -#include "mihfid.hpp" - -#include -#include -#include -#include -#include - -#include -/////////////////////////////////////////////////////////////////////////////// - - -namespace odtone { namespace mihf { - -static std::map _callbacks; /**< Callback map of the supported messages.*/ - -/** - * Registering a callback handler for a MIH message identifier. - * This should only be used on MIHF initialization because it's not thread safe. - * - * @param mid The MIH Message identifier. - * @param func The handler function. - */ -void sac_register_callback(uint mid, handler_t func) -{ - ODTONE_LOG(1, "(sac) sac_register_callback(): mid ", mid, " handler ", func); - _callbacks[mid] = func; -} - -/** - * Construct a Service Access Controller. - * - * @param t The transmit module. - */ -sac_dispatch::sac_dispatch(transmit &t) - : _transmit(t) -{ -} - -/** - * Check if there is a handler for this message and call it, else - * discard message. - * - * @param in The input message. - */ -void sac_dispatch::operator()(meta_message_ptr& in) -{ - /** __no__ authentication at this point */ - - uint mid = in->mid(); - - ODTONE_LOG(1, "(sac) dispatching message with mid: ", mid); - // - // no thread safety because insertion should __only__ be made - // on MIHF initialization - // - std::map::iterator it; - it = _callbacks.find(mid); - - if(it != _callbacks.end()) { - handler_t process_message = it->second; - meta_message_ptr out(new meta_message); - - out->tid(in->tid()); - // send response if it was generated - try { - - if (process_message(in, out)) { - _transmit(out); - } else { - ODTONE_LOG(1, "sac_dispatch::operator() Message not transmitted out."); - } - - } catch(mih::bad_tlv) { - ODTONE_LOG(1, "Discarding malformed message."); - } catch(unknown_link_sap) { - ODTONE_LOG(1, "Received message from an unknown Link SAP. Discarding message."); - } catch(unknown_mih_user) { - ODTONE_LOG(1, "Received message from an unknown MIH-User. Discarding message."); - } - } else { - ODTONE_LOG(1, "(sac) (warning) message with mid: ", mid, - " unknown, discarding."); - } -} - -/** - * Check if there's a handler for this message and call it, else - * discard message. - * - * @param in The input message. - * @param out The output message. - */ -bool sac_process_message(meta_message_ptr& in, meta_message_ptr& out) -{ - // discard messages that this MIHF broadcasted to itself - // discard messages that are not destined to this MIHF or if - // multicast messages are not supported - if(in->source() == mihfid) { - ODTONE_LOG(1, "(sac) Discarding message! Reason: ", - "message was broadcasted to itself"); - return false; - } - - if(!utils::this_mihf_is_destination(in) && !utils::is_multicast(in)) { - ODTONE_LOG(1, "(sac) Discarding message! Reason: ", - "this is not the message destination"); - return false; - } - - /** __no__ authentication at this point */ - - uint mid = in->mid(); - - // - // no thread safety because insertion should __only__ be made - // on MIHF initialization - // - std::map::iterator it; - it = _callbacks.find(mid); - - if(it != _callbacks.end()) { - handler_t process_message = it->second; - - bool rsp; - - try { - - rsp = process_message(in, out); - - } catch(mih::bad_tlv) { - ODTONE_LOG(1, "Discarding malformed message."); - return false; - } - - // set ip and port of response message - out->ip(in->ip()); - out->scope(in->scope()); - out->port(in->port()); - - // response message must have the same tid - out->tid(in->tid()); - - return rsp; - } else { - ODTONE_LOG(1, "(sac) (warning) message with mid: ", mid, - " unknown, discarding."); - } - - return false; -} - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_management.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_management.cpp deleted file mode 100644 index 9c31b2c9e8..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/service_management.cpp +++ /dev/null @@ -1,699 +0,0 @@ -//============================================================================== -// Brief : Service Management -// Authors : Simao Reis -// Carlos Guimarães -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "service_management.hpp" -#include "log.hpp" -#include "utils.hpp" -#include "mihfid.hpp" -#include "transmit.hpp" - -#include -#include -#include -#include -#include -#include - -#include -/////////////////////////////////////////////////////////////////////////////// - -extern odtone::uint16 kConf_MIHF_Link_Response_Time_Value; -extern odtone::uint16 kConf_MIHF_Link_Delete_Value; - -namespace odtone { namespace mihf { - -/** - * Construct the service management. - * - * @param io The io_service object that service management module will - * use to dispatch handlers for any asynchronous operations performed on - * the socket. - * @param lpool The local transaction pool module. - * @param link_abook The link book module. - * @param user_abook The user book module. - * @param address_abook The address book module. - * @param t The transmit module. - * @param lrpool The link response pool module. - * @param dscv_order Ordered list of entities that will manage the - * discovery of new PoS. - * @param enable_unsolicited Allows unsolicited discovery. - */ -service_management::service_management(io_service &io, - local_transaction_pool &lpool, - link_book &link_abook, - user_book &user_abook, - address_book &address_book, - transmit &t, - link_response_pool &lrpool, - std::vector &dscv_order, - bool enable_unsolicited) - : _lpool(lpool), - _link_abook(link_abook), - _user_abook(user_abook), - _abook(address_book), - _transmit(t), - _lrpool(lrpool), - _discover(io, lpool, address_book, user_abook, t, dscv_order, enable_unsolicited) -{ - _dscv_order = dscv_order; - _enable_unsolicited = enable_unsolicited; - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - - // Get capabilities from statically configured Link SAPs - const std::vector link_sap_list = _link_abook.get_ids(); - - BOOST_FOREACH(mih::octet_string id, link_sap_list) { - meta_message_ptr out(new meta_message()); - - *out << mih::request(mih::request::capability_discover); - out->tid(0); - out->destination(mih::id(id)); - - ODTONE_LOG(1, "(mics) forwarding Link_Capability_Discover.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - } -} - -/** - * Asks for the capabilities of all local Link SAPs. - * - * @param in The input message. - * @param out The output message. - * @return Always false, because it does not send any response directly. - */ -bool service_management::link_capability_discover_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - // Asks for local Link SAPs capabilities - ODTONE_LOG(1, "(mism) gathering information about local Link SAPs capabilities"); - - *out << mih::request(mih::request::capability_discover); - out->tid(in->tid()); - out->destination(in->source()); - - // Check if the Link SAP is still active - uint16 fails = _link_abook.fail(out->destination().to_string()); - if(fails > kConf_MIHF_Link_Delete_Value) { - mih::octet_string dst = out->destination().to_string(); - _link_abook.inactive(dst); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } - else { - ODTONE_LOG(1, "(mics) forwarding Link_Capability_Discover.request to ", - out->destination().to_string()); - utils::forward_request(out, _lpool, _transmit); - } - - return false; -} - -/** - * Piggyback local MIHF Capabilities in request message. - * - * @param in input message. - * @param out output message. - */ -void service_management::piggyback_capabilities(meta_message_ptr& in, - meta_message_ptr& out) -{ - // Get local capabilities - address_entry mihf_cap = _abook.get(mihfid_t::instance()->to_string()); - - *out << mih::request(mih::request::capability_discover) - & mih::tlv_net_type_addr_list(mihf_cap.capabilities_list_net_type_addr) - & mih::tlv_event_list(mihf_cap.capabilities_event_list) - & mih::tlv_command_list(mihf_cap.capabilities_cmd_list) - & mih::tlv_query_type_list(mihf_cap.capabilities_query_type) - & mih::tlv_transport_option_list(mihf_cap.capabilities_trans_list) - & mih::tlv_mbb_ho_supp_list(mihf_cap.capabilities_mbb_ho_supp); - - out->tid(in->tid()); - out->source(in->source()); - out->destination(in->destination()); -} - -/** - * Parse all capabilities from MIH Capability Discover message and stores - * them. - * - * @param in input message. - * @param out output message. - */ -void service_management::get_capabilities(meta_message_ptr& in, - meta_message_ptr& out) -{ - address_entry mihf_info; - mihf_info.ip = in->ip(); - mihf_info.port = in->port(); - - if(in->opcode() == mih::operation::request) { - *in >> mih::request(mih::request::capability_discover) - & mih::tlv_net_type_addr_list(mihf_info.capabilities_list_net_type_addr) - & mih::tlv_event_list(mihf_info.capabilities_event_list) - & mih::tlv_command_list(mihf_info.capabilities_cmd_list) - & mih::tlv_query_type_list(mihf_info.capabilities_query_type) - & mih::tlv_transport_option_list(mihf_info.capabilities_trans_list) - & mih::tlv_mbb_ho_supp_list(mihf_info.capabilities_mbb_ho_supp); - } else if(in->opcode() == mih::operation::response) { - mih::status st; - *in >> mih::response(mih::response::capability_discover) - & mih::tlv_status(st) - & mih::tlv_net_type_addr_list(mihf_info.capabilities_list_net_type_addr) - & mih::tlv_event_list(mihf_info.capabilities_event_list) - & mih::tlv_command_list(mihf_info.capabilities_cmd_list) - & mih::tlv_query_type_list(mihf_info.capabilities_query_type) - & mih::tlv_transport_option_list(mihf_info.capabilities_trans_list) - & mih::tlv_mbb_ho_supp_list(mihf_info.capabilities_mbb_ho_supp); - } - - _abook.add(in->source().to_string(), mihf_info); -} - -/** - * Set response to MIH Capability Discover message. - * - * @param in input message. - * @param out output message. - */ -void service_management::set_capability_discover_response(meta_message_ptr& in, - meta_message_ptr& out) -{ - // Create and piggyback local capabilities in response message - address_entry mihf_cap = _abook.get(mihfid_t::instance()->to_string()); - - *out << mih::response(mih::response::capability_discover) - & mih::tlv_status(mih::status_success) - & mih::tlv_net_type_addr_list(mihf_cap.capabilities_list_net_type_addr) - & mih::tlv_event_list(mihf_cap.capabilities_event_list) - & mih::tlv_command_list(mihf_cap.capabilities_cmd_list) - & mih::tlv_query_type_list(mihf_cap.capabilities_query_type) - & mih::tlv_transport_option_list(mihf_cap.capabilities_trans_list) - & mih::tlv_mbb_ho_supp_list(mihf_cap.capabilities_mbb_ho_supp); - - out->tid(in->tid()); - out->source(mihfid); - out->destination(in->source()); -} - -/** - * Send Capability Discover Indication message to all MIH Users. - * - * @param in input message. - * @param out output message. - */ -void service_management::send_indication(meta_message_ptr& in, - meta_message_ptr& out) -{ - std::vector ids = _user_abook.get_ids(); - in->opcode(mih::operation::indication); - for (std::vector::iterator it = ids.begin(); it < ids.end(); ++it) { - if(std::find(_dscv_order.begin(), _dscv_order.end(), *it) == _dscv_order.end()) { - in->destination(mih::id(*it)); - _transmit(in); - ODTONE_LOG(3, "(mism) Capability_Discover.indication sent to ", - in->destination().to_string()); - } - } -} - -/** - * Capability Discover Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::capability_discover_request(meta_message_ptr& in, - meta_message_ptr& out) -{ - ODTONE_LOG(1, "(mism) received Capability_Discover.request from ", - in->source().to_string(), " with destination ", - in->destination().to_string()); - - // User requests the capabilities of a remote MIHF - if (in->is_local() && !utils::this_mihf_is_destination(in)) { - // Multicast && Discover Module ON - if(utils::is_multicast(in) && _dscv_order.size() != 0) { - _discover.request(in, out); - return false; - } - // Multicast && Discover Module OFF - piggyback_capabilities(in, out); - utils::forward_request(out, _lpool, _transmit); - return false; - // User requets the capabilitties of the local MIHF - } else if (in->is_local() && utils::this_mihf_is_destination(in)) { - set_capability_discover_response(in, out); - return true; - // Remote requets received - } else if (utils::this_mihf_is_destination(in)) { - get_capabilities(in, out); - send_indication(in, out); - set_capability_discover_response(in, out); - return true; - // Multicast request received - } else if (utils::is_multicast(in)) { - get_capabilities(in, out); - send_indication(in, out); - set_capability_discover_response(in, out); - return true; - } else { - ODTONE_LOG(3, "(mism) response to broadcast Capability_Discover.request disabled"); - return false; - } - - return false; -} - -/** - * Capability Discover Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::capability_discover_response(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received Capability_Discover.response from ", - in->source().to_string()); - - // Check if it is a discovery message - if(in->is_local() && std::find(_dscv_order.begin(), - _dscv_order.end(), - in->source().to_string()) != _dscv_order.end()) { - _discover.response(in, out); - return false; - } - - // Store remote MIHF capabilities - get_capabilities(in, out); - - // do we have a request from a user? - if (_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "forwarding Capability_Discover.response to ", - in->destination().to_string()); - in->opcode(mih::operation::confirm); - _transmit(in); - return false; - } - - // set source id to broadcast id and check if there's a - // broadcast request from a user - mih::id tmp = in->source(); - in->source(mih::id("")); - if (_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "forwarding Capability_Discover.response to ", - in->destination().to_string()); - in->opcode(mih::operation::confirm); - in->source(tmp); - _transmit(in); - return false; - } - - if(_enable_unsolicited) { - ODTONE_LOG(1, "forwarding Capability_Discover.response to all", - "MIH-Users"); - - std::vector user_id_list = _user_abook.get_ids(); - BOOST_FOREACH(mih::octet_string user, user_id_list) { - ODTONE_LOG(3, "forwarding Capability_Discover.response to ", - user); - in->opcode(mih::operation::confirm); - in->source(mihfid); - in->destination(mih::id(user)); - _transmit(in); - } - - return false; - } else { - ODTONE_LOG(1, "no pending transaction for this message, discarding"); - return false; - } -} - -/** - * Capability Discover Confirm message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::capability_discover_confirm(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received Capability_Discover.confirm from ", - in->source().to_string()); - - _link_abook.reset(in->source().to_string()); - - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "no pending transaction for this message, discarding"); - return false; - } - - mih::status st; - boost::optional event; - boost::optional command; - - *in >> mih::confirm(mih::confirm::capability_discover) - & mih::tlv_status(st) - & mih::tlv_link_evt_list(event) - & mih::tlv_link_cmd_list(command); - - if(st == mih::status_success) { - // Update Link SAP capabilities in the Link Book - _link_abook.update_capabilities(in->source().to_string(), event.get(), command.get()); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - } - - return false; -} - -/** - * Register Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::register_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received MIH_Register.request from ", in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - if(in->is_local()) { - in->source(mihfid); - } else { - // Set registration - mih::link_id_list lil; - *in >> mih::request(mih::request::mih_register) - & mih::tlv_link_id_list(lil); - _abook.set_registration(in->source().to_string(), lil); - // - } - - // Forward this message to MIH-User for handover as an indication - in->opcode(mih::operation::indication); - std::vector user_list = _user_abook.get_ids(); - BOOST_FOREACH(mih::octet_string id, user_list) { - in->destination(mih::id(id)); - _lpool.add(in); - _transmit(in); - - ODTONE_LOG(1, "(mism) forwarding MIH_Register.indication to " , in->destination().to_string()); - } - - // Restore the original opcode after sending the indication message - in->opcode(mih::operation::request); - return false; - } else { - // Set registration - mih::link_id_list lil; - *in >> mih::request(mih::request::mih_register) - & mih::tlv_link_id_list(lil); - _abook.set_registration(in->destination().to_string(), lil); - // - - // try to forward the message, this is to handle the - // special case of the user handling MIH commands - // sending some MIH command request to a peer mihf - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * Register Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::register_response(meta_message_ptr&in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received MIH_Register.response from ", in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - // Set registration time interval - mih::status st; - uint16 interval; - *in >> mih::confirm(mih::confirm::mih_register) - & mih::tlv_status(st) - & mih::tlv_time_interval(interval); - - if(st == mih::status_success) { - _abook.set_registration(in->source().to_string(), interval); - } - // - - ODTONE_LOG(1, "(mism) forwarding MIH_Register.confirm to " , in->destination().to_string()); - in->opcode(mih::operation::confirm); - _transmit(in); - } else { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - // Set registration time interval - mih::status st; - uint16 interval; - *in >> mih::confirm(mih::confirm::mih_register) - & mih::tlv_status(st) - & mih::tlv_time_interval(interval); - - if(st == mih::status_success) { - _abook.set_registration(in->destination().to_string(), interval); - } - // - - in->source(mihfid); - _transmit(in); - } - - return false; -} - -/** - * DeRegister Request message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::deregister_request(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received MIH_DeRegister.request from ", - in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - if(in->is_local()) - in->source(mihfid); - - // Forward this message to MIH-User for handover as an indication - in->opcode(mih::operation::indication); - std::vector user_list = _user_abook.get_ids(); - BOOST_FOREACH(mih::octet_string id, user_list) { - in->destination(mih::id(id)); - _lpool.add(in); - _transmit(in); - - ODTONE_LOG(1, "(mism) forwarding MIH_DeRegister.indication to ", - in->destination().to_string()); - } - - // Restore the original opcode after sending the indication message - in->opcode(mih::operation::request); - return false; - } else { - // try to forward the message, this is to handle the - // special case of the user handling MIH commands - // sending some MIH command request to a peer mihf - utils::forward_request(in, _lpool, _transmit); - return false; - } - - return false; -} - -/** - * DeRegister Response message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::deregister_response(meta_message_ptr&in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received MIH_DeRegister.response from ", in->source().to_string()); - - if(utils::this_mihf_is_destination(in)) { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - // Set registration - mih::status st; - *in >> mih::confirm(mih::confirm::mih_deregister) - & mih::tlv_status(st); - - if(st == mih::status_success) { - // Set empty registered link id list - boost::optional lil; - boost::optional interval; - _abook.set_registration(in->source().to_string(), lil); - _abook.set_registration(in->source().to_string(), interval); - } - // - - ODTONE_LOG(1, "(mism) forwarding MIH_DeRegister.confirm to " , in->destination().to_string()); - in->opcode(mih::operation::confirm); - _transmit(in); - } else { - if(!_lpool.set_user_tid(in)) { - ODTONE_LOG(1, "(mics) warning: no local transaction for this msg ", - "discarding it"); - return false; - } - - // Set registration - mih::status st; - *in >> mih::confirm(mih::confirm::mih_deregister) - & mih::tlv_status(st); - - if(st == mih::status_success) { - // Set empty registered link id list - boost::optional lil; - boost::optional interval; - _abook.set_registration(in->destination().to_string(), lil); - _abook.set_registration(in->destination().to_string(), interval); - } - // - - in->source(mihfid); - _transmit(in); - } - - return false; -} - -/** - * Link Register Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::link_register_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received Link_Register.indication from ", - in->source().to_string()); - - // Add Link SAP to the list of known Link SAPs - mih::status st; - mih::link_id link_id; - - mih::octet_string ip(in->ip()); - - *in >> odtone::mih::indication() - & odtone::mih::tlv_interface_type_addr(link_id); - - ODTONE_LOG(4, "((mism) received Link_Register.indication: link_id", link_id); - // Add Link SAP to the list of known Link SAPs - _link_abook.add(in->source().to_string(), in->ip(), in->port(), link_id); - - // Update MIHF network type address - address_entry mihf_cap = _abook.get(mihfid_t::instance()->to_string()); - - // Set Network Type Address - mih::net_type_addr nta; - nta.nettype.link = link_id.type; - nta.addr = link_id.addr; - - if(mihf_cap.capabilities_list_net_type_addr.is_initialized()) { - mihf_cap.capabilities_list_net_type_addr.get().push_back(nta); - } else { - mih::net_type_addr_list ntal; - ntal.push_back(nta); - mihf_cap.capabilities_list_net_type_addr = ntal; - } - _abook.add(mihfid_t::instance()->to_string(), mihf_cap); - - // Request the Link SAP capabilities - link_capability_discover_request(in, out); - - return false; -} - -/** - * User Register Indication message handler. - * - * @param in The input message. - * @param out The output message. - * @return True if the response is sent immediately or false otherwise. - */ -bool service_management::user_register_indication(meta_message_ptr &in, - meta_message_ptr &out) -{ - ODTONE_LOG(1, "(mism) received User_Register.indication from ", - in->source().to_string()); - - // Add MIH User to the list of known MIH Users - boost::optional supp_cmd; - boost::optional supp_iq; - - mih::octet_string ip(in->ip()); - - *in >> odtone::mih::indication() - & odtone::mih::tlv_command_list(supp_cmd) - & odtone::mih::tlv_query_type_list(supp_iq); - - _user_abook.add(in->source().to_string(), ip, in->port(), supp_cmd, supp_iq); - - // Update MIHF capabilities - utils::update_local_capabilities(_abook, _link_abook, _user_abook); - - return false; -} - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/src_transaction.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/src_transaction.cpp deleted file mode 100644 index ef132d87b0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/src_transaction.cpp +++ /dev/null @@ -1,157 +0,0 @@ -//============================================================================== -// Brief : Source Transaction -// Authors : Simao Reis -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "log.hpp" -#include "src_transaction.hpp" -#include "utils.hpp" -/////////////////////////////////////////////////////////////////////////////// - -namespace odtone { namespace mihf { - -/** - * Constructor a Source State Machine transaction. - * - * @param f The transaction handler. - * @param netsap The netsap module. - */ -src_transaction_t::src_transaction_t(handler_t &f, net_sap &netsap) - : transaction_t(f, netsap) -{ - state = SRC_INIT; -} - -/** - * Run Source State Machine transaction. - */ -void src_transaction_t::run() -{ - switch (state) - { - case SRC_INIT: goto _init_lbl_; - case SRC_WAIT_RESPONSE_MSG: goto _wait_response_msg_lbl_; - case SRC_WAIT_ACK: goto _wait_ack_lbl_; - case SRC_PROCESS_MSG: goto _process_msg_lbl_; - case SRC_FAILURE: goto _failure_lbl_; - case SRC_SUCCESS: goto _success_lbl_; - } - - _init_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) init tid ", out->tid()); - transaction_status = ONGOING; - response_received = false; - transaction_stop_when = 15; // FIXME: read from config - opcode = out->opcode(); - is_multicast = utils::is_multicast(out); - start_ack_requestor = (out->ackreq() && !is_multicast); - tid = out->tid(); - my_mihf_id = out->source(); - peer_mihf_id = out->destination(); - - _netsap.send(out); - - if(start_ack_requestor) - ack_requestor(); - - if (opcode == mih::operation::indication) { - if (start_ack_requestor) { - ack_requestor_status = ONGOING; - goto _wait_ack_lbl_; - } - else - goto _success_lbl_; - } - else if (opcode == mih::operation::response) - goto _success_lbl_; - else if (opcode == mih::operation::request) - goto _wait_response_msg_lbl_; - - assert(0); // failsafe - } - - _wait_ack_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) wait ack tid ", tid); - state = SRC_WAIT_ACK; - - if (ack_requestor_status == SUCCESS) - goto _success_lbl_; - else if (ack_requestor_status == FAILURE) - goto _failure_lbl_; - - return; - } - - _wait_response_msg_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) wait response tid ", tid); - state = SRC_WAIT_RESPONSE_MSG; - - if (transaction_stop_when == 0) { - if (response_received) - goto _success_lbl_; - else - goto _failure_lbl_; - } else if (msg_in_avail) - goto _process_msg_lbl_; - - return; - } - - _process_msg_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) process msg tid ", tid); - state = SRC_PROCESS_MSG; - - start_ack_responder = in->ackreq(); - - msg_out_avail = false; - - if (start_ack_responder) - ack_responder(); - - process_message(in, out); - msg_in_avail = false; - response_received = true; - - if (is_multicast) - goto _wait_response_msg_lbl_; - else - goto _success_lbl_; - } - - _failure_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) failure tid ", tid); - transaction_status = FAILURE; - state = SRC_FAILURE; - return; - } - - _success_lbl_: - { - ODTONE_LOG(1, "(src_transaction_t) success tid ", tid); - transaction_status = SUCCESS; - state = SRC_SUCCESS; - } - - return; -} - - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/transaction_pool.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/transaction_pool.cpp deleted file mode 100644 index 204e5a1ee1..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/mihf_src/transaction_pool.cpp +++ /dev/null @@ -1,195 +0,0 @@ -//============================================================================== -// Brief : Transaction Pool -// Authors : Simao Reis -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2013 Universidade Aveiro -// Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -/////////////////////////////////////////////////////////////////////////////// -#include "log.hpp" -#include "transaction_pool.hpp" -/////////////////////////////////////////////////////////////////////////////// - -namespace odtone { namespace mihf { - -/** - * Construct a transaction pool. - * - * @param io The io_service object that transaction pool module will - * use to dispatch handlers for any asynchronous operations performed on - * the socket. - */ -transaction_pool::transaction_pool(io_service &io) - : _timer(io, boost::posix_time::seconds(1)), - _dst_mutex(), - _src_mutex() -{ - // start timer - _timer.expires_from_now(boost::posix_time::seconds(1)); - _timer.async_wait(boost::bind(&transaction_pool::tick, this)); -} - -/** - * Decrements the timer of each transaction only if its value is - * greater than 0. - * - * @param set The transaction type. - * @param it The transaction. - * @param mutex The mutex. - */ -template -void transaction_pool::dec(Set &set, - SetIterator &it, - boost::mutex &mutex) -{ - Set del_these; - - { - boost::mutex::scoped_lock lock(mutex); - - for(it = set.begin(); it != set.end(); it++) { - (*it)->transaction_stop_when--; - ODTONE_LOG(1, "(transaction_pool) decrementing tid ", (*it)->tid, " counter down to ", (*it)->transaction_stop_when); - if ((*it)->transaction_stop_when == 0) { - (*it)->run(); - - if ((*it)->transaction_status == ONGOING) - del_these.insert(*it); - } - - if ((*it)->ack_requestor_status == ONGOING) { - (*it)->retransmission_when--; - if ((*it)->retransmission_when == 0) { - (*it)->ack_requestor(); - (*it)->run(); - } - } - - if ((*it)->transaction_status != ONGOING) - del_these.insert(*it); - } - } - - // delete finished transactions - for (it = del_these.begin(); it != del_these.end(); it++) - del(*it); -} - -/** - * Decrements each transaction timer existente in the transaction pool. - */ -void transaction_pool::tick() -{ - //ODTONE_LOG(1, "(transaction_pool) tick"); - _timer.expires_from_now(boost::posix_time::seconds(1)); - _timer.async_wait(boost::bind(&transaction_pool::tick, this)); - - src_transaction_set::iterator src_it; - if (_src.size() > 0) - dec(_src, src_it, _src_mutex); - - dst_transaction_set::iterator dst_it; - if (_dst.size() > 0) - dec(_dst, dst_it, _dst_mutex); -} - -/** - * Add a new source transaction entry in the transaction pool. - * - * @param t The source transaction pointer. - */ -void transaction_pool::add(src_transaction_ptr &t) -{ - ODTONE_LOG(1, "(transaction_pool) add src tid ", t->tid); - boost::mutex::scoped_lock lock(_src_mutex); - _src.insert(t); -} - -/** - * Add a new destination transaction entry in the transaction pool. - * - * @param t The destination transaction pointer. - */ -void transaction_pool::add(dst_transaction_ptr &t) -{ - ODTONE_LOG(1, "(transaction_pool) add dst tid ", t->tid); - boost::mutex::scoped_lock lock(_dst_mutex); - _dst.insert(t); -} - -/** - * Remove an existing source transaction entry from the transaction pool. - * - * @param t The source transaction pointer to be removed. - */ -void transaction_pool::del(const src_transaction_ptr &t) -{ - ODTONE_LOG(1, "(transaction_pool) del src tid ", t->tid); - boost::mutex::scoped_lock lock(_src_mutex); - _src.erase(t); -} - -/** - * Remove a existing destination transaction entry from the transaction pool. - * - * @param t destination transaction pointer to be removed. - */ -void transaction_pool::del(const dst_transaction_ptr &t) -{ - ODTONE_LOG(1, "(transaction_pool) del dst tid ", t->tid); - boost::mutex::scoped_lock lock(_dst_mutex); - _dst.erase(t); -} - -/** - * Searchs for a source transaction in the transaction pool. - * - * @param id The MIH destination identifier to search for. - * @param tid The transaction identifier to search for. - * @param t The source transaction pointer. - */ -void transaction_pool::find(const mih::id &id, uint16 tid, src_transaction_ptr &t) -{ - boost::mutex::scoped_lock lock(_src_mutex); - src_transaction_set::iterator it; - - for(it = _src.begin(); it != _src.end(); it++) { - if(((*it)->peer_mihf_id == id) && (*it)->tid == tid) { - t = *it; - return; - } - } -} - -/** - * Searchs for a destination transaction in the transaction pool. - * - * @param id The MIH source identifier to search for. - * @param tid The transaction identifier to search for. - * @param t The destination transaction pointer. - */ -void transaction_pool::find(const mih::id &id, uint16 tid, dst_transaction_ptr &t) -{ - boost::mutex::scoped_lock lock(_dst_mutex); - dst_transaction_set::iterator it; - - for(it = _dst.begin(); it != _dst.end(); it++) { - if(((*it)->peer_mihf_id == id) && (*it)->tid == tid) { - t = *it; - return; - } - } -} - - -} /* namespace mihf */ } /* namespace odtone */ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/build_all.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/build_all.bash deleted file mode 100644 index 688342049a..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/build_all.bash +++ /dev/null @@ -1,122 +0,0 @@ -#! /bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file build_all.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### - -echo_success "\n###############################" -echo_success "# Check installed utils and libs" -echo_success "###############################" -test_command_install_package "gccxml" "gccxml" "--force-yes" -test_command_install_package "iptables" "iptables" -#test_command_install_package "ebtables" "ebtables" "--force-yes" -test_command_install_package "ip" "iproute" -test_install_package "openssl" -test_install_package "libblas-dev" -# for itti analyser -test_install_package "libgtk-3-dev" -test_install_package "libxml2" -test_install_package "libxml2-dev" -test_install_package "libforms-bin" "--force-yes" -test_install_package "libforms-dev" -test_install_package "libatlas-dev" -test_install_package "libatlas-base-dev" -test_install_package "libpgm-5.1-0" "--force-yes" -test_install_package "libpgm-dev" "--force-yes" -test_install_package linux-headers-`uname -r` -test_install_package "tshark" "--force-yes" -# for ODTONE git clone -test_install_package "git" - -test_install_asn1c_4_rrc_cellular - - -echo_success "\n###############################" -echo_success "# COMPILE oaisim" -echo_success "###############################" -cd $OPENAIR_TARGETS/SIMU/USER -#echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo `" -#make --keep-going oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo ` - -echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 -j`grep -c ^processor /proc/cpuinfo `" -#make --keep-going oaisim NAS= -make --keep-going oaisim DEBUG=1 NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 -j`grep -c ^processor /proc/cpuinfo ` - -if [[ $? -eq 2 ]] ; then - exit 1 -fi - - -echo_success "\n###############################" -echo_success "# COMPILE IP kernel drivers" -echo_success "###############################" -echo_success "Compiling IP Drivers" -cd $OPENAIR2_DIR -make naslite_netlink_ether.ko -cd $OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/ -make - - -echo_success "\n###############################" -echo_success "# COMPILE MIH-F" -echo_success "###############################" -cd $ODTONE_ROOT -b2 --boost-root=$BOOST_ROOT linkflags=-lpthread - - -echo_success "\n###############################" -echo_success "# COMPILE MIH-USER" -echo_success "###############################" -cd $ODTONE_ROOT/app/lte_test_user/ -b2 --boost-root=$BOOST_ROOT linkflags=-lrt linkflags=-lpthread - - -echo_success "\n###############################" -echo_success "# COMPILE ITTI ANALYSER" -echo_success "###############################" -cd $OPENAIR_DIR/common/utils/itti_analyzer -if [ ! -f $OPENAIR_DIR/common/utils/itti_analyzer/Makefile ] - then - autoreconf -i - mkdir -m 777 objs - cd objs - ../configure - fi -sudo make install -j`grep -c ^processor /proc/cpuinfo ` - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/env_802dot21.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/env_802dot21.bash deleted file mode 100644 index 32bc915d99..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/env_802dot21.bash +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file env_802dot21.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# - -##################################################### -# VARIABLES TO BE FILLED WITH RIGHT VALUES: -##################################################### -export BOOST_ROOT=path_to_boost_folder -export ODTONE_ROOT=path_to_odtone_folder - -export MIH_F=odtone-mihf -export ENB_MIH_F_CONF_FILE=odtone_enb.conf -export UE_MIH_F_CONF_FILE=odtone_ue.conf - -export ODTONE_MIH_USER_DIR=$ODTONE_ROOT/app/lte_test_user -export ODTONE_MIH_EXE_DIR=$ODTONE_ROOT/dist - -#export ENB_MIH_USER=enb2_lte_user -#export ENB_MIH_USER_CONF_FILE=enb2_lte_user.conf -export ENB_MIH_USER=enb_lte_user -export ENB_MIH_USER_CONF_FILE=enb_lte_user.conf - -export UE_MIH_USER=ue_lte_user -export UE_MIH_USER_CONF_FILE=ue_lte_user.conf -##################################################### - - -ENV_SCRIPT_SOURCED="?" -ENV_SCRIPT_ERRORS="no" - -if [[ $BASH_SOURCE != $0 ]]; then - THIS_SCRIPT_PATH=${BASH_SOURCE%env_802dot21.bash} - [[ x"$THIS_SCRIPT_PATH" == x ]] && THIS_SCRIPT_PATH="./" - ENV_SCRIPT_SOURCED="yes" -else - THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -fi - -ENV_SCRIPT_STARTED="yes" -source $THIS_SCRIPT_PATH/utils.bash - -if [ -d $ODTONE_ROOT ]; then - echo_success "ODTONE_ROOT = $ODTONE_ROOT." >&2 -else - echo_error "ODTONE_ROOT variable was not set correctly, please update ($ODTONE_ROOT)." >&2 -fi -if [ ! -d $BOOST_ROOT ]; then - echo_error "BOOST_ROOT variable was not set correctly, please update (may be you also need to install boost), exiting." - ENV_SCRIPT_ERRORS="yes" -else - command -v b2 >/dev/null 2>&1 - if [ $? -ne 0 ]; then - echo_warning "Program b2 is not installed or not in the PATH variable. Trying to resolve..." >&2 - if [[ -x "$BOOST_ROOT/b2" ]]; then - echo_success "Program b2 found in dir $BOOST_ROOT." >&2 - export PATH=$PATH:$BOOST_ROOT - else - echo_warning "Program b2 not found in dir $BOOST_ROOT. Trying to install..." >&2 - cd $BOOST_ROOT; ./bootstrap.sh; - cd - - export PATH=$PATH:$BOOST_ROOT - fi - command -v $BOOST_ROOT/b2 >/dev/null 2>&1 - if [ $? -eq 0 ]; then - echo_success "Program b2 is now reachable by the PATH variable during the execution of this script." >&2 - else - echo_error "Built of b2 failed. Please help yourself" >&2 - fi - fi -fi - - -if [ ! -d $ODTONE_ROOT ]; then - echo_error "ODTONE_ROOT variable was not set correctly, please update (may be you also need to install odtone), exiting." - ENV_SCRIPT_ERRORS="yes" -fi - - -[[ x"$ENV_SCRIPT_ERRORS" == "xyes" ]] && [[ x"$ENV_SCRIPT_SOURCED" == "xyes" ]] && return 1 -[[ x"$ENV_SCRIPT_ERRORS" == "xyes" ]] && [[ x"$ENV_SCRIPT_SOURCED" == "xno" ]] && exit 1 - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/utils.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/utils.bash deleted file mode 100644 index 9ce016d1d2..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/common/openair_scripts/utils.bash +++ /dev/null @@ -1,377 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file utils.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# - -cidr2mask() { - local i mask="" - local full_octets=$(($1/8)) - local partial_octet=$(($1%8)) - - for ((i=0;i<4;i+=1)); do - if [ $i -lt $full_octets ]; then - mask+=255 - elif [ $i -eq $full_octets ]; then - mask+=$((256 - 2**(8-$partial_octet))) - else - mask+=0 - fi - test $i -lt 3 && mask+=. - done - - echo $mask -} - - -black='\E[30m' -red='\E[31m' -green='\E[32m' -yellow='\E[33m' -blue='\E[34m' -magenta='\E[35m' -cyan='\E[36m' -white='\E[37m' -reset_color='\E[00m' - -ROOT_UID=0 -E_NOTROOT=67 - -HOSTNAME=$(hostname -f) - -trim () -{ - echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' -} - -trim2() -{ - local var=$@ - var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters - var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters - echo -n "$var" -} - -cecho() # Color-echo -# arg1 = message -# arg2 = color -{ - local default_msg="No Message." - message=${1:-$default_msg} - color=${2:-$green} - echo -e -n "$color$message$reset_color" - echo - return -} - -echo_error() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $red -} - -echo_warning() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $yellow -} - -echo_success() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $green -} - -bash_exec() { - output=$($1 2>&1) - result=$? - if [ $result -eq 0 ] - then - echo_success "$1" - else - echo_error "$1: $output" - fi -} - - -extract() { - if [ -f $1 ] ; then - case $1 in - *.tar.bz2) tar xvjf $1 ;; - *.tar.gz) tar xvzf $1 ;; - *.bz2) bunzip2 $1 ;; - *.rar) unrar $1 ;; - *.gz) gunzip $1 ;; - *.tar) tar xvf $1 ;; - *.tbz2) tar xvjf $1 ;; - *.tgz) tar xvzf $1 ;; - *.zip) unzip $1 ;; - *.Z) uncompress $1 ;; - *.7z) 7z x $1 ;; - *) echo_error "'$1' cannot be extracted via >extract<" ; return 1;; - esac - else - echo_error "'$1' is not a valid file" - return 1 - fi - return 0 -} - - -set_openair() { - path=`pwd` - declare -i length_path - declare -i index - length_path=${#path} - - for i in 'openair1' 'openair2' 'openair3' 'openair-cn' 'targets' - do - index=`echo $path | grep -b -o $i | cut -d: -f1` - #echo ${path%$token*} - if [[ $index -lt $length_path && index -gt 0 ]] - then - declare -x OPENAIR_DIR - index=`expr $index - 1` - openair_path=`echo $path | cut -c1-$index` - #openair_path=`echo ${path:0:$index}` - export OPENAIR_DIR=$openair_path - export OPENAIR1_DIR=$openair_path/openair1 - export OPENAIR2_DIR=$openair_path/openair2 - export OPENAIR3_DIR=$openair_path/openair3 - export OPENAIRCN_DIR=$openair_path/openair-cn - export OPENAIR_TARGETS=$openair_path/targets - return 0 - fi - done - return -1 -} - -test_install_asn1c_4_rrc_cellular() { - if [ -d $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c ]; then - if [ -x $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c/asn1c/asn1c ]; then - if [ -x /usr/local/bin/asn1c ]; then - diff /usr/local/bin/asn1c $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c/asn1c/asn1c >/dev/null 2>&1; - if [ $? -eq 0 ]; then - echo_success "asn1c for RRC cellular installed" - return 0 - fi - fi - echo_warning "Installing asn1c for RRC cellular..." - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c - sudo make install - return 0 - fi - else - echo_warning "asn1c for RRC cellular is not installed in $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/. Installing it" - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c - svn co https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk asn1c - fi - echo_warning "Configuring and building and installing asn1c for RRC cellular..." - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c - ./configure - make - sudo make install -} - -wait_process_started () { - if [ -z "$1" ] - then - echo_error "WAITING FOR PROCESS START: NO PROCESS" - return 1 - fi - ps -C $1 > /dev/null 2>&1 - while [ $? -ne 0 ]; do - echo_warning "WAITING FOR $1 START" - sleep 2 - ps -C $1 > /dev/null 2>&1 - done - echo_success "PROCESS $1 STARTED" - return 0 -} - -is_process_started () { - if [ -z "$1" ] - then - echo_error "WAITING FOR PROCESS START: ERROR NO PROCESS NAME IN ARGUMENT" - return 1 - fi - ps -C $1 > /dev/null 2>&1 - if [ $? -ne 0 ] - then - echo_success "PROCESS $1 NOT STARTED" - return 1 - fi - echo_success "PROCESS $1 STARTED" - return 0 -} - -assert() { - # If condition false - # exit from script with error message - E_PARAM_ERR=98 - E_PARAM_FAILED=99 - - if [ -z "$2" ] # Not enought parameters passed. - then - return $E_PARAM_ERR - fi - - lineno=$2 - if [ ! $1 ] - then - echo "Assertion failed: \"$1\"" - echo "File \"$0\", line $lineno" - exit $E_ASSERT_FAILED - fi -} - - -test_install_package() { - # usage: test_install_package package_name_to_be_installed optional_option_to_apt_get_install - dpkg --get-selections $1 | grep -i install > /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo_warning "Package $1 is not installed. Installing it." >&2 - apt-get install $2 $1 -y - dpkg --get-selections $1 | grep -i install > /dev/null 2>&1 - if [ $? -ne 0 ]; then - exit 1 - fi - else - echo_success "$1 is installed" - fi - return 0 -} - - - -test_command_install_package() { - # usage: test_command_install_package searched_binary package_to_be_installed_if_binary_not_found optional_option_to_apt_get_install - if [ $# -eq 2 ]; then - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it." >&2; apt-get install $2 -y; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - else - if [ $# -eq 3 ]; then - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it (apt-get install $3 $2)." >&2; apt-get install $3 $2 -y; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - else - echo_success "test_command_install_package: BAD PARAMETER" - exit 1 - fi - fi - echo_success "$1 available" -} - -test_command_install_script() { - # usage: test_command_install_script searched_binary script_to_be_invoked_if_binary_not_found - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it." >&2; bash $2; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - echo_success "$1 available" -} - -start_openswitch_daemon() { - rmmod -s bridge - if [[ -e "/lib/modules/`uname -r`/extra/openvswitch.ko" ]] ; then - bash_exec "insmod /lib/modules/`uname -r`/extra/openvswitch.ko" - else - echo_error "/lib/modules/`uname -r`/extra/openvswitch.ko not found, exiting" - exit -1 - fi - is_process_started "ovsdb-server" - if [ $? -ne 0 ] - then - ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,manager_options --pidfile --detach - wait_process_started "ovsdb-server" - fi - # To be done after installation - # ovs-vsctl --no-wait init - is_process_started "ovs-vswitchd" - if [ $? -ne 0 ] - then - ovs-vswitchd --pidfile --detach - wait_process_started "ovs-vswitchd" - fi -} - -check_enb_config() { - if [ ! -f $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf ] - then - echo "Cannot find file $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf" - echo "Please make sure to create one that fits your use (you can use mme_default.conf file as template)" - exit -1 - fi -} - - -check_for_root_rights() { - if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root" 1>&2 - exit -1 - fi -} - -rotate_log_file () { - if [ -f $1 ]; then - TIMESTAMP=`date +%Y-%m-%d.%Hh_%Mm_%Ss` - NEWLOGFILE=$1.$TIMESTAMP - mv $1 $NEWLOGFILE - cat /dev/null > $1 - sync - nohup gzip -f -9 $NEWLOGFILE & - fi -} - -########################################################### -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIRCN_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIRCN_DIR = $OPENAIRCN_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/enb_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/enb_lte_user.conf deleted file mode 100644 index b9bbf279de..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/enb_lte_user.conf +++ /dev/null @@ -1,40 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_enb - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/link_sap.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/link_sap.conf deleted file mode 100644 index c5b63413d0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/link_sap.conf +++ /dev/null @@ -1,47 +0,0 @@ -#=============================================================================== -# Brief : Link SAP configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[link] -## -## Link SAP identifier -## -id=link1 - -## -## Link SAP listening -## -port = 1235 - -## -## Link SAP interface technology -## -tec = 802_11 - -## -## Link SAP interface address -## -link_addr = 00:11:22:33:44:55 - -## -## Comma separated list of the Link SAP supported events -## -event_list = link_detected, link_up, link_down, link_parameters_report, link_going_down, link_handover_imminent, link_handover_complete - -[mihf] -ip=127.0.0.1 -local_port=1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/odtone_enb.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/odtone_enb.conf deleted file mode 100644 index 93d8fa1a9f..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_conf/odtone_enb.conf +++ /dev/null @@ -1,72 +0,0 @@ -#=============================================================================== -# Brief : MIHF configuration file -# Authors : Carlos Guimaraes -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[mihf] -## -## This mihf's id -## -## Usage: id = -## -id = mihf1_enb - -## -## Port on localhost that MIH Users and MIH Link SAPs connect to. -## -## Usage: local_port = -## -local_port = 1025 - -## -## Port to which remote peer MIHF connect to -## -## Usage: remote_port = -## -remote_port = 4551 - -## -## Comma seperated list of remote MIHF's -## -## If you want to test remote MIHF communication add an entry here -## with the IP address of the remote MIHF. -## -## Usage: peers = , ... -## -#peers = mihf2_ue 192.168.13.1 4551 udp, mihf3_ue 192.168.56.101 4551 udp -peers = mihf2_ue 10.0.0.2 4551 udp, mihf3_ue 192.168.14.4 4551 udp - -## -## Comma separated list of local MIH User SAPs id's and ports -## -## Usage: users = [ ], ... -## Note: If no command is specified, the MIHF will assume that the MIH-User -## supports all MIH_***_HO_*** commands and the MIH_Get_Information -## Note: If no query is specified, the MIHF will assume that the MIH-User does -## not support the MIH_Get_Information command. -## -users = user_enb 1635 - -## -## Comma separated list of local MIH Link SAPs id's and ports. -## -## Usage: links = [ ], ... -## -links = enb_lte_link00 1234 LTE 00:39:18:36:62:00 00:11:33 5, enb_eth_link00 1234 802_3 e0:db:55:eb:33:ac - -## -## Comma separated list of the MIHF's transport protocol -## -transport = udp diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient deleted file mode 100644 index 29465e592a..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.cpp deleted file mode 100644 index 8e384e776d..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "cpprest/basic_types.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/uri.h" -#include - -#include "CRMClient.hpp" - -using namespace std; -using namespace web; -using namespace web::http; -using namespace web::http::client; -using namespace utility; - - -CRMClient::CRMClient(char* url) -{ - m_url = (char*) (malloc (200* sizeof (char))); - m_url = url; -} - -CRMClient::CRMClient() -{ -} - -CRMClient::~CRMClient() -{ -} - -void CRMClient::SetUrl(char* url) -{ - m_url = url; -} - - -/****************************************************** -* Retrieves a JSON value from an HTTP request -* The JSON value is stored in the file "outputGET.txt" -*******************************************************/ - -pplx::task CRMClient::RequestJSONValueAsync() -{ - http_client client (U(m_url)); - return client.request(methods::GET).then([](http_response response) -> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - ofstream myfile; - myfile.open ("outputGET.txt"); - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString <second; - - for(auto iterInner = arrayValue.cbegin(); iterInner != arrayValue.cend(); ++iterInner) - { - const json::value &propertyValue = iterInner->second; - for(auto iterlast = propertyValue.cbegin(); iterlast != propertyValue.cend(); ++iterlast) - { - const json::value &Name = iterlast->first; - const json::value &Value = iterlast->second; - cout<< U("Parameter: ") << Name.to_string()< CRMClient::StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4) -{ - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("pid"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6) -{ - - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("key"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("type"), json::value(param3))); - putvalue.push_back(make_pair(json::value("unit"), json::value(param4))); - putvalue.push_back(make_pair(json::value("value"), json::value(param5))); - putvalue.push_back(make_pair(json::value("time"), json::value(param6))); - - const string_t& s = ""; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5) -{ - - http_client client (U(m_url)); - json::value::field_map putvalue; - - putvalue.push_back(make_pair(json::value("did"), json::value(param1))); - putvalue.push_back(make_pair(json::value("name"), json::value(param2))); - putvalue.push_back(make_pair(json::value("description"), json::value(param3))); - putvalue.push_back(make_pair(json::value("value"), json::value(param4))); - putvalue.push_back(make_pair(json::value("time"), json::value(param5))); - - const string_t& s = "/"; - json::value object = json::value::object(putvalue); - return client.request(methods::PUT, s, object).then([](http_response response)-> pplx::task - { - if(response.status_code() == status_codes::OK) - { - return response.extract_json(); - } - - return pplx::task_from_result(json::value()); - }) - .then([](pplx::task previousTask) - { - try - { - const json::value& v = previousTask.get(); - string_t jsonString = v.to_string(); - cout << U("Response...") << jsonString < CRMClient::Delete() -{ - char* url = m_url; - return pplx::create_task([url] - { - http_client client (U(url)); - - return client.request(methods::DEL); - - }).then([](http_response response) - { - if(response.status_code() == status_codes::OK) - { - auto body = response.extract_string(); - - std::wcout << L"Deleted: " << body.get().c_str() << std::endl; - } - }); -} diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.hpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.hpp deleted file mode 100644 index a49f2e62c8..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClient.hpp +++ /dev/null @@ -1,94 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : FATMA HRIZI -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#ifndef ODTONE_CRM_CLIENT_HPP -#define ODTONE_CRM_CLIENT_HPP - - -#include -#include -#include -#include -#include -#include "cpprest/basic_types.h" -#include "cpprest/asyncrt_utils.h" -#include "cpprest/uri.h" -#include - - -/** - * CRM Client Class - * - * Defines the required functions to Get/Store Data from/in the CRRM - * - **/ -class CRMClient { - -public: - - CRMClient(); - CRMClient(char* url); - ~CRMClient(); - - void SetUrl(char* url); - - /** - * Get the data from the CRRM - * - * Returns JSON Format - */ - pplx::task RequestJSONValueAsync(); - - /** - * Store Policies data from the CRRM - * - * Takes 4 parameters: P_ID, Name, Description, Value - * Returns the JSON format of the stored entity - */ - pplx::task StoreJSONValuePolicies(char * param1, char * param2, char * param3, char * param4); - - /** - * Store Measurements data from the CRRM - * - * Takes 5 parameters: M_ID, Name, Type, Unit, Value, Time - * Returns the JSON format of the stored entity - */ - pplx::task StoreJSONValuemeasurements(char * param1, char * param2, char * param3, char * param4, char * param5, char * param6); - - /** - * Store Decisions data from the CRRM - * - * Takes 4 parameters: D_ID, Name, Description, Value - * Returns the JSON format of the stored entity - */ - pplx::task StoreJSONValuedecisions(char * param1, char * param2, char * param3, char * param4, char * param5); - - - - /** - * Delete Entities from the CRRM - * - * Returns the JSON format of the deleted entity - */ - pplx::task Delete(); - - -private: - char * m_url; - -}; -#endif diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClientmain b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClientmain deleted file mode 100644 index 971f08c4fe..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/CRMClientmain and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Jamfile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Jamfile deleted file mode 100644 index c2a6aecbc4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Jamfile +++ /dev/null @@ -1,44 +0,0 @@ -#=============================================================================== -# Brief : MIH-User SAP Application Sample Project Build -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -project enb_lte_user - ; - -exe enb_lte_user - : enb_lte_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - -install install - : enb_lte_user - enb_lte_user.conf - ue_lte_user - ue_lte_user.conf - : ../../dist - ; - -project ue_lte_user - ; - -exe ue_lte_user - : ue_lte_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Makefile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Makefile deleted file mode 100644 index b6837ad748..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -main: main.cpp - g++-4.8 -Wall main.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -L. -std=c++11 -lcrmclient -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -o CRMClientmain - -lib: CRMClient.cpp - -# 64 bits compilation -# g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -m64 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem -# g++-4.8 -shared -m64 -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o -# ln -sf libcrmclient.so.1.0 libcrmclient.so -# ln -sf libcrmclient.so.1.0 libcrmclient.so.1 - -# 32 bits compilation - g++-4.8 -Wall -fPIC -c CRMClient.cpp -I /opt/casablanca/Release/include/ -L/usr/local/lib -L/opt/casablanca/Binaries/Release32/ -std=c++11 -lpthread -lboost_system -lboost_thread -lcasablanca -lboost_filesystem - g++-4.8 -shared -Wl,-soname,libcrmclient.so.1 -o libcrmclient.so.1.0 CRMClient.o - ln -sf libcrmclient.so.1.0 libcrmclient.so - ln -sf libcrmclient.so.1.0 libcrmclient.so.1 - -clean: - rm *.o *.so* diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/diffueenb b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/diffueenb deleted file mode 100644 index 2babd62267..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/diffueenb +++ /dev/null @@ -1,201 +0,0 @@ -difference between UE and eNB implementation: - -net_type_addr_list2string - -send_MIH_Link_Action_Power_Up_plus_scan_request: added in UE - -event_handler: -case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1;; - } - break; - - -No action in the odtone::mih::indication::link_parameters_report - -Define the eNB Scenario: - - -The UE Scenario: - -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - - - - -the eNB scenario - -// +--------+ +-----+ +---------+ +----------+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | | LINK_SAP | | MIH-F | -// +---+----+ +--+--+ +----+----+ +----+-----+ +---------+ -// | | | | | -// ... (start of MIH-F here) ... ... ... | -// | |---------- Link_Capability_Discover.request --------X| | | -// ... (start of LINK_SAP here) ... ... | | -// | |<--------- Link_Register.indication -----------------| | | -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// ------------------------------------------------------------------------------------------------------------------------ -// Get the measurements from the UE -// ------------------------------------------------------------------------------------------------------------------------ - -Is this necessary? the link is not up by default?? -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -Is this necessary? the link is not up by default?? - -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | - ... -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | - -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| - - -// ------------------------------------------------------------------------------------------------------------------------ -// END OF THE EXECUTION -// ------------------------------------------------------------------------------------------------------------------------ - - - - - - - - - - - - - - - - - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -// +--------+ +-----+ -// |MIH_USER| |MIH-F| -// +---+----+ +--+--+ -// | | _current_link_action_request = 0 -// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -// | | -// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -// |<--------- Capability_Discover.confirm --------------| (success) -// | | -// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 1: Sequentially activate and deactivate each resource -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// |<--------- Link_Actions.confirm ---------------------| (success) -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 2: Activate all resources, then deactivate all resources -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | _current_link_action_request = 0 -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// | | -/////////////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/dummy_130606.tgz b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/dummy_130606.tgz deleted file mode 100644 index 11ef083a92..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/dummy_130606.tgz and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/eNB_lte_user_tcs.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/eNB_lte_user_tcs.cpp deleted file mode 100644 index 72d46e791b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/eNB_lte_user_tcs.cpp +++ /dev/null @@ -1,1412 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -// Fatma HRIZI EURECOM fr> -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -//This file is the implementation of the MIH user in the eNB - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -// +--------+ +-----+ -// |MIH_USER| |MIH-F| -// +---+----+ +--+--+ -// | | _current_link_action_request = 0 -// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -// | | -// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -// |<--------- Capability_Discover.confirm --------------| (success) -// | | -// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 1: Sequentially activate and deactivate each resource -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// |<--------- Link_Actions.confirm ---------------------| (success) -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 2: Activate all resources, then deactivate all resources -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | _current_link_action_request = 0 -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// | | -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s; - if(evtP.get(odtone::mih::mih_evt_link_detected)) s = std::string("DETECTED "); - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s; - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s = std::string("Link_Get_Parameters "); - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(const odtone::mih::config& cfg); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES) -//----------------------------------------------------------------------------- -{ - - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - log_(0, ""); - - // - // Local Capability Discover Request - // - odtone::mih::message msg; - _mihfid.assign("mihf2"); - msg << odtone::mih::request(odtone::mih::request::capability_discover, _mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Capability_Discover.request --->]["+msg.destination().to_string()+"]\n"); - _mihf.async_send(msg, boost::bind(&mih_user::receive_MIH_Capability_Discover_confirm, this, _1)); - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)"); - log_(0, ""); - - //****eNB***** - // Remote Capability Discover Request - // - mih_user::send_MIH_Capability_Discover_request(cfg); - - //Trigger Link_Configure_Thresholds Request - // odtone::mih::message m; - //m.destination(msg.source()); - //mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - //****eNB***** -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - } - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - - break; - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} -/* -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - log_(0, "MIH_Link_Detected.indication - End\n"); -} -*/ -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - -boost::system::error_code ec; - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - log_(0, " - LINK_ID - Link identifier: ", link_id2string(i->id).c_str()); - log_(0, " - Network ID: ", i->network_id); - log_(0, " - SINR: ", i->sinr); - log_(0, " - Data_rate: ", i->data_rate); - } - - send_MIH_Link_Configure_Thresholds_request(msg, ec); - - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (const odtone::mih::threshold *th = boost::get(&i->thold)) { - - log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available - } - else{ - log_(0, " -Regular Report for BW Threshold "); - //update MEAS - } - } - - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - //boost::optional ntal; - //boost::optional evt; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::request(odtone::mih::request::capability_discover) - //& odtone::mih::tlv_net_type_addr_list(ntal) - //& odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - _mihfid.assign("mihf2"); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - odtone::mih::threshold th; - std::vector thl; - - odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - - - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - - odtone::mih::link_det_info_list ldil; - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - - - lti.type = i->id.type; - lti.addr = i->id.addr; - lp = odtone::mih::link_param_lte_bandwidth; - lcp.type = lp; - if ( link_measures_request ==0){ - lcp.timer_interval = 10; - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } - else{ - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - th.threshold_val = 5; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - } - -/* - if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -*/ -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1234), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.conf deleted file mode 100644 index b9bbf279de..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.conf +++ /dev/null @@ -1,40 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_enb - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.cpp deleted file mode 100644 index 8b6d45652e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/enb_lte_user.cpp +++ /dev/null @@ -1,1713 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -//The thresholds for the Energy Detection Sensing algorithm respectively for 10 and 100 samples -#define ED_THRESHOLD_10 23695432 -#define ED_THRESHOLD_100 230445932 -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Initiallization of the MIH-USER and the MIHF -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | - -// ------------------------------------------------------------------------------------------------------------------------ -// Locally send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to local MIHF) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | - -// ------------------------------------------------------------------------------------------------------------------------ -// Remotely send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to remote MIHF of the UE) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Detect the connection of the UE to the eNB + Start the measurement report process -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Activate the TVWS link (After running the cognitive algorithms) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -// | | | -// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -// | | | - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static const char* const kConf_MIH_Commands = "user.commands"; - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string exec(char* cmd) { - FILE* pipe = popen(cmd, "r"); - if (!pipe) return "ERROR"; - char buffer[128]; - std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - pclose(pipe); - return result; -} - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} - - -/*//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} -*/ - -//Updated from UE code -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - - //Measurements report methods - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - int receive_Sensing_Report(); - void receive_CRRM_Data(); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - void forward_Parameters_Report_indication(odtone::mih::message& m); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - odtone::uint second_link_activated; - odtone::uint count; - odtone::uint sensing_done; - odtone::uint sensing_score; - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - second_link_activated = 0; - count = 0; - sensing_done = 0; - sensing_score = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - - //send a capability discover request to the remote UE - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - boost::system::error_code ec; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} -// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - //for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - //{ - // rcv_link_id.addr = i->addr; - // rcv_link_id.type = boost::get(i->nettype.link); - //} - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - - std::cout<<"NTALL "<begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; -// std::ostringstream stream; -// std::stringstream st; -// odtone::mih::net_type_addr net_type_addr; -// net_type_addr = boost::get(*i); -// stream << net_type_addr; -// std::string s; -// std::stringstream st (stream.str()); -// while (getline (st, s, '\n')) -// { -// std::stringstream ss(s); -// getline (ss, name, ':'); -// getline (ss, value, '\n'); -// // ss>>name>>value; -// std::cout<<" name "<addr; - getline (st, s, ' '); - std::cout<<"LINK_TUPLE_ID s "<(*/i->addr/*)*/; - li.type = boost::get(i->nettype.link); - if (std::find(_link_id_list.begin(), _link_id_list.end(), li)==_link_id_list.end()) - _link_id_list.push_back(li); // save the link identifier of the network interface - - std::cout<<"LINK_TUPLE_ID - Link identifier:after "<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// std::cout<<"_link_id_list addr "<addr<<" TYPE "<type<addr<<" TYPE "<type<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - -// link_act_req.action.param.param = res; - -// link_act_req.ex_time = 0; - link_act_req.ex_time = 5000; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - -// odtone::mih::id mid_ue; -// mid_ue.assign("mihf2_ue"); - m.destination(/*mid_ue*/_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st); -// & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -// if (larl) { -// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -// { -// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -// } -// } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -// #ifdef SCENARIO_1 -// if (larl) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// if (rsp->result.get() == odtone::mih::link_ac_success) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// _current_link_action_request += 1; -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_1 -// -// #ifdef SCENARIO_2 -// // 2nd scenario: Activate all resources, then deactivate all resources -// if (larl.get().size() > 0) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (++_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// _current_link_action_request = 0; -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -void mih_user::receive_CRRM_Data() -{ - - //CRRM data report - std::string result = exec ("./CRMClientmain 0 1"); -} - -//----------------------------------------------------------------------------- -int mih_user::receive_Sensing_Report() -//----------------------------------------------------------------------------- -{ - std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); - std::string tmp; - int value; - std::stringstream ss(result); - ss >> tmp >> value; - std::cout<<"Result of Sensing "<> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value ); - // ferreira: Upload of measurements to gae-spectra.com - // FIXME This will not work for: more than 3 types of measurements OR out of sequence types of measurements - std::string crmc_cmd_str; - std::stringstream crmc_ss; - std::string result; - if (count % 10 == 0) // All measures at CRM are outdated! do server cleanup! - result = exec ("./CRMClient DEL 2"); - if (count % 3 == 0) // Add 1st measurement (RSRP) - crmc_ss << "./CRMClient PUT 2 meas_no." << count << " " << msg.source().to_string() << "_" << link_id2string(link).c_str() << " RSRP dB " << (short) *value << " 3" ; - if (count % 3 == 1) // Add 2nd measurement (RSRQ) - crmc_ss << "./CRMClient PUT 2 meas_no." << count << " " << msg.source().to_string() << "_" << link_id2string(link).c_str() << " RSRQ dB " << (short) *value << " 3" ; - if (count % 3 == 2) // Add 3rd measurement (CQI) - crmc_ss << "./CRMClient PUT 2 meas_no." << count << " " << msg.source().to_string() << "_" << link_id2string(link).c_str() << " CQI - " << (short) *value << " 3" ; - crmc_cmd_str = crmc_ss.str(); - const char* crmc_cmd_cstr = crmc_cmd_str.c_str(); - char* crmc_cmd_char = new char [strlen(crmc_cmd_cstr)+1]; - strcpy(crmc_cmd_char, crmc_cmd_cstr); - result = exec (crmc_cmd_char); - delete [] crmc_cmd_char; - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - - //eNB1: Forward the message to UE 2 - forward_Parameters_Report_indication(msg); - - //eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm - - //First Phase: Collect the data as input fot the cognitive algorithm - //Sensing data - if (sensing_done == 0) - sensing_score = receive_Sensing_Report(); - - //CRRM Data - receive_CRRM_Data(); - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (odtone::mih::threshold *th = boost::get(&i->thold)) { -// log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// if(*i==link) - odtone::mih::l2_3gpp_addr add; - odtone::mih::link_type type; - type = odtone::mih::link_type_lte; -// add.value = "l2_3gpp_addr"; - link1.addr = add; - link1.type = type; -// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); - - //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 - if (second_link_activated==0) - { - if (count == 20) - { - send_MIH_Link_Action_Power_Up_request(_link_id_list[1]);//Link LTE - second_link_activated = 1; - } - } - - count++; -// continue; -// send_MIH_Link_Action_Power_Up_request(link); -// if (link_id2string(link).c_str() == "LTE") -// } - } - } - -} - - -//Forward the MIH_Link_Parameters_Report to the UE of the CPE -//----------------------------------------------------------------------------- -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - msg.destination(mid_ue); - - //mn_ho_candidate_query is used to constuct/send the message containing parameters reports - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); - - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - odtone::mih::threshold th2; - std::vector thl1; - std::vector thl2; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lcp1.type = lp1; - lcp2.type = lp2; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th2.threshold_val = -19; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - - - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ " --->][ ADDR LINK " - + m.destination().to_string() +"]\n"); - std::cout<<"LINK TUPLE ID "< lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti); -// & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter()->default_value("enb_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1_enb"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.conf deleted file mode 100644 index 27d56760be..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.cpp deleted file mode 100644 index 896958f62b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/mih_user/lte_test_user/ue_lte_user.cpp +++ /dev/null @@ -1,1399 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -//#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - - - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - // send Link_Action / Power Up - lid.type = odtone::mih::link_type_lte; - lid.addr = ldi.id.addr; - //send_MIH_Link_Action_Power_Up_plus_scan_request(lid); - log_(0, "MIH_Link_Detected.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - - link_act_req.id = link; - link_act_req.action.type = odtone::mih::link_ac_type_power_up; - link_act_req.action.attr.clear(); - link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); - - link_act_req.ex_time = 5000; // in ms - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); - mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); - -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th; - std::vector thl; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp = odtone::mih::link_param_lte_rsrp; - lcp.type = lp; - - link_measures_request = 0; - if ( link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th.threshold_val = -105; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("ue_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf2_ue"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/enb.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/enb.conf deleted file mode 100644 index 8acd6d84af..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/enb.conf +++ /dev/null @@ -1,217 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - # real_time choice in {hard, rt-preempt, no} - real_time = "no"; - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "92"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - # srs_BandwidthConfig =; - # srs_SubframeConfig =; - # srs_ackNackST =; - # srs_MaxUpPts =; - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; - -# rach_sizeOfRA_PreamblesGroupA = ; -# rach_messageSizeGroupA = ; -# rach_messagePowerOffsetGroupB = ; - - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - }, - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; -/* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; -*/ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.13.11"; - ipv6 = "192:168:30::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.13.10/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.13.10/24"; - }; - - log_config : - { - global_log_level ="debug"; - global_log_verbosity ="medium"; - hw_log_level ="debug"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="debug"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - - } -); diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/start_enb.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/start_enb.bash deleted file mode 100644 index 23d02bd58b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb1/oai_conf/start_enb.bash +++ /dev/null @@ -1,196 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_enb.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# ENB CONFIG FILE -#------------------------------------------------ -#declare -x ENB_CONFIG_FILE="CONF/enb.sfr.yang.conf" -declare -x ENB_CONFIG_FILE="enb.conf" - -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth1" -declare -x EMULATION_DEV_ADDRESS="192.168.13.1" -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x ENB_IPv4="10.0.0.1" -declare -x ENB_IPv6="2001:1::1" -declare -x ENB_IPv6_CIDR=$ENB_IPv6"/64" -declare -x ENB_IPv4_CIDR=$ENB_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 6 2 0 0 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x ENB_RAL_IP_ADDRESS="127.0.0.1" -declare -x ENB_MIHF_IP_ADDRESS=127.0.0.1 -MIH_LOG_FILE="mih-f_enb.log" - -#------------------------------------------------ -LOG_FILE="/tmp/oai_sim_enb.log" - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -bash_exec "ifconfig eth2 up 192.168.14.3 netmask 255.255.255.0" -bash_exec "ip r d default via 192.168.14.4 dev eth2" -bash_exec "ip r a default via 192.168.12.100 dev eth0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - -bash_exec "/sbin/iptables -t mangle -F" -bash_exec "/sbin/iptables -t nat -F" -bash_exec "/sbin/iptables -t raw -F" -bash_exec "/sbin/iptables -t filter -F" -bash_exec "/sbin/ip6tables -t mangle -F" -bash_exec "/sbin/ip6tables -t filter -F" -bash_exec "/sbin/ip6tables -t raw -F" - -################################################## -# LAUNCH eNB executable -################################################## - -echo "Bringup eNB interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $ENB_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -bash_exec "ip link set $LTEIF up" -sleep 1 -bash_exec "ip addr add dev $LTEIF $ENB_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $ENB_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" -bash_exec "sysctl -w net.ipv4.ip_forward=1" -assert " `sysctl -n net.ipv4.ip_forward` -eq 1" $LINENO - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ebtables -t nat -A POSTROUTING -p arp -j mark --mark-set 3 - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - - -# start MIH-F -xterm -hold -title "[RELAY][eNB1] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -ENB_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LINK_ID=`trim2 $ENB_RAL_LINK_ID` -ENB_RAL_LINK_ID=`echo $ENB_RAL_LINK_ID | cut -d" " -f1` - -ENB_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LISTENING_PORT=`trim2 $ENB_RAL_LISTENING_PORT` -ENB_RAL_LISTENING_PORT=`echo $ENB_RAL_LISTENING_PORT | cut -d" " -f2` - -ENB_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -ENB_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` -#remove 2 last digits (vitualization, index on 2 digits) -ENB_RAL_LINK_ID_STRIPPED=${ENB_RAL_LINK_ID%%??} - -#xterm -hold -e gdb --args -$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l9 -u0 -b1 -M0 -p2 -g1 -D $EMULATION_DEV_INTERFACE \ - --enb-ral-listening-port $ENB_RAL_LISTENING_PORT \ - --enb-ral-link-id $ENB_RAL_LINK_ID_STRIPPED \ - --enb-ral-ip-address $ENB_RAL_IP_ADDRESS \ - --enb-mihf-remote-port $ENB_MIHF_REMOTE_PORT \ - --enb-mihf-ip-address $ENB_MIHF_IP_ADDRESS \ - --enb-mihf-id $ENB_MIHF_ID \ - -O $ENB_CONFIG_FILE > log_enb.txt & -# -O $ENB_CONFIG_FILE | grep "RAL\|PDCP" & - -wait_process_started oaisim - -# start MIH-USER -# wait for emulation start -tshark -c 150 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -sudo xterm -hold -title "[RELAY][eNB1] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER_CONF_FILE & -wait_process_started $ENB_MIH_USER - -xterm -hold -title "[RELAY][eNB1] CRM Client" -e tail -f outputGET.txt & - -sleep 100000 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/enb2_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/enb2_lte_user.conf deleted file mode 100644 index 356a52abbb..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/enb2_lte_user.conf +++ /dev/null @@ -1,40 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user2_enb - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/link_sap.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/link_sap.conf deleted file mode 100644 index c5b63413d0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/link_sap.conf +++ /dev/null @@ -1,47 +0,0 @@ -#=============================================================================== -# Brief : Link SAP configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[link] -## -## Link SAP identifier -## -id=link1 - -## -## Link SAP listening -## -port = 1235 - -## -## Link SAP interface technology -## -tec = 802_11 - -## -## Link SAP interface address -## -link_addr = 00:11:22:33:44:55 - -## -## Comma separated list of the Link SAP supported events -## -event_list = link_detected, link_up, link_down, link_parameters_report, link_going_down, link_handover_imminent, link_handover_complete - -[mihf] -ip=127.0.0.1 -local_port=1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/odtone_enb.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/odtone_enb.conf deleted file mode 100644 index 56a1f5e89e..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_conf/odtone_enb.conf +++ /dev/null @@ -1,73 +0,0 @@ -#=============================================================================== -# Brief : MIHF configuration file -# Authors : Carlos Guimaraes -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[mihf] -## -## This mihf's id -## -## Usage: id = -## -id = mihf4_enb - -## -## Port on localhost that MIH Users and MIH Link SAPs connect to. -## -## Usage: local_port = -## -local_port = 1025 - -## -## Port to which remote peer MIHF connect to -## -## Usage: remote_port = -## -remote_port = 4551 - -## -## Comma seperated list of remote MIHF's -## -## If you want to test remote MIHF communication add an entry here -## with the IP address of the remote MIHF. -## -## Usage: peers = , ... -## -#peers = mihf3_ue 10.0.0.3 4551 udp -peers = mihf3_ue 10.0.2.3 4551 udp - -## -## Comma separated list of local MIH User SAPs id's and ports -## -## Usage: users = [ ], ... -## Note: If no command is specified, the MIHF will assume that the MIH-User -## supports all MIH_***_HO_*** commands and the MIH_Get_Information -## Note: If no query is specified, the MIHF will assume that the MIH-User does -## not support the MIH_Get_Information command. -## -users = user_enb 1635 - -## -## Comma separated list of local MIH Link SAPs id's and ports. -## -## Usage: links = [ ], ... -## -#links = enb_lte_link00 1234 LTE 00:39:18:36:62:00 00:11:33 5, enb_eth_link00 1234 802_3 e0:db:55:eb:33:ac -links = enb_lte_link00 1234 LTE 00:39:18:36:62:00 00:11:33 5 - -## -## Comma separated list of the MIHF's transport protocol -## -transport = udp diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/Jamfile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/Jamfile deleted file mode 100644 index 4f1c6cb43f..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/Jamfile +++ /dev/null @@ -1,31 +0,0 @@ -#=============================================================================== -# Brief : MIH-User SAP Application Sample Project Build -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -project enb2_lte_user - ; - -exe enb2_lte_user - : enb2_lte_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - -install install - : enb2_lte_user - : ../../dist - ; diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb2_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb2_lte_user.cpp deleted file mode 100644 index 319d68e2e3..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb2_lte_user.cpp +++ /dev/null @@ -1,1824 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -//The thresholds for the Energy Detection Sensing algorithm respectively for 10 and 100 samples -#define ED_THRESHOLD_10 23695432 -#define ED_THRESHOLD_100 230445932 -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Initiallization of the MIH-USER and the MIHF -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | - -// ------------------------------------------------------------------------------------------------------------------------ -// Locally send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to local MIHF) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | - -// ------------------------------------------------------------------------------------------------------------------------ -// Remotely send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to remote MIHF of the UE) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Detect the connection of the UE to the eNB + Start the measurement report process -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Activate the TVWS link (After running the cognitive algorithms) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -// | | | -// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -// | | | - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static const char* const kConf_MIH_Commands = "user.commands"; - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string exec(char* cmd) { - FILE* pipe = popen(cmd, "r"); - if (!pipe) return "ERROR"; - char buffer[128]; - std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - pclose(pipe); - return result; -} - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} - - -/*//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} -*/ - -//Updated from UE code -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - - //Measurements report methods - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - int receive_Sensing_Report(); - void receive_CRRM_Data(); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - void forward_Parameters_Report_indication(odtone::mih::message& m); - - void receive_MIH_MN_HO_Candidate_Query_request(odtone::mih::message& msg); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - odtone::uint second_link_activated; - odtone::uint count; - odtone::uint sensing_done; - odtone::uint sensing_score; - - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - second_link_activated = 0; - count = 0; - sensing_done = 0; - sensing_score = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - - //send a capability discover request to the remote UE - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - - - case odtone::mih::indication::mn_ho_candidate_query: - log_(0, "MIH-User has received a request \"mn_ho_candidate_query\""); - mih_user::receive_MIH_MN_HO_Candidate_Query_request(msg); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - boost::system::error_code ec; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} -// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address -// for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -// { -// rcv_link_id.addr = i->addr; -// rcv_link_id.type = boost::get(i->nettype.link); -// } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - - std::cout<<"NTALL "<begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; -// std::ostringstream stream; -// std::stringstream st; -// odtone::mih::net_type_addr net_type_addr; -// net_type_addr = boost::get(*i); -// stream << net_type_addr; -// std::string s; -// std::stringstream st (stream.str()); -// while (getline (st, s, '\n')) -// { -// std::stringstream ss(s); -// getline (ss, name, ':'); -// getline (ss, value, '\n'); -// // ss>>name>>value; -// std::cout<<" name "<addr; - getline (st, s, ' '); - std::cout<<"LINK_TUPLE_ID s "<(i->addr); -// li.type = boost::get(i->nettype.link); -// if (std::find(_link_id_list.begin(), _link_id_list.end(), li)==_link_id_list.end()) -// _link_id_list.push_back(li); // save the link identifier of the network interface - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - - std::cout<<"LINK_TUPLE_ID - Link identifier:after "<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// std::cout<<"_link_id_list addr "<addr<<" TYPE "<type<addr<<" TYPE "<type<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - -// link_act_req.action.param.param = res; - -// link_act_req.ex_time = 0; - link_act_req.ex_time = 5000; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - -// odtone::mih::id mid_ue; -// mid_ue.assign("mihf2_ue"); - m.destination(/*mid_ue*/_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st); -// & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -// if (larl) { -// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -// { -// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -// } -// } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -// #ifdef SCENARIO_1 -// if (larl) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// if (rsp->result.get() == odtone::mih::link_ac_success) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// _current_link_action_request += 1; -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_1 -// -// #ifdef SCENARIO_2 -// // 2nd scenario: Activate all resources, then deactivate all resources -// if (larl.get().size() > 0) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (++_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// _current_link_action_request = 0; -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); - // ferreira: Added sleep time + exit + output to make visible the end of SPECTRA demo - if( second_link_activated == 1 ) - { - unsigned int pause_time = 30; // in seconds to show the result of the demo then proceed - log_(0, "\n\n\n\n\t----- Confirmed Configuration of LTE Link for TVWS -----\n"); - log_(0, "\n\t----- END OF SPECTRA DEMO ! -----\n"); -// log_(0, "\n\n MIH User regular function will resume in (secs) : ", pause_time ); -// usleep(pause_time * 1000000); - exit(1); - } -} - -// void mih_user::cognitive_decision() -// { -// -// //Sensing measurements report -// std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); -// } - - -void mih_user::receive_CRRM_Data() -{ - - //CRRM data report - std::string result = exec ("./CRMClientmain 0 1"); -} - - -//----------------------------------------------------------------------------- -int mih_user::receive_Sensing_Report() -//----------------------------------------------------------------------------- -{ - std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); - std::string tmp; - int value; - std::stringstream ss(result); - ss >> tmp >> value; - sensing_done = 1; -// std::cout<<"Result "<> odtone::mih::request() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - -// log_(0, "MIH_MN_HO_Candidate_Query.request - RECEIVED - Begin"); -// log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); -// log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -// -// for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) -// { -// log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); -// if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) -// { -// log_(0, "Meausrement Value: ", (short) *value ); -// } -// } - - - // ferreira: changed output of message for better readability! - log_(0, "\n["+getTimeStamp4Log()+"] [RX] [FROM: "+ msg.source().to_string() +"] [Link ID: "+ link_id2string(link).c_str() +"]"); - log_(0, "\t[MIH_MN_HO_Candidate_Query [MIH_Link_Parameters_Report]]"); - - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "\t[Measurement Types: RSRP 0|RSRQ 1|CQI 2] [type: ", i->param.type, "| value: ", (short) *value, "]" ); - } - } - - -//eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm - - //First Phase: Collect the data as input fot the cognitive algorithm - //Sensing data - if (sensing_done == 0) - sensing_score = receive_Sensing_Report(); - - //CRRM Data - // receive_CRRM_Data(); - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (odtone::mih::threshold *th = boost::get(&i->thold)) { -// log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// if(*i==link) - odtone::mih::l2_3gpp_addr add; - odtone::mih::link_type type; - type = odtone::mih::link_type_lte; -// add.value = "l2_3gpp_addr"; -// link1.addr = add; -// link1.type = type; -// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); - -// ferreira: commented out the count printouts and changed the comparison value (originally count >= 30 ) - //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 -// log_(0, "COUNT: ", count ); - if (second_link_activated==0) - { -// log_(0, "COUNT: ", count ); - if (count >= 1500) - { -// log_(0, "COUNT: ", count ); - send_MIH_Link_Action_Power_Up_request(_link_id_list[0]);//Link LTE - second_link_activated = 1; - } - } - - count++; -// continue; -// send_MIH_Link_Action_Power_Up_request(link); -// if (link_id2string(link).c_str() == "LTE") -// } - } - } - -} - - - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link, link1; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - -// log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); -// log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); -// log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); -// std::cout<<"LINK_TUPLE_ID - Link identifier: "< RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); -// if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) -// { -// log_(0, "Meausrement Value: ", (short) *value ); -// } -// } -// log_(0, "MIH_Link_Parameters_Report.indication - End"); - - // ferreira: changed output of message for better readability! - log_(0, "\n["+getTimeStamp4Log()+"] [RX] [FROM: "+ msg.source().to_string() +"] [Link ID: "+ link_id2string(link).c_str() +"]"); - log_(0, "\t[MIH_Link_Parameters_Report]"); - - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "\t[Measurement Types: RSRP 0|RSRQ 1|CQI 2] [type: ", i->param.type, "| value: ", (short) *value, "]" ); - } - } -// log_(0, "MIH_Link_Parameters_Report.indication - End"); - - - //eNB1: Forward the message to UE 2 - // forward_Parameters_Report_indication(msg); - - //eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm - - //First Phase: Collect the data as input fot the cognitive algorithm - //Sensing data -// int score; -// score = receive_Sensing_Report(); -// - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (odtone::mih::threshold *th = boost::get(&i->thold)) { -// log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); -// //link_action if free channel is available -// // for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// // if(*i==link) -// odtone::mih::l2_3gpp_addr add; -// odtone::mih::link_type type; -// type = odtone::mih::link_type_lte; -// // add.value = "l2_3gpp_addr"; -// link1.addr = add; -// link1.type = type; -// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); - - //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 - if (second_link_activated==0) - { - send_MIH_Link_Action_Power_Up_request(_link_id_list[0]); - second_link_activated = 1; - } -// continue; - // send_MIH_Link_Action_Power_Up_request(link); -// if (link_id2string(link).c_str() == "LTE") -// } - } - } - -} - - -//Forward the MIH_Link_Parameters_Report to the UE of the CPE -//----------------------------------------------------------------------------- -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - msg.destination(mid_ue); - - //mn_ho_candidate_query is used to constuct/send the message containing parameters reports - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); - - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - odtone::mih::threshold th2; - std::vector thl1; - std::vector thl2; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lcp1.type = lp1; - lcp2.type = lp2; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th2.threshold_val = -19; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - - - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue");//mihf2_ue - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ " --->][ ADDR LINK " - + m.destination().to_string() +"]\n"); - std::cout<<"LINK TUPLE ID "< lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti); -// & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter()->default_value("enb_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf4_enb"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.conf deleted file mode 100644 index b9bbf279de..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.conf +++ /dev/null @@ -1,40 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_enb - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp deleted file mode 100644 index b0fb81c99d..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp +++ /dev/null @@ -1,1681 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -//The thresholds for the Energy Detection Sensing algorithm respectively for 10 and 100 samples -#define ED_THRESHOLD_10 23695432 -#define ED_THRESHOLD_100 230445932 -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Initiallization of the MIH-USER and the MIHF -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | - -// ------------------------------------------------------------------------------------------------------------------------ -// Locally send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to local MIHF) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | - -// ------------------------------------------------------------------------------------------------------------------------ -// Remotely send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to remote MIHF of the UE) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Detect the connection of the UE to the eNB + Start the measurement report process -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Activate the TVWS link (After running the cognitive algorithms) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -// | | | -// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -// | | | - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static const char* const kConf_MIH_Commands = "user.commands"; - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string exec(char* cmd) { - FILE* pipe = popen(cmd, "r"); - if (!pipe) return "ERROR"; - char buffer[128]; - std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - pclose(pipe); - return result; -} - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} - - -/*//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} -*/ - -//Updated from UE code -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - - //Measurements report methods - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - int receive_Sensing_Report(); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - void forward_Parameters_Report_indication(odtone::mih::message& m); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - odtone::uint second_link_activated; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - second_link_activated = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - - //send a capability discover request to the remote UE - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - boost::system::error_code ec; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} -// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address -// for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -// { -// rcv_link_id.addr = i->addr; -// rcv_link_id.type = boost::get(i->nettype.link); -// } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - - std::cout<<"NTALL "<begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; -// std::ostringstream stream; -// std::stringstream st; -// odtone::mih::net_type_addr net_type_addr; -// net_type_addr = boost::get(*i); -// stream << net_type_addr; -// std::string s; -// std::stringstream st (stream.str()); -// while (getline (st, s, '\n')) -// { -// std::stringstream ss(s); -// getline (ss, name, ':'); -// getline (ss, value, '\n'); -// // ss>>name>>value; -// std::cout<<" name "<addr; - getline (st, s, ' '); - std::cout<<"LINK_TUPLE_ID s "<(i->addr); - li.type = boost::get(i->nettype.link); - if (std::find(_link_id_list.begin(), _link_id_list.end(), li)==_link_id_list.end()) - _link_id_list.push_back(li); // save the link identifier of the network interface - - std::cout<<"LINK_TUPLE_ID - Link identifier:after "<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// std::cout<<"_link_id_list addr "<addr<<" TYPE "<type<addr<<" TYPE "<type<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - -// link_act_req.action.param.param = res; - -// link_act_req.ex_time = 0; - link_act_req.ex_time = 5000; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - -// odtone::mih::id mid_ue; -// mid_ue.assign("mihf2_ue"); - m.destination(/*mid_ue*/_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st); -// & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -// if (larl) { -// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -// { -// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -// } -// } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -// #ifdef SCENARIO_1 -// if (larl) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// if (rsp->result.get() == odtone::mih::link_ac_success) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// _current_link_action_request += 1; -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_1 -// -// #ifdef SCENARIO_2 -// // 2nd scenario: Activate all resources, then deactivate all resources -// if (larl.get().size() > 0) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (++_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// _current_link_action_request = 0; -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -// void mih_user::cognitive_decision() -// { -// -// //Sensing measurements report -// std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); -// } - -//----------------------------------------------------------------------------- -int mih_user::receive_Sensing_Report() -//----------------------------------------------------------------------------- -{ - std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); - std::string tmp; - int value; - std::stringstream ss(result); - ss >> tmp >> value; -// std::cout<<"Result "<> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value ); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - - - //eNB1: Forward the message to UE 2 - // forward_Parameters_Report_indication(msg); - - //eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm - - //First Phase: Collect the data as input fot the cognitive algorithm - //Sensing data - int score; - score = receive_Sensing_Report(); - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (odtone::mih::threshold *th = boost::get(&i->thold)) { - log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// if(*i==link) - odtone::mih::l2_3gpp_addr add; - odtone::mih::link_type type; - type = odtone::mih::link_type_lte; -// add.value = "l2_3gpp_addr"; - link1.addr = add; - link1.type = type; -// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); - - //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 - if (second_link_activated==0) - { - send_MIH_Link_Action_Power_Up_request(_link_id_list[0]); - second_link_activated = 1; - } -// continue; -// send_MIH_Link_Action_Power_Up_request(link); -// if (link_id2string(link).c_str() == "LTE") -// } - } - } - -} - - -//Forward the MIH_Link_Parameters_Report to the UE of the CPE -//----------------------------------------------------------------------------- -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - msg.destination(mid_ue); - - //mn_ho_candidate_query is used to constuct/send the message containing parameters reports - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); - - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - odtone::mih::threshold th2; - std::vector thl1; - std::vector thl2; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lcp1.type = lp1; - lcp2.type = lp2; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th2.threshold_val = -19; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - - - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ " --->][ ADDR LINK " - + m.destination().to_string() +"]\n"); - std::cout<<"LINK TUPLE ID "< lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti); -// & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter()->default_value("enb_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1_enb"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp.old b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp.old deleted file mode 100644 index b32628931c..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user.cpp.old +++ /dev/null @@ -1,1346 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -// +--------+ +-----+ -// |MIH_USER| |MIH-F| -// +---+----+ +--+--+ -// | | _current_link_action_request = 0 -// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -// | | -// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -// |<--------- Capability_Discover.confirm --------------| (success) -// | | -// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 1: Sequentially activate and deactivate each resource -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// |<--------- Link_Actions.confirm ---------------------| (success) -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 2: Activate all resources, then deactivate all resources -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | _current_link_action_request = 0 -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// | | -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s; - if(evtP.get(odtone::mih::mih_evt_link_detected)) s = std::string("DETECTED "); - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s; - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s = std::string("Link_Get_Parameters "); - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES) -//----------------------------------------------------------------------------- -{ - - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - } - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - - break; - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - odtone::mih::threshold th; - std::vector thl; - - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - lp = odtone::mih::link_param_lte_bandwidth; - - lcp.type = lp; - - if ( link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th.threshold_val = 0; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("mih_usr.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1234), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user2.cpp.old b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user2.cpp.old deleted file mode 100644 index 1f64a5d556..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user2.cpp.old +++ /dev/null @@ -1,1565 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Initiallization of the MIH-USER and the MIHF -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | - -// ------------------------------------------------------------------------------------------------------------------------ -// Locally send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to local MIHF) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | - -// ------------------------------------------------------------------------------------------------------------------------ -// Remotely send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to remote MIHF of the UE) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Detect the connection of the UE to the eNB + Start the measurement report process -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Activate the TVWS link (After running the cognitive algorithms) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -// | | | -// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -// | | | - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} - - -/*//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} -*/ - -//Updated from UE code -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - void do_nothing(); - void forward_Parameters_Report_indication(odtone::mih::message& m); - void receive_MIH_MN_HO_Candidate_Query_request(odtone::mih::message& msg); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - - //send a capability discover request to the remote UE - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - //mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - //_num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::mn_ho_candidate_query: - log_(0, "MIH-User has received a request \"mn_ho_candidate_query\""); - mih_user::receive_MIH_MN_HO_Candidate_Query_request(msg); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - boost::system::error_code ec; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} -// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get(), msg.source()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(dest); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -void mih_user::receive_MIH_MN_HO_Candidate_Query_request(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::request() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_MN_HO_Candidate_Query.request - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - - - //Test 1: Forward the message to UE - // forward_Parameters_Report_indication(msg); - -} - -//----------------------------------------------------------------------------- -void mih_user::do_nothing() -//----------------------------------------------------------------------------- -{ - -} - -//----------------------------------------------------------------------------- -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - msg.destination(mid_ue); - - - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); - - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - odtone::mih::threshold th2; - std::vector thl1; - std::vector thl2; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lcp1.type = lp1; - lcp2.type = lp2; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th2.threshold_val = -19; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - - - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); -// m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+m.destination().to_string() +"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp1 == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp1.timer_interval); - - if(lcp1.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp1.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp1.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", (short) th1.threshold_val); - - if(th1.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th1.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - odtone::uint iter; - odtone::mih::status st; - - //boost::optional lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti); -// & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter()->default_value("enb2_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf4_enb"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user_tcs.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user_tcs.cpp deleted file mode 100644 index 72d46e791b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/enb_lte_user_tcs.cpp +++ /dev/null @@ -1,1412 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -// Fatma HRIZI EURECOM fr> -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -//This file is the implementation of the MIH user in the eNB - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -// +--------+ +-----+ -// |MIH_USER| |MIH-F| -// +---+----+ +--+--+ -// | | _current_link_action_request = 0 -// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -// | | -// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -// |<--------- Capability_Discover.confirm --------------| (success) -// | | -// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 1: Sequentially activate and deactivate each resource -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// |<--------- Link_Actions.confirm ---------------------| (success) -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 2: Activate all resources, then deactivate all resources -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | _current_link_action_request = 0 -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// | | -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s; - if(evtP.get(odtone::mih::mih_evt_link_detected)) s = std::string("DETECTED "); - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s; - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s = std::string("Link_Get_Parameters "); - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(const odtone::mih::config& cfg); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES) -//----------------------------------------------------------------------------- -{ - - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - log_(0, ""); - - // - // Local Capability Discover Request - // - odtone::mih::message msg; - _mihfid.assign("mihf2"); - msg << odtone::mih::request(odtone::mih::request::capability_discover, _mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Capability_Discover.request --->]["+msg.destination().to_string()+"]\n"); - _mihf.async_send(msg, boost::bind(&mih_user::receive_MIH_Capability_Discover_confirm, this, _1)); - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)"); - log_(0, ""); - - //****eNB***** - // Remote Capability Discover Request - // - mih_user::send_MIH_Capability_Discover_request(cfg); - - //Trigger Link_Configure_Thresholds Request - // odtone::mih::message m; - //m.destination(msg.source()); - //mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - //****eNB***** -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - } - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - - break; - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} -/* -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - log_(0, "MIH_Link_Detected.indication - End\n"); -} -*/ -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - -boost::system::error_code ec; - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - log_(0, " - LINK_ID - Link identifier: ", link_id2string(i->id).c_str()); - log_(0, " - Network ID: ", i->network_id); - log_(0, " - SINR: ", i->sinr); - log_(0, " - Data_rate: ", i->data_rate); - } - - send_MIH_Link_Configure_Thresholds_request(msg, ec); - - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (const odtone::mih::threshold *th = boost::get(&i->thold)) { - - log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available - } - else{ - log_(0, " -Regular Report for BW Threshold "); - //update MEAS - } - } - - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - //boost::optional ntal; - //boost::optional evt; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::request(odtone::mih::request::capability_discover) - //& odtone::mih::tlv_net_type_addr_list(ntal) - //& odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - _mihfid.assign("mihf2"); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - odtone::mih::threshold th; - std::vector thl; - - odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - - - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - - odtone::mih::link_det_info_list ldil; - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - - - lti.type = i->id.type; - lti.addr = i->id.addr; - lp = odtone::mih::link_param_lte_bandwidth; - lcp.type = lp; - if ( link_measures_request ==0){ - lcp.timer_interval = 10; - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } - else{ - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - th.threshold_val = 5; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - } - -/* - if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -*/ -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1234), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.conf deleted file mode 100644 index 27d56760be..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.cpp deleted file mode 100644 index 582573a666..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/mih_user/lte_test_user/ue_lte_user.cpp +++ /dev/null @@ -1,1658 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_req -//#define SCENARIO_1 // Sequentially activate and deactivate each resou -//#define SCENARIO_2 // Activate all resources, then deactivate all resour -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -// int& operator [](const link_param_lte_enum value) -// { -// static std::map var; -// if (var.size() == 0) -// { -// var[link_param_lte_rsrp]="link_param_lte_rsrp"; -// var[link_param_lte_rsrq]="link_param_lte_rsrq"; -// var[link_param_lte_cqi]="link_param_lte_cqi"; -// var[link_param_lte_bandwidth]="link_param_lte_bandwidth"; -// var[link_param_lte_pkt_delay]="link_param_lte_pkt_delay"; -// } -// return var[value]; -// } - -const char * MeasurementTypes[]= -{ - "LTE_RSRP", /**< RSRP. */ - "LTE_RSRQ", /**< RSRQ. */ - "link_param_lte_cqi", /**< Multicast packet loss rate.*/ - "link_param_lte_bandwidth", /**< System Load. */ - "link_param_lte_pkt_delay", /**< Number of registered users. */ - "link_param_lte_pkt_loss", /**< Number of active users. */ - "link_param_lte_l2_buffer", /**< Congestion windows of users. */ - "link_param_lte_MN_cap", /**< Congestion windows of users. */ - "link_param_lte_embms", /**< Congestion windows of users. */ - "link_param_lte_jumbo_feasibility", /**< Congestion windows of users. */ - "link_param_lte_jumbo_setup", /**< Congestion windows of users. */ - "link_param_lte_active_embms", /**< Transmission rate of users. */ - "link_param_lte_link_congestion", /**< Link congestion. */ -}; - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)){ - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type"; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - - - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - //send a capability discover request to the remote eNB - mih_user::send_MIH_Capability_Discover_request_remote(); - -} - - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1;; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - // send Link_Action / Power Up - lid.type = odtone::mih::link_type_lte; - lid.addr = ldi.id.addr; - //send_MIH_Link_Action_Power_Up_plus_scan_request(lid); - log_(0, "MIH_Link_Detected.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - - link_act_req.id = link; - link_act_req.action.type = odtone::mih::link_ac_type_power_up; - link_act_req.action.attr.clear(); - link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); - - link_act_req.ex_time = 5000; // in ms - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_enb; - mid_enb.assign("mihf1_enb"); - m.destination(mid_enb); -// m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get(), msg.source()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(dest); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); - mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); - -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl){ - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - -// odtone::mih::link_param_report lpr = lprl.back(); -// -// log_(0, "Meausrement Type: ", lpr.param.type); -// if(odtone::mih::link_param_val *value = boost::get(&lpr.param.value)){ -// log_(0, "Meausrement Value: ", *value); -// -// }; -// const odtone::mih::threshold *th; - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { -// odtone::mih::link_param_lte * index = boost::get(&i->param.type); -// int val = (short)*index; -// log_(0, "Meausrement Type: index ", *index); - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); -// log_(0, "Meausrement Type: ", MeasurementTypes[index]); -// log_(0, "Meausrement Type: ", &i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } -// if (th = boost::get (&i->thold)) -// { -// log_(0, "Threshold crossed ", boost::get (i->param.value)); -// } -// else -// { -// log_(0,"Regular Report"); -// } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - std::vector thl1; - odtone::mih::threshold th2; - std::vector thl2; - odtone::mih::threshold th3; - std::vector thl3; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_cfg_param lcp3; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - odtone::mih::link_param_lte lp3; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lp3 = odtone::mih::link_param_lte_cqi; - lcp1.type = lp1; - lcp2.type = lp2; - lcp3.type = lp3; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - lcp3.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - lcp3.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp3.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - lcp3.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_val = -19; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - th3.threshold_val = 0; - th3.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - thl3.push_back(th3); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - lcp3.threshold_list = thl3; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - lcpl.push_back(lcp3); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp1 == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - if(lp2 == odtone::mih::link_param_lte_rsrq) {log_(0, "\t LTE link parameter LTE RSRQ");} - log_(0, "\t- TIMER INTERVAL - Value: ", lcp1.timer_interval); - - if(lcp1.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp1.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp1.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", (short) th1.threshold_val); - - if(th1.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th1.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -// //----------------------------------------------------------------------------- -// void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -// //----------------------------------------------------------------------------- -// { -// odtone::mih::message m; -// odtone::mih::threshold th; -// std::vector thl; -// odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -// //List of the link threshold parameters -// odtone::mih::link_cfg_param_list lcpl; -// odtone::mih::link_cfg_param lcp; -// odtone::mih::link_param_lte lp; -// //odtone::mih::link_param_gen lp; -// -// odtone::mih::link_param_type typr; -// -// log_(0,""); -// log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -// -// //link_tuple_id -// lti.type = rcv_link_id.type; -// lti.addr = rcv_link_id.addr; -// -// //local_l2_3gpp_addr = boost::get(lti.addr); -// -// -// //link_param_gen_data_rate = 0, /**< Data rate. */ -// //link_param_gen_signal_strength = 1, /**< Signal strength. */ -// //link_param_gen_sinr = 2, /**< SINR. */ -// //link_param_gen_throughput = 3, /**< Throughput. */ -// //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -// //lp = odtone::mih::link_param_lte_bandwidth; -// lp = odtone::mih::link_param_lte_rsrp; -// lcp.type = lp; -// -// link_measures_request = 0; -// if ( link_measures_request ==0){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 3000; -// //th_action_normal = 0, /**< Set normal threshold. */ -// //th_action_one_shot = 1, /**< Set one-shot threshold. */ -// //th_action_cancel = 2 /**< Cancel threshold. */ -// lcp.action = odtone::mih::th_action_normal; -// link_measures_request = 1; -// } else if ( link_measures_request==1){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 0; -// lcp.action = odtone::mih::th_action_cancel; -// link_measures_request = 0; -// } -// -// //above_threshold = 0, /**< Above threshold. */ -// //below_threshold = 1, /**< Below threshold. */ -// th.threshold_val = -105; -// th.threshold_x_dir = odtone::mih::threshold::above_threshold; -// -// thl.push_back(th); -// lcp.threshold_list = thl; -// lcpl.push_back(lcp); -// -// m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -// & odtone::mih::tlv_link_identifier(lti) -// & odtone::mih::tlv_link_cfg_param_list(lcpl); -// -// m.destination(msg.source()); -// -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -// // link_tupple_id2string(lti).c_str() + -// link_id2string(lti).c_str()+ -// " --->]["+_mihfid.to_string()+"]\n"); -// -// _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); -// -// log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); -// -// log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); -// -// //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} -// //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} -// //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} -// //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} -// //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} -// if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} -// -// log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); -// -// if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} -// if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} -// if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} -// -// log_(0, "\t Threshold value: ", th.threshold_val); -// -// if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} -// if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} -// -// log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -// } - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - odtone::uint iter; - odtone::mih::status st; - - //boost::optional lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter lcsl; -// // Todtone::mih::link_cfg_status_list lcsl; -// // Todtone::mih::link_cfg_status lcp; -// //odtone::mih::link_param_gen lp; -// -// // T odtone::mih::link_tuple_id lti; -// -// //msg >> odtone::mih::confirm() -// // & odtone::mih::tlv_status(st) -// // & odtone::mih::tlv_link_identifier(lti) -// // & odtone::mih::tlv_link_cfg_status_list(lcsl); -// -// -// log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); -// log_(0,""); -// } - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("ue_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf2_ue"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/enb.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/enb.conf deleted file mode 100644 index 8acd6d84af..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/enb.conf +++ /dev/null @@ -1,217 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - # real_time choice in {hard, rt-preempt, no} - real_time = "no"; - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "92"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - # srs_BandwidthConfig =; - # srs_SubframeConfig =; - # srs_ackNackST =; - # srs_MaxUpPts =; - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; - -# rach_sizeOfRA_PreamblesGroupA = ; -# rach_messageSizeGroupA = ; -# rach_messagePowerOffsetGroupB = ; - - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - }, - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; -/* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; -*/ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.13.11"; - ipv6 = "192:168:30::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.13.10/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.13.10/24"; - }; - - log_config : - { - global_log_level ="debug"; - global_log_verbosity ="medium"; - hw_log_level ="debug"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="debug"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - - } -); diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/start_enb.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/start_enb.bash deleted file mode 100644 index c877b9b843..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/enb2/oai_conf/start_enb.bash +++ /dev/null @@ -1,211 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_enb.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# ENB CONFIG FILE -#------------------------------------------------ -#declare -x ENB_CONFIG_FILE="CONF/enb.sfr.yang.conf" -declare -x ENB_CONFIG_FILE="enb.conf" - -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth0" -declare -x EMULATION_DEV_ADDRESS="192.168.15.6" -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x ENB_IPv4="10.0.2.4" -declare -x ENB_IPv6="2001:2::4" -declare -x ENB_IPv6_CIDR=$ENB_IPv6"/64" -declare -x ENB_IPv4_CIDR=$ENB_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 6 2 0 0 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x ENB_RAL_IP_ADDRESS="127.0.0.1" -declare -x ENB_MIHF_IP_ADDRESS=127.0.0.1 -MIH_LOG_FILE="mih-f_enb.log" - -#------------------------------------------------ -LOG_FILE="/tmp/oai_sim_enb.log" - -# EXE options -EXE_MODE="DEBUG" # PROD or DEBUG - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "service network-manager stop" -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - -bash_exec "/sbin/iptables -t mangle -F" -bash_exec "/sbin/iptables -t nat -F" -bash_exec "/sbin/iptables -t raw -F" -bash_exec "/sbin/iptables -t filter -F" -bash_exec "/sbin/ip6tables -t mangle -F" -bash_exec "/sbin/ip6tables -t filter -F" -bash_exec "/sbin/ip6tables -t raw -F" - -################################################## -# LAUNCH eNB executable -################################################## - -echo "Bringup eNB interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $ENB_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -bash_exec "ip link set $LTEIF up" -sleep 1 -bash_exec "ip addr add dev $LTEIF $ENB_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $ENB_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" -bash_exec "sysctl -w net.ipv4.ip_forward=1" -assert " `sysctl -n net.ipv4.ip_forward` -eq 1" $LINENO - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ebtables -t nat -A POSTROUTING -p arp -j mark --mark-set 3 - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - - -# start MIH-F -xterm -hold -title "[eNB][eNB2] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -ENB_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LINK_ID=`trim2 $ENB_RAL_LINK_ID` -ENB_RAL_LINK_ID=`echo $ENB_RAL_LINK_ID | cut -d" " -f1` - -ENB_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LISTENING_PORT=`trim2 $ENB_RAL_LISTENING_PORT` -ENB_RAL_LISTENING_PORT=`echo $ENB_RAL_LISTENING_PORT | cut -d" " -f2` - -ENB_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -ENB_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` -#remove 2 last digits (vitualization, index on 2 digits) -ENB_RAL_LINK_ID_STRIPPED=${ENB_RAL_LINK_ID%%??} - -if [ $EXE_MODE = "DEBUG" ] ; then -#xterm -hold -e gdb --args -$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l9 -u0 -b1 -M0 -p2 -g3 -D $EMULATION_DEV_INTERFACE \ - --enb-ral-listening-port $ENB_RAL_LISTENING_PORT \ - --enb-ral-link-id $ENB_RAL_LINK_ID_STRIPPED \ - --enb-ral-ip-address $ENB_RAL_IP_ADDRESS \ - --enb-mihf-remote-port $ENB_MIHF_REMOTE_PORT \ - --enb-mihf-ip-address $ENB_MIHF_IP_ADDRESS \ - --enb-mihf-id $ENB_MIHF_ID \ - -O $ENB_CONFIG_FILE > log_enb.txt 2> /dev/null & -# -O $ENB_CONFIG_FILE | grep "RAL\|PDCP" & -else -#xterm -hold -e gdb --args -$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l3 -u0 -b1 -M0 -p2 -g3 -D $EMULATION_DEV_INTERFACE \ - --enb-ral-listening-port $ENB_RAL_LISTENING_PORT \ - --enb-ral-link-id $ENB_RAL_LINK_ID_STRIPPED \ - --enb-ral-ip-address $ENB_RAL_IP_ADDRESS \ - --enb-mihf-remote-port $ENB_MIHF_REMOTE_PORT \ - --enb-mihf-ip-address $ENB_MIHF_IP_ADDRESS \ - --enb-mihf-id $ENB_MIHF_ID \ - -O $ENB_CONFIG_FILE > /dev/null & -# -O $ENB_CONFIG_FILE | grep "RAL\|PDCP" & -fi - -wait_process_started oaisim - -# start MIH-USER -# wait for emulation start -tshark -c 150 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -xterm -hold -title "[eNB][eNB2] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER_CONF_FILE & -wait_process_started $ENB_MIH_USER - -xterm -hold -title "[eNB][eNB2] TVWS Sensing" -e ./server & -#xterm -hold -title "[eNB][eNB2] output" -e tail -f log_enb.txt | grep -i recon & - -sleep 100000 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/link_sap.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/link_sap.conf deleted file mode 100644 index c5b63413d0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/link_sap.conf +++ /dev/null @@ -1,47 +0,0 @@ -#=============================================================================== -# Brief : Link SAP configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[link] -## -## Link SAP identifier -## -id=link1 - -## -## Link SAP listening -## -port = 1235 - -## -## Link SAP interface technology -## -tec = 802_11 - -## -## Link SAP interface address -## -link_addr = 00:11:22:33:44:55 - -## -## Comma separated list of the Link SAP supported events -## -event_list = link_detected, link_up, link_down, link_parameters_report, link_going_down, link_handover_imminent, link_handover_complete - -[mihf] -ip=127.0.0.1 -local_port=1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/odtone_ue.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/odtone_ue.conf deleted file mode 100644 index 44545e6206..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/odtone_ue.conf +++ /dev/null @@ -1,73 +0,0 @@ -#=============================================================================== -# Brief : MIHF configuration file -# Authors : Carlos Guimaraes -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[mihf] -## -## This mihf's id -## -## Usage: id = -## -id = mihf2_ue - -## -## Port on localhost that MIH Users and MIH Link SAPs connect to. -## -## Usage: local_port = -## -local_port = 1025 - -## -## Port to which remote peer MIHF connect to -## -## Usage: remote_port = -## -remote_port = 4551 - -## -## Comma seperated list of remote MIHF's -## -## If you want to test remote MIHF communication add an entry here -## with the IP address of the remote MIHF. -## -## Usage: peers = , ... -## -peers = mihf1_enb 10.0.0.1 4551 - -## -## Comma separated list of local MIH User SAPs id's and ports -## -## Usage: users = [ ], ... -## Note: If no command is specified, the MIHF will assume that the MIH-User -## supports all MIH_***_HO_*** commands and the MIH_Get_Information -## Note: If no query is specified, the MIHF will assume that the MIH-User does -## not support the MIH_Get_Information command. -## -#users = user 1235 -users = user_ue 1635 - -## -## Comma separated list of local MIH Link SAPs id's and ports. -## -## Usage: links = [ ], ... -## -## -links = ue_lte_link00 1234 LTE 00:39:18:36:73:02 00:11:22 5 - -## -## Comma separated list of the MIHF's transport protocol -## -transport = udp diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/ue_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/ue_lte_user.conf deleted file mode 100644 index 27d56760be..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_conf/ue_lte_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/.ue_lte_user_old.cpp.kate-swp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/.ue_lte_user_old.cpp.kate-swp deleted file mode 100644 index 667b216e6e..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/.ue_lte_user_old.cpp.kate-swp and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/Jamfile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/Jamfile deleted file mode 100644 index c2a6aecbc4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/Jamfile +++ /dev/null @@ -1,44 +0,0 @@ -#=============================================================================== -# Brief : MIH-User SAP Application Sample Project Build -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -project enb_lte_user - ; - -exe enb_lte_user - : enb_lte_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - -install install - : enb_lte_user - enb_lte_user.conf - ue_lte_user - ue_lte_user.conf - : ../../dist - ; - -project ue_lte_user - ; - -exe ue_lte_user - : ue_lte_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/dummy_130606.tgz b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/dummy_130606.tgz deleted file mode 100644 index 11ef083a92..0000000000 Binary files a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/dummy_130606.tgz and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.conf deleted file mode 100644 index b9bbf279de..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.conf +++ /dev/null @@ -1,40 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_enb - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.cpp deleted file mode 100644 index 4571396bd4..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user.cpp +++ /dev/null @@ -1,1695 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -//The thresholds for the Energy Detection Sensing algorithm respectively for 10 and 100 samples -#define ED_THRESHOLD_10 23695432 -#define ED_THRESHOLD_100 230445932 -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER (of the eNB) for the demo of the Scenario 2 of SPECTRA project is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Initiallization of the MIH-USER and the MIHF -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | - -// ------------------------------------------------------------------------------------------------------------------------ -// Locally send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to local MIHF) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | - -// ------------------------------------------------------------------------------------------------------------------------ -// Remotely send the Capability Discover and the Event Subscribe primitives -// (from MIH USER to remote MIHF of the UE) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Detect the connection of the UE to the eNB + Start the measurement report process -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... | | -// | | | -// ------------------------------------------------------------------------------------------------------------------------ -// Activate the TVWS link (After running the cognitive algorithms) -// ------------------------------------------------------------------------------------------------------------------------ -// | | | -// |-------------- MIH_Link_Actions.request ------------>|--------------- MIH_Link_Actions.request ----------->| -// | | | -// |<------------- MIH_Link_Actions.confirm -------------|<-------------- MIH_Link_Actions.confirm ------------| -// | | | - -//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -static const char* const kConf_MIH_Commands = "user.commands"; - -///////////////////////////////////////////////////////////////////////////////////////// - -std::string exec(char* cmd) { - FILE* pipe = popen(cmd, "r"); - if (!pipe) return "ERROR"; - char buffer[128]; - std::string result = ""; - while(!feof(pipe)) { - if(fgets(buffer, 128, pipe) != NULL) - result += buffer; - } - pclose(pipe); - return result; -} - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} - - -/*//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} -*/ - -//Updated from UE code -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - - //Measurements report methods - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - int receive_Sensing_Report(); - void receive_CRRM_Data(); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - void forward_Parameters_Report_indication(odtone::mih::message& m); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - odtone::uint second_link_activated; - odtone::uint count; - odtone::uint sensing_done; - odtone::uint sensing_score; - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - second_link_activated = 0; - count = 0; - sensing_done = 0; - sensing_score = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(/*const odtone::mih::config& cfg,*/ const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - - //send a capability discover request to the remote UE - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - boost::system::error_code ec; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} -// mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, /*boost::cref(cfg),*/ _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address -// for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) -// { -// rcv_link_id.addr = i->addr; -// rcv_link_id.type = boost::get(i->nettype.link); -// } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - - std::cout<<"NTALL "<begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; -// std::ostringstream stream; -// std::stringstream st; -// odtone::mih::net_type_addr net_type_addr; -// net_type_addr = boost::get(*i); -// stream << net_type_addr; -// std::string s; -// std::stringstream st (stream.str()); -// while (getline (st, s, '\n')) -// { -// std::stringstream ss(s); -// getline (ss, name, ':'); -// getline (ss, value, '\n'); -// // ss>>name>>value; -// std::cout<<" name "<addr; - getline (st, s, ' '); - std::cout<<"LINK_TUPLE_ID s "<(*/i->addr/*)*/; - li.type = boost::get(i->nettype.link); - if (std::find(_link_id_list.begin(), _link_id_list.end(), li)==_link_id_list.end()) - _link_id_list.push_back(li); // save the link identifier of the network interface - - std::cout<<"LINK_TUPLE_ID - Link identifier:after "<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// std::cout<<"_link_id_list addr "<addr<<" TYPE "<type<addr<<" TYPE "<type<]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - -// link_act_req.action.param.param = res; - -// link_act_req.ex_time = 0; - link_act_req.ex_time = 5000; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - -// odtone::mih::id mid_ue; -// mid_ue.assign("mihf2_ue"); - m.destination(/*mid_ue*/_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st); -// & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -// if (larl) { -// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -// { -// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -// } -// } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -// #ifdef SCENARIO_1 -// if (larl) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// if (rsp->result.get() == odtone::mih::link_ac_success) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// _current_link_action_request += 1; -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_1 -// -// #ifdef SCENARIO_2 -// // 2nd scenario: Activate all resources, then deactivate all resources -// if (larl.get().size() > 0) { -// odtone::mih::link_action_rsp *rsp = &larl->front(); -// if (++_current_link_action_request < _nb_of_link_action_requests) { -// if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// } -// else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { -// _current_link_action_request = 0; -// mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); -// } -// else { // Ends the scenario -// mih_user::send_MIH_Event_Unsubscribe_request(); -// } -// } -// #endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -void mih_user::receive_CRRM_Data() -{ - - //CRRM data report - std::string result = exec ("./CRMClientmain 0 1"); -} - -//----------------------------------------------------------------------------- -int mih_user::receive_Sensing_Report() -//----------------------------------------------------------------------------- -{ - std::string result = exec ("./client 127.0.0.1 4546 10 | grep \"SCORE\""); - std::string tmp; - int value; - std::stringstream ss(result); - ss >> tmp >> value; - std::cout<<"Result of Sensing "<> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - std::cout<<"LINK_TUPLE_ID - Link identifier: "< RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value ); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - - - //eNB1: Forward the message to UE 2 - forward_Parameters_Report_indication(msg); - - //eNB2 : Action Power Up the TVWS Link after running the cognitive algorithm - - //First Phase: Collect the data as input fot the cognitive algorithm - //Sensing data - if (sensing_done == 0) - sensing_score = receive_Sensing_Report(); - - //CRRM Data - receive_CRRM_Data(); - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (odtone::mih::threshold *th = boost::get(&i->thold)) { -// log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available -// for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { -// if(*i==link) - odtone::mih::l2_3gpp_addr add; - odtone::mih::link_type type; - type = odtone::mih::link_type_lte; -// add.value = "l2_3gpp_addr"; - link1.addr = add; - link1.type = type; -// send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_power_up); - - //Send ONLY ONCE RRC_Connection_Reconfiguration request to the UE on LTE link 0 - if (second_link_activated==0) - { - if (count == 20) - { - send_MIH_Link_Action_Power_Up_request(_link_id_list[1]);//Link LTE - second_link_activated = 1; - } - } - - count++; -// continue; -// send_MIH_Link_Action_Power_Up_request(link); -// if (link_id2string(link).c_str() == "LTE") -// } - } - } - -} - - -//Forward the MIH_Link_Parameters_Report to the UE of the CPE -//----------------------------------------------------------------------------- -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf3_ue"); - msg.destination(mid_ue); - - //mn_ho_candidate_query is used to constuct/send the message containing parameters reports - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- before MIH_User_PARAMETERS.indication --->]["+msg.destination().to_string()+"]\n"); - - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, "MIH_User_PARAMETERS.indication- SENT (towards UE)\n"); - -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - odtone::mih::threshold th2; - std::vector thl1; - std::vector thl2; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lcp1.type = lp1; - lcp2.type = lp2; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th2.threshold_val = -19; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - - - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.source(_mihuserid); - odtone::mih::id mid_ue; - mid_ue.assign("mihf2_ue"); - m.destination(mid_ue); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ " --->][ ADDR LINK " - + m.destination().to_string() +"]\n"); - std::cout<<"LINK TUPLE ID "< lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti); -// & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter()->default_value("enb_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1_enb"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user_tcs.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user_tcs.cpp deleted file mode 100644 index 72d46e791b..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/enb_lte_user_tcs.cpp +++ /dev/null @@ -1,1412 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -// Fatma HRIZI EURECOM fr> -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -//This file is the implementation of the MIH user in the eNB - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER is the following (with eRALlteDummy and NASRGDummy executables) -// +--------+ +-----+ -// |MIH_USER| |MIH-F| -// +---+----+ +--+--+ -// | | _current_link_action_request = 0 -// |---------- User_Register.indication ---------------->| (supported_commands) Handler next msg=user_reg_handler -// | | -// |---------- Capability_Discover.request ------------->| Handler next msg=receive_MIH_Capability_Discover_confirm -// |<--------- Capability_Discover.confirm --------------| (success) -// | | -// |---------- Event_Subscribe.request ----------------->| Handler next msg=receive_MIH_Event_Subscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 1: Sequentially activate and deactivate each resource -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// |<--------- Link_Actions.confirm ---------------------| (success) -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// Scenario 2: Activate all resources, then deactivate all resources -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Link_Actions.request -------------------->| (activate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | _current_link_action_request = 0 -// |---------- Link_Actions.request -------------------->| (deactivate-resources[_current_link_action_request]) -// | | Handler next msg=receive_MIH_Link_Actions_confirm -// | | _current_link_action_request = _current_link_action_request + 1 -// |<--------- Link_Actions.confirm ---------------------| (success) -// | . | -// | . | -// | . | -// | | -// ------------------------------------------------------------------------------------------------------------------------ -// | | -// |---------- Event_Unsubscribe.request --------------->| Handler next msg=receive_MIH_Event_Unsubscribe_confirm -// |<--------- Event_Subscribe.confirm ------------------| (success) -// | | -// | | -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s; - if(evtP.get(odtone::mih::mih_evt_link_detected)) s = std::string("DETECTED "); - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s; - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s = std::string("Link_Get_Parameters "); - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::link_id link_id; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - link_id.type = boost::get(i->nettype.link); - link_id.addr = i->addr; - if (i != ntalP->begin()) { - s += " / "; - } - s += link_id2string(link_id); - } - - return s; -} - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(const odtone::mih::config& cfg); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES) -//----------------------------------------------------------------------------- -{ - - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } - else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - log_(0, ""); - - // - // Local Capability Discover Request - // - odtone::mih::message msg; - _mihfid.assign("mihf2"); - msg << odtone::mih::request(odtone::mih::request::capability_discover, _mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Capability_Discover.request --->]["+msg.destination().to_string()+"]\n"); - _mihf.async_send(msg, boost::bind(&mih_user::receive_MIH_Capability_Discover_confirm, this, _1)); - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)"); - log_(0, ""); - - //****eNB***** - // Remote Capability Discover Request - // - mih_user::send_MIH_Capability_Discover_request(cfg); - - //Trigger Link_Configure_Thresholds Request - // odtone::mih::message m; - //m.destination(msg.source()); - //mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - //****eNB***** -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - } - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - - break; - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} -/* -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - log_(0, "MIH_Link_Detected.indication - End\n"); -} -*/ -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - - odtone::mih::link_det_info_list ldil; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - -boost::system::error_code ec; - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - log_(0, " - LINK_ID - Link identifier: ", link_id2string(i->id).c_str()); - log_(0, " - Network ID: ", i->network_id); - log_(0, " - SINR: ", i->sinr); - log_(0, " - Data_rate: ", i->data_rate); - } - - send_MIH_Link_Configure_Thresholds_request(msg, ec); - - - log_(0, "MIH_Link_Detected.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - - for (odtone::mih::link_param_rpt_list::iterator i = lprl.begin(); i != lprl.end(); i++) - { - if (const odtone::mih::threshold *th = boost::get(&i->thold)) { - - log_(0, " - BW Threshold crossed, Value:", boost::get(i->param.value)); - //link_action if free channel is available - } - else{ - log_(0, " -Regular Report for BW Threshold "); - //update MEAS - } - } - - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - //boost::optional ntal; - //boost::optional evt; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::request(odtone::mih::request::capability_discover) - //& odtone::mih::tlv_net_type_addr_list(ntal) - //& odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - _mihfid.assign("mihf2"); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - odtone::mih::threshold th; - std::vector thl; - - odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - - - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - - odtone::mih::link_det_info_list ldil; - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_det_info_list(ldil); - for (odtone::mih::link_det_info_list::iterator i = ldil.begin(); i != ldil.end(); i++) - { - - - lti.type = i->id.type; - lti.addr = i->id.addr; - lp = odtone::mih::link_param_lte_bandwidth; - lcp.type = lp; - if ( link_measures_request ==0){ - lcp.timer_interval = 10; - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } - else{ - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - th.threshold_val = 5; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - } - -/* - if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -*/ -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1234), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf1"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.conf deleted file mode 100644 index 27d56760be..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.cpp deleted file mode 100644 index 40b4891a18..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user.cpp +++ /dev/null @@ -1,1658 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_req -//#define SCENARIO_1 // Sequentially activate and deactivate each resou -//#define SCENARIO_2 // Activate all resources, then deactivate all resour -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -// int& operator [](const link_param_lte_enum value) -// { -// static std::map var; -// if (var.size() == 0) -// { -// var[link_param_lte_rsrp]="link_param_lte_rsrp"; -// var[link_param_lte_rsrq]="link_param_lte_rsrq"; -// var[link_param_lte_cqi]="link_param_lte_cqi"; -// var[link_param_lte_bandwidth]="link_param_lte_bandwidth"; -// var[link_param_lte_pkt_delay]="link_param_lte_pkt_delay"; -// } -// return var[value]; -// } - -const char * MeasurementTypes[]= -{ - "LTE_RSRP", /**< RSRP. */ - "LTE_RSRQ", /**< RSRQ. */ - "link_param_lte_cqi", /**< Multicast packet loss rate.*/ - "link_param_lte_bandwidth", /**< System Load. */ - "link_param_lte_pkt_delay", /**< Number of registered users. */ - "link_param_lte_pkt_loss", /**< Number of active users. */ - "link_param_lte_l2_buffer", /**< Congestion windows of users. */ - "link_param_lte_MN_cap", /**< Congestion windows of users. */ - "link_param_lte_embms", /**< Congestion windows of users. */ - "link_param_lte_jumbo_feasibility", /**< Congestion windows of users. */ - "link_param_lte_jumbo_setup", /**< Congestion windows of users. */ - "link_param_lte_active_embms", /**< Transmission rate of users. */ - "link_param_lte_link_congestion", /**< Link congestion. */ -}; - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)){ - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type"; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - - - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - //send a capability discover request to the remote eNB - mih_user::send_MIH_Capability_Discover_request_remote(); - -} - - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1;; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - // send Link_Action / Power Up - lid.type = odtone::mih::link_type_lte; - lid.addr = ldi.id.addr; - //send_MIH_Link_Action_Power_Up_plus_scan_request(lid); - log_(0, "MIH_Link_Detected.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - - link_act_req.id = link; - link_act_req.action.type = odtone::mih::link_ac_type_power_up; - link_act_req.action.attr.clear(); - link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); - - link_act_req.ex_time = 5000; // in ms - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_enb; - mid_enb.assign("mihf1_enb"); - m.destination(mid_enb); -// m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get(), msg.source()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(dest); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); - mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); - -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); -/* - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl){ - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2*/ - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - -// odtone::mih::link_param_report lpr = lprl.back(); -// -// log_(0, "Meausrement Type: ", lpr.param.type); -// if(odtone::mih::link_param_val *value = boost::get(&lpr.param.value)){ -// log_(0, "Meausrement Value: ", *value); -// -// }; -// const odtone::mih::threshold *th; - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { -// odtone::mih::link_param_lte * index = boost::get(&i->param.type); -// int val = (short)*index; -// log_(0, "Meausrement Type: index ", *index); - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); -// log_(0, "Meausrement Type: ", MeasurementTypes[index]); -// log_(0, "Meausrement Type: ", &i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } -// if (th = boost::get (&i->thold)) -// { -// log_(0, "Threshold crossed ", boost::get (i->param.value)); -// } -// else -// { -// log_(0,"Regular Report"); -// } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - std::vector thl1; - odtone::mih::threshold th2; - std::vector thl2; - odtone::mih::threshold th3; - std::vector thl3; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_cfg_param lcp3; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - odtone::mih::link_param_lte lp3; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lp3 = odtone::mih::link_param_lte_cqi; - lcp1.type = lp1; - lcp2.type = lp2; - lcp3.type = lp3; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - lcp3.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - lcp3.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp3.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - lcp3.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_val = -19; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - th3.threshold_val = 0; - th3.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - thl3.push_back(th3); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - lcp3.threshold_list = thl3; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - lcpl.push_back(lcp3); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp1 == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - if(lp2 == odtone::mih::link_param_lte_rsrq) {log_(0, "\t LTE link parameter LTE RSRQ");} - log_(0, "\t- TIMER INTERVAL - Value: ", lcp1.timer_interval); - - if(lcp1.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp1.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp1.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", (short) th1.threshold_val); - - if(th1.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th1.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -// //----------------------------------------------------------------------------- -// void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -// //----------------------------------------------------------------------------- -// { -// odtone::mih::message m; -// odtone::mih::threshold th; -// std::vector thl; -// odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -// //List of the link threshold parameters -// odtone::mih::link_cfg_param_list lcpl; -// odtone::mih::link_cfg_param lcp; -// odtone::mih::link_param_lte lp; -// //odtone::mih::link_param_gen lp; -// -// odtone::mih::link_param_type typr; -// -// log_(0,""); -// log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -// -// //link_tuple_id -// lti.type = rcv_link_id.type; -// lti.addr = rcv_link_id.addr; -// -// //local_l2_3gpp_addr = boost::get(lti.addr); -// -// -// //link_param_gen_data_rate = 0, /**< Data rate. */ -// //link_param_gen_signal_strength = 1, /**< Signal strength. */ -// //link_param_gen_sinr = 2, /**< SINR. */ -// //link_param_gen_throughput = 3, /**< Throughput. */ -// //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -// //lp = odtone::mih::link_param_lte_bandwidth; -// lp = odtone::mih::link_param_lte_rsrp; -// lcp.type = lp; -// -// link_measures_request = 0; -// if ( link_measures_request ==0){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 3000; -// //th_action_normal = 0, /**< Set normal threshold. */ -// //th_action_one_shot = 1, /**< Set one-shot threshold. */ -// //th_action_cancel = 2 /**< Cancel threshold. */ -// lcp.action = odtone::mih::th_action_normal; -// link_measures_request = 1; -// } else if ( link_measures_request==1){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 0; -// lcp.action = odtone::mih::th_action_cancel; -// link_measures_request = 0; -// } -// -// //above_threshold = 0, /**< Above threshold. */ -// //below_threshold = 1, /**< Below threshold. */ -// th.threshold_val = -105; -// th.threshold_x_dir = odtone::mih::threshold::above_threshold; -// -// thl.push_back(th); -// lcp.threshold_list = thl; -// lcpl.push_back(lcp); -// -// m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -// & odtone::mih::tlv_link_identifier(lti) -// & odtone::mih::tlv_link_cfg_param_list(lcpl); -// -// m.destination(msg.source()); -// -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -// // link_tupple_id2string(lti).c_str() + -// link_id2string(lti).c_str()+ -// " --->]["+_mihfid.to_string()+"]\n"); -// -// _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); -// -// log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); -// -// log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); -// -// //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} -// //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} -// //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} -// //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} -// //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} -// if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} -// -// log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); -// -// if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} -// if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} -// if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} -// -// log_(0, "\t Threshold value: ", th.threshold_val); -// -// if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} -// if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} -// -// log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -// } - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - odtone::uint iter; - odtone::mih::status st; - - //boost::optional lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter lcsl; -// // Todtone::mih::link_cfg_status_list lcsl; -// // Todtone::mih::link_cfg_status lcp; -// //odtone::mih::link_param_gen lp; -// -// // T odtone::mih::link_tuple_id lti; -// -// //msg >> odtone::mih::confirm() -// // & odtone::mih::tlv_status(st) -// // & odtone::mih::tlv_link_identifier(lti) -// // & odtone::mih::tlv_link_cfg_status_list(lcsl); -// -// -// log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); -// log_(0,""); -// } - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("ue_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf2_ue"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user_old.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user_old.cpp deleted file mode 100644 index 40a286434f..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/mih_user/lte_test_user/ue_lte_user_old.cpp +++ /dev/null @@ -1,1437 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_requests -//#define SCENARIO_1 // Sequentially activate and deactivate each resource -//#define SCENARIO_2 // Activate all resources, then deactivate all resources -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type "; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - - - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - mih_user::send_MIH_Capability_Discover_request_remote(); -} - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1; - } - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - // send Link_Action / Power Up - lid.type = odtone::mih::link_type_lte; - lid.addr = ldi.id.addr; - //send_MIH_Link_Action_Power_Up_plus_scan_request(lid); - log_(0, "MIH_Link_Detected.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - - link_act_req.id = link; - link_act_req.action.type = odtone::mih::link_ac_type_power_up; - link_act_req.action.attr.clear(); - link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); - - link_act_req.ex_time = 5000; // in ms - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - - - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ---- 2=>CQI ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value ); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_enb; - mid_enb.assign ("mihf1_enb"); - m.destination(mid_enb); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get(), m); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); - mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); - -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); // DUMMY -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); // DUMMY -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); // DUMMY -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters -// log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); -// if (larl) { -// log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); -// for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) -// { -// log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), -// ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); -// if (_last_link_action_type == odtone::mih::link_ac_type_power_up ) -// { -// send_MIH_Link_Action_Power_Up_plus_scan_request(i->id); -// } -// } -// } -// log_(0, ""); - -/* - - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - }*/ -// #endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th; - std::vector thl; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp; - odtone::mih::link_param_lte lp; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp = odtone::mih::link_param_lte_rsrp; - lcp.type = lp; - - link_measures_request = 0; - if ( link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp.timer_interval = 0; - lcp.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th.threshold_val = -105; - th.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl.push_back(th); - lcp.threshold_list = thl; - lcpl.push_back(lcp); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+_mihfid.to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - - log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); - - if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", th.threshold_val); - - if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - // T odtone::uint iter; - // T odtone::mih::status st; - - //boost::optional lcsl; - // Todtone::mih::link_cfg_status_list lcsl; - // Todtone::mih::link_cfg_status lcp; - //odtone::mih::link_param_gen lp; - - // T odtone::mih::link_tuple_id lti; - - //msg >> odtone::mih::confirm() - // & odtone::mih::tlv_status(st) - // & odtone::mih::tlv_link_identifier(lti) - // & odtone::mih::tlv_link_cfg_status_list(lcsl); - - - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); - log_(0,""); -} - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("ue_lte_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf2_ue"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/oai_conf/start_ue.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/oai_conf/start_ue.bash deleted file mode 100644 index f2bc5f59f5..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue1/oai_conf/start_ue.bash +++ /dev/null @@ -1,206 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_ue.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth0" -declare -x EMULATION_DEV_ADDRESS="192.168.13.2" - -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x UE_IPv4="10.0.0.2" -declare -x UE_IPv6="2001:1::2" -declare -x UE_IPv6_CIDR=$UE_IPv6"/64" -declare -x UE_IPv4_CIDR=$UE_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 7 3 0 2 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 - -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x UE_MIHF_IP_ADDRESS="127.0.0.1" -declare -x UE_RAL_IP_ADDRESS="127.0.0.1" -LOG_FILE="/tmp/oai_sim_ue.log" - -#------------------------------------------------ -MIH_LOG_FILE="mih-f_ue.log" - -# EXE options -EXE_MODE="PROD" # PROD or DEBUG - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - - -################################################## -# LAUNCH UE -################################################## - -echo "Bringup UE interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $UE_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -bash_exec "ip link set $LTEIF up" -sleep 1 -bash_exec "ip addr add dev $LTEIF $UE_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $UE_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip -4 route add default dev $LTEIF table lte -ip -6 route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - -echo "printing the MIH file path" -echo "$ODTONE_MIH_EXE_DIR/$MIH_F $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE" -echo "$ODTONE_MIH_EXE_DIR/$UE_MIH_USER $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE" - -# start MIH-F -xterm -hold -title "[UE][UE1] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F -sleep 3 - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -UE_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LINK_ID=`trim2 $UE_RAL_LINK_ID` -UE_RAL_LINK_ID=`echo $UE_RAL_LINK_ID | cut -d" " -f1` -UE_RAL_LINK_ID_STRIPPED=${UE_RAL_LINK_ID%%??} - -UE_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LISTENING_PORT=`trim2 $UE_RAL_LISTENING_PORT` -UE_RAL_LISTENING_PORT=`echo $UE_RAL_LISTENING_PORT | cut -d" " -f2` - -UE_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -UE_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -#xterm -hold -e gdb --args -# $EMULATION_DEV_INTERFACE -D192.168.13.2 -#sudo ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE -#$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/rb_tool -a -c0 -i0 -z0 -s 10.0.0.2 -t 10.0.0.1 -r 1 - -if [ $EXE_MODE = "DEBUG" ] ; then - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_ADDRESS \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > log_ue.txt & -else - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -l3 -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_ADDRESS \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > /dev/null & - -fi - -wait_process_started oaisim - - -# start MIH-USER - -# wait for emulation start -tshark -c 500 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -sleep 5 - -xterm -hold -title "[UE][UE1] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$UE_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE & -wait_process_started $UE_MIH_USER - -sleep 100000 - - - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/link_sap.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/link_sap.conf deleted file mode 100644 index c5b63413d0..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/link_sap.conf +++ /dev/null @@ -1,47 +0,0 @@ -#=============================================================================== -# Brief : Link SAP configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2013 Universidade Aveiro -# Copyright (C) 2009-2013 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[link] -## -## Link SAP identifier -## -id=link1 - -## -## Link SAP listening -## -port = 1235 - -## -## Link SAP interface technology -## -tec = 802_11 - -## -## Link SAP interface address -## -link_addr = 00:11:22:33:44:55 - -## -## Comma separated list of the Link SAP supported events -## -event_list = link_detected, link_up, link_down, link_parameters_report, link_going_down, link_handover_imminent, link_handover_complete - -[mihf] -ip=127.0.0.1 -local_port=1025 diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/odtone_ue.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/odtone_ue.conf deleted file mode 100644 index c2f596c5cc..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/odtone_ue.conf +++ /dev/null @@ -1,74 +0,0 @@ -#=============================================================================== -# Brief : MIHF configuration file -# Authors : Carlos Guimaraes -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -[mihf] -## -## This mihf's id -## -## Usage: id = -## -id = mihf3_ue - -## -## Port on localhost that MIH Users and MIH Link SAPs connect to. -## -## Usage: local_port = -## -local_port = 1025 - -## -## Port to which remote peer MIHF connect to -## -## Usage: remote_port = -## -remote_port = 4551 - -## -## Comma seperated list of remote MIHF's -## -## If you want to test remote MIHF communication add an entry here -## with the IP address of the remote MIHF. -## -## Usage: peers = , ... -## -#peers = mihf1_enb 10.0.0.1 4551 udp, mihf4_enb 10.0.0.4 4551 udp -peers = mihf1_enb 192.168.14.3 4551 udp, mihf4_enb 10.0.2.4 4551 udp - -## -## Comma separated list of local MIH User SAPs id's and ports -## -## Usage: users = [ ], ... -## Note: If no command is specified, the MIHF will assume that the MIH-User -## supports all MIH_***_HO_*** commands and the MIH_Get_Information -## Note: If no query is specified, the MIHF will assume that the MIH-User does -## not support the MIH_Get_Information command. -## -#users = user 1235 -users = user_ue 1635 - -## -## Comma separated list of local MIH Link SAPs id's and ports. -## -## Usage: links = [ ], ... -## -## -links = ue_lte_link00 1234 LTE 00:39:18:36:73:02 00:11:22 5 - -## -## Comma separated list of the MIHF's transport protocol -## -transport = udp diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/ue2_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/ue2_user.conf deleted file mode 100644 index b50aab8e28..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_conf/ue2_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue2 - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/Jamfile b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/Jamfile deleted file mode 100644 index 42075be3e2..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/Jamfile +++ /dev/null @@ -1,33 +0,0 @@ -#=============================================================================== -# Brief : MIH-User SAP Application Sample Project Build -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -project ue2_user - ; - -exe ue2_user - : ue2_user.cpp - ../../lib/odtone//odtone - /boost//program_options - ; - -install install - : ue2_user - ue2_user.conf - : ../../dist - ; - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.conf b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.conf deleted file mode 100644 index b50aab8e28..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.conf +++ /dev/null @@ -1,42 +0,0 @@ -#=============================================================================== -# Brief : MIH-User configuration file -# Authors : Carlos Guimaraes -# Bruno Santos -#------------------------------------------------------------------------------- -# ODTONE - Open Dot Twenty One -# -# Copyright (C) 2009-2012 Universidade Aveiro -# Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -# -# This software is distributed under a license. The full license -# agreement can be found in the file LICENSE in this distribution. -# This software may not be copied, modified, sold or distributed -# other than expressed in the named license agreement. -# -# This software is distributed without any warranty. -#=============================================================================== - -## -## User id -## -[user] -id = user_ue2 - -## -## Commands supported by the MIH-User -## -commands = mih_link_get_parameters, mih_link_configure_thresholds, mih_link_actions, mih_net_ho_candidate_query, mih_net_ho_commit, mih_n2n_ho_query_resources, mih_n2n_ho_commit, mih_n2n_ho_complete, mih_mn_ho_candidate_query, mih_mn_ho_commit, mih_mn_ho_complete - -## -## Port used for communication with MIHF -## -[conf] -port = 1635 - -## -## MIHF configuration. For the default demonstration leave as is. -## -[mihf] -local_port = 1025 - - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.cpp b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.cpp deleted file mode 100644 index 1e947bb4f6..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/mih_user/lte_test_user/ue2_user.cpp +++ /dev/null @@ -1,1712 +0,0 @@ -//============================================================================== -// Brief : MIH-User -// Authors : Bruno Santos -//------------------------------------------------------------------------------ -// ODTONE - Open Dot Twenty One -// -// Copyright (C) 2009-2012 Universidade Aveiro -// Copyright (C) 2009-2012 Instituto de Telecomunicações - Pólo Aveiro -// -// This software is distributed under a license. The full license -// agreement can be found in the file LICENSE in this distribution. -// This software may not be copied, modified, sold or distributed -// other than expressed in the named license agreement. -// -// This software is distributed without any warranty. -//============================================================================== - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// - -// Definition of the scenario to execute -#define NB_OF_RESOURCES 4 // Should not exceed mih_user::_max_link_action_req -//#define SCENARIO_1 // Sequentially activate and deactivate each resou -//#define SCENARIO_2 // Activate all resources, then deactivate all resour -#define NUM_PARM_REPORT 10 - -/////////////////////////////////////////////////////////////////////////////// -// The scenario coded in this MIH-USER demo is the following -// +--------+ +-----+ +---------+ -// |MIH_USER| |MIH-F| |LINK_SAP | -// +---+----+ +--+--+ +----+----+ -// | | | -// ... (start of MIH-F here) ... ... -// | |---------- Link_Capability_Discover.request --------X| -// ... (start of LINK_SAP here) ... ... -// | |<--------- Link_Register.indication -----------------| -// | |---------- Link_Capability_Discover.request -------->| -// | |<--------- Link_Capability_Discover.confirm ---------| -// | | | -// ... (start of MIH USER here) ... ... -// |---------- MIH_User_Register.indication ------------>| (supported_commands) | -// | | | -// |---------- MIH_Capability_Discover.request --------->| | -// |<--------- MIH_Capability_Discover.confirm ----------| | -// | | | -// |---------- MIH_Event_Subscribe.request ------------->|---------- Link_Event_Subscribe.request ------------>| -// |<--------- MIH_Event_Subscribe.confirm --------------|<--------- Link_Event_Subscribe.confirm -------------| -// | | | -// |---------- MIH_Link_Actions.request ---------------->|---------- Link_Actions.request -------------------->| -// | (POWER UP + SCAN) | (POWER UP + SCAN) | -// ... ... ... -// | | | -// |<--------- Link_Detected.indication -----------------|<--------- Link_Detected.indication -----------------| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | RRC Connection Reestablishment notification) | -// | | | -// |---------- MIH_Link_Configure_Thresholds.request --->|---------- Link_Configure_Thresholds.request ------->| -// | | | -// |<--------- Link_Up.indication -----------------------|<--------- Link_Up.indication -----------------------| -// | | (RRC Connection reconfiguration notification) | -// |<--------- MIH_Link_Configure_Thresholds.confirm ----|<--------- Link_Configure_Thresholds.confirm --------| -// | | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Actions.confirm -----------------|<--------- Link_Actions.confirm ---------------------| -// | (Success) | | -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// |<--------- MIH_Link_Parameters_Report.indication ----|<--------- MIH_Link_Parameters_Report.indication ----| -// ... ... ... -// etc etc etc - -/////////////////////////////////////////////////////////////////////////////// - -static const char* const kConf_MIH_Commands = "user.commands"; - -/////////////////////////////////////////////////////////////////////////////// - -namespace po = boost::program_options; - -using odtone::uint; -using odtone::ushort; -using odtone::sint8; - -odtone::logger log_("[mih_usr]", std::cout); - -/////////////////////////////////////////////////////////////////////////////// - -// int& operator [](const link_param_lte_enum value) -// { -// static std::map var; -// if (var.size() == 0) -// { -// var[link_param_lte_rsrp]="link_param_lte_rsrp"; -// var[link_param_lte_rsrq]="link_param_lte_rsrq"; -// var[link_param_lte_cqi]="link_param_lte_cqi"; -// var[link_param_lte_bandwidth]="link_param_lte_bandwidth"; -// var[link_param_lte_pkt_delay]="link_param_lte_pkt_delay"; -// } -// return var[value]; -// } - -const char * MeasurementTypes[]= -{ - "LTE_RSRP", /**< RSRP. */ - "LTE_RSRQ", /**< RSRQ. */ - "link_param_lte_cqi", /**< Multicast packet loss rate.*/ - "link_param_lte_bandwidth", /**< System Load. */ - "link_param_lte_pkt_delay", /**< Number of registered users. */ - "link_param_lte_pkt_loss", /**< Number of active users. */ - "link_param_lte_l2_buffer", /**< Congestion windows of users. */ - "link_param_lte_MN_cap", /**< Congestion windows of users. */ - "link_param_lte_embms", /**< Congestion windows of users. */ - "link_param_lte_jumbo_feasibility", /**< Congestion windows of users. */ - "link_param_lte_jumbo_setup", /**< Congestion windows of users. */ - "link_param_lte_active_embms", /**< Transmission rate of users. */ - "link_param_lte_link_congestion", /**< Link congestion. */ -}; - -/////////////////////////////////////////////////////////////////////////////// - -//----------------------------------------------------------------------------- -void __trim(odtone::mih::octet_string &str, const char chr) -//----------------------------------------------------------------------------- -{ - str.erase(std::remove(str.begin(), str.end(), chr), str.end()); -} -//----------------------------------------------------------------------------- -template std::string StringOf(T object) { -//----------------------------------------------------------------------------- - std::ostringstream os; - os << object; - return(os.str()); -} -//----------------------------------------------------------------------------- -std::string getTimeStamp4Log() -//----------------------------------------------------------------------------- -{ - std::stringstream ss (std::stringstream::in | std::stringstream::out); - struct timespec time_spec; - unsigned int time_now_micros; - unsigned int time_now_s; - clock_gettime (CLOCK_REALTIME, &time_spec); - time_now_s = (unsigned int) time_spec.tv_sec % 3600; - time_now_micros = (unsigned int) time_spec.tv_nsec/1000; - ss << time_now_s << ':' << time_now_micros; - return ss.str(); -} -//----------------------------------------------------------------------------- -std::string status2string(odtone::mih::status statusP){ -//----------------------------------------------------------------------------- - switch (statusP.get()) { - case odtone::mih::status_success: return "SUCCESS";break; - case odtone::mih::status_failure: return "UNSPECIFIED_FAILURE";break; - case odtone::mih::status_rejected: return "REJECTED";break; - case odtone::mih::status_authorization_failure: return "AUTHORIZATION_FAILURE";break; - case odtone::mih::status_network_error: return "NETWORK_ERROR";break; - default: return "UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_down_reason2string(odtone::mih::link_dn_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_dn_reason_explicit_disconnect: return "DN_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_dn_reason_packet_timeout: return "DN_REASON_PACKET_TIMEOUT";break; - case odtone::mih::link_dn_reason_no_resource: return "DN_REASON_NO_RESOURCE";break; - case odtone::mih::link_dn_reason_no_broadcast: return "DN_REASON_NO_BROADCAST";break; - case odtone::mih::link_dn_reason_authentication_failure: return "DN_REASON_AUTHENTICATION_FAILURE";break; - case odtone::mih::link_dn_reason_billing_failure: return "DN_REASON_BILLING_FAILURE";break; - default: return "DN_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string link_going_down_reason2string(odtone::mih::link_gd_reason reasonP){ -//----------------------------------------------------------------------------- - switch (reasonP.get()) { - case odtone::mih::link_gd_reason_explicit_disconnect: return "GD_REASON_EXPLICIT_DISCONNECT";break; - case odtone::mih::link_gd_reason_link_parameter_degrading: return "GD_REASON_PARAMETER_DEGRADING";break; - case odtone::mih::link_gd_reason_low_power: return "GD_REASON_LOW_POWER";break; - case odtone::mih::link_gd_reason_no_resource: return "GD_REASON_NO_RESOURCE";break; - default: return "GD_REASON_UNKNOWN"; - } -} -//----------------------------------------------------------------------------- -std::string evt2string(odtone::mih::mih_evt_list evtP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(evtP.get(odtone::mih::mih_evt_link_detected)) s += "DETECTED "; - if(evtP.get(odtone::mih::mih_evt_link_up)) s += "UP "; - if(evtP.get(odtone::mih::mih_evt_link_down)) s += "DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_parameters_report)) s += "PARAMETERS_REPORT "; - if(evtP.get(odtone::mih::mih_evt_link_going_down)) s += "GOING_DOWN "; - if(evtP.get(odtone::mih::mih_evt_link_handover_imminent)) s += "HANDOVER_IMMINENT "; - if(evtP.get(odtone::mih::mih_evt_link_handover_complete)) s += "HANDOVER_COMPLETE "; - if(evtP.get(odtone::mih::mih_evt_link_pdu_transmit_status)) s += "PDU_TRANSMIT_STATUS "; - return s; -} -//----------------------------------------------------------------------------- -std::string cmd2string(odtone::mih::mih_cmd_list cmdP){ -//----------------------------------------------------------------------------- - std::string s=std::string(" "); - if(cmdP.get(odtone::mih::mih_cmd_link_get_parameters)) s += "Link_Get_Parameters "; - if(cmdP.get(odtone::mih::mih_cmd_link_configure_thresholds)) s += "Link_Configure_Thresholds "; - if(cmdP.get(odtone::mih::mih_cmd_link_actions)) s += "Link_Actions "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_candidate_query)) s += "Net_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_net_ho_commit)) s += "Net_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_query_resources)) s += "N2N_HO_Query_Resources "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_commit)) s += "N2N_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_n2n_ho_complete)) s += "N2N_HO_Complete "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_candidate_query)) s += "MN_HO_Candidate_Query "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_commit)) s += "MN_HO_Commit "; - if(cmdP.get(odtone::mih::mih_cmd_mn_ho_complete)) s += "MN_HO_Complete "; - return s; -} -//----------------------------------------------------------------------------- -std::string link_type2string(const odtone::mih::link_type& lt) -//----------------------------------------------------------------------------- -{ - switch (lt.get()) { - case odtone::mih::link_type_gsm: return "GSM"; break; - case odtone::mih::link_type_gprs: return "GPRS"; break; - case odtone::mih::link_type_edge: return "EDGE"; break; - case odtone::mih::link_type_ethernet: return "Ethernet"; break; - case odtone::mih::link_type_wireless_other: return "Other"; break; - case odtone::mih::link_type_802_11: return "IEEE 802.11"; break; - case odtone::mih::link_type_cdma2000: return "CDMA-2000"; break; - case odtone::mih::link_type_umts: return "UMTS"; break; - case odtone::mih::link_type_cdma2000_hrpd: return "CDMA-2000-HRPD"; break; - case odtone::mih::link_type_lte: return "LTE"; break; - case odtone::mih::link_type_802_16: return "IEEE 802.16"; break; - case odtone::mih::link_type_802_20: return "IEEE 802.20"; break; - case odtone::mih::link_type_802_22: return "IEEE 802.22"; break; - default: break; - } - return "Unknown link type"; -} -//----------------------------------------------------------------------------- -std::string link_addr2string(const odtone::mih::link_addr *addr) -//----------------------------------------------------------------------------- -{ - if (const odtone::mih::mac_addr *la = boost::get(addr)) { - return la->address(); - } - else if (const odtone::mih::l2_3gpp_3g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d") % plmn % la->_cell_id); - } - else if (const odtone::mih::l2_3gpp_2g_cell_id *la = boost::get(addr)) { - char plmn[16]; - sprintf(plmn, "%hhx:%hhx:%hhx", la->plmn_id[0], la->plmn_id[1], la->plmn_id[2]); - return str(boost::format("%s %d %d") % plmn % la->_lac % la->_ci); - } - else if (const odtone::mih::l2_3gpp_addr *la = boost::get(addr)){ - return la->value; - } - else if (const odtone::mih::l2_3gpp2_addr *la = boost::get(addr)) { - return la->value; - } - else if (const odtone::mih::other_l2_addr *la = boost::get(addr)) { - return la->value; - } - return "null"; -} -//----------------------------------------------------------------------------- -std::string l2_3gpp_3g_cell_id2string(odtone::mih::l2_3gpp_3g_cell_id& addr) -//----------------------------------------------------------------------------- -{ - char buffer[256]; - int index = 0; - - index += std::sprintf(&buffer[index], "plmn: -%hhx--%hhx--%hhx-\n", addr.plmn_id[0], addr.plmn_id[1], addr.plmn_id[2]); - index += std::sprintf(&buffer[index], "cell_id: %hhx\n", addr._cell_id); - return buffer; -} -//----------------------------------------------------------------------------- -std::string link_id2string(odtone::mih::link_id linkP) -//----------------------------------------------------------------------------- -{ - std::string s; - s = link_type2string(linkP.type.get()) + " " + link_addr2string(&linkP.addr); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_addr2string(odtone::mih::ip_addr ip_addrP) { -//----------------------------------------------------------------------------- - std::string s; - switch (ip_addrP.type()) { - case odtone::mih::ip_addr::ipv4: s = "ipv4 "; break; - case odtone::mih::ip_addr::ipv6: s = "ipv6 "; break; - default: s = "Unkown type"; - } - s += ip_addrP.address(); - return s; -} -//----------------------------------------------------------------------------- -std::string ip_tuple2string(odtone::mih::ip_tuple ip_tupleP) { -//----------------------------------------------------------------------------- - char buffer[128]; - std::snprintf(buffer, 128, "%s/%d", ip_addr2string(ip_tupleP.ip).c_str(), ip_tupleP.port_val); - return buffer; -} -//----------------------------------------------------------------------------- -std::string ip_proto2string(odtone::mih::proto ip_protoP) { -//----------------------------------------------------------------------------- - switch (ip_protoP.get()) { - case odtone::mih::proto_tcp: return "TCP"; - case odtone::mih::proto_udp: return "UDP"; - default: break; - } - return "Unknown IP protocol"; -} -// TEMP : next 2 functions are commented to restore flow_id as a uint32 -// full structure will be updated later -/*//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::flow_id flowP) { -//----------------------------------------------------------------------------- - std::string s; - odtone::mih::ip_tuple ip; - ip = flowP.src; - s = "SRC = " + ip_tuple2string(flowP.src); - s += ", DST = " + ip_tuple2string(flowP.dst); - s += ", PROTO = " + ip_proto2string(flowP.transport); - return s; -} -//----------------------------------------------------------------------------- -std::string flow_id2string(odtone::mih::link_ac_param link_ac_paramP) { -//----------------------------------------------------------------------------- - if (odtone::mih::resource_desc *res = boost::get(&link_ac_paramP.param)) { - return flow_id2string(res->fid); - } - else if (odtone::mih::flow_attribute *flow = boost::get(&link_ac_paramP.param)) { - return flow_id2string(flow->id); - } - return "null"; -}*/ -//----------------------------------------------------------------------------- -std::string link_ac_result2string(odtone::mih::link_ac_result resultP) -//----------------------------------------------------------------------------- -{ - switch (resultP.get()) { - case odtone::mih::link_ac_success: return "SUCCESS"; break; - case odtone::mih::link_ac_failure: return "FAILURE"; break; - case odtone::mih::link_ac_refused: return "REFUSED"; break; - case odtone::mih::link_ac_incapable: return "INCAPABLE"; break; - default: break; - } - return "Unknown action result"; -} -//----------------------------------------------------------------------------- -std::string link_actions_req2string(odtone::mih::link_action_req link_act_reqP) { -//----------------------------------------------------------------------------- - std::string s; - - s = link_id2string(link_act_reqP.id); - - if(link_act_reqP.action.type == odtone::mih::link_ac_type_none) s += ", AC_TYPE_NONE"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_disconnect) s += ", AC_TYPE_DISCONNECT"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_low_power) s += ", AC_TYPE_LOW_POWER"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_down) s += ", AC_TYPE_POWER_DOWN"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_power_up) s += ", AC_TYPE_POWER_UP"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_flow_attr) s += ", AC_TYPE_FLOW_ATTR"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_activate_resources) s += ", AC_TYPE_ACTIVATE_RESOURCES"; - if(link_act_reqP.action.type == odtone::mih::link_ac_type_link_deactivate_resources) s += ", AC_TYPE_DEACTIVATE_RESOURCES"; - - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_data_fwd_req)) s += ", AC_ATTR_DATA_FWD_REQ"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_scan)) s += ", AC_ATTR_SCAN"; - if(link_act_reqP.action.attr.get(odtone::mih::link_ac_attr_res_retain)) s += ", AC_ATTR_RES_RETAIN"; - - s += ", " + StringOf(link_act_reqP.ex_time) + " ms"; - return s; -} -//----------------------------------------------------------------------------- -std::string net_type_addr_list2string(boost::optional ntalP) { -//----------------------------------------------------------------------------- - std::string s; - std::ostringstream stream; - odtone::mih::net_type_addr net_type_addr; - - for (odtone::mih::net_type_addr_list::iterator i = ntalP->begin(); i != ntalP->end(); i++) - { - net_type_addr = boost::get(*i); - stream << net_type_addr; - if (i != ntalP->begin()) { - stream << " / "; - } - } - s = stream.str(); - return s; -} - - - -/** - * Parse supported commands. - * - * @param cfg Configuration options. - * @return An optional list of supported commands. - */ -boost::optional parse_supported_commands(const odtone::mih::config &cfg) -{ - using namespace boost; - - odtone::mih::mih_cmd_list commands; - - std::map enum_map; - enum_map["mih_link_get_parameters"] = odtone::mih::mih_cmd_link_get_parameters; - enum_map["mih_link_configure_thresholds"] = odtone::mih::mih_cmd_link_configure_thresholds; - enum_map["mih_link_actions"] = odtone::mih::mih_cmd_link_actions; - enum_map["mih_net_ho_candidate_query"] = odtone::mih::mih_cmd_net_ho_candidate_query; - enum_map["mih_net_ho_commit"] = odtone::mih::mih_cmd_net_ho_commit; - enum_map["mih_n2n_ho_query_resources"] = odtone::mih::mih_cmd_n2n_ho_query_resources; - enum_map["mih_n2n_ho_commit"] = odtone::mih::mih_cmd_n2n_ho_commit; - enum_map["mih_n2n_ho_complete"] = odtone::mih::mih_cmd_n2n_ho_complete; - enum_map["mih_mn_ho_candidate_query"] = odtone::mih::mih_cmd_mn_ho_candidate_query; - enum_map["mih_mn_ho_commit"] = odtone::mih::mih_cmd_mn_ho_commit; - enum_map["mih_mn_ho_complete"] = odtone::mih::mih_cmd_mn_ho_complete; - - std::string tmp = cfg.get(kConf_MIH_Commands); - __trim(tmp, ' '); - - char_separator sep1(","); - tokenizer< char_separator > list_tokens(tmp, sep1); - - BOOST_FOREACH(std::string str, list_tokens) { - if(enum_map.find(str) != enum_map.end()) { - commands.set((odtone::mih::mih_cmd_list_enum) enum_map[str]); - } - } - - return commands; -} - -/////////////////////////////////////////////////////////////////////////////// -/** - * This class provides an implementation of an IEEE 802.21 MIH-User. - */ -class mih_user : boost::noncopyable { -public: - /** - * Construct the MIH-User. - * - * @param cfg Configuration options. - * @param io The io_service object that the MIH-User will use to - * dispatch handlers for any asynchronous operations performed on the socket. - */ - mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io); - - /** - * Destruct the MIH-User. - */ - ~mih_user(); - -protected: - /** - * User registration handler. - * - * @param cfg Configuration options. - * @param ec Error Code. - */ - void user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec); - /** - * Default MIH event handler. - * - * @param msg Received event notification. - * @param ec Error code. - */ - void event_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - /** - * MIH receive message handler. - * - * @param msg Received message. - * @param ec Error code. - */ - void receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec); - - void send_MIH_User_Register_indication(const odtone::mih::config& cfg); - - void send_MIH_Capability_Discover_request(void); - void send_MIH_Capability_Discover_request_remote(void); - void receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest); - void receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Event_Unsubscribe_request(void); - void send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt); - void receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg); - - void send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type); - void receive_MIH_Link_Actions_confirm(odtone::mih::message& msg); - void receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec); - void forward_Parameters_Report_indication(odtone::mih::message& msg); - - void send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec); - void receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec); - -private: - odtone::sap::user _mihf; /**< User SAP helper. */ - odtone::mih::id _mihfid; /**< MIHF destination ID. */ - odtone::mih::id _mihuserid; /**< MIH_USER ID. */ - - odtone::mih::ip_addr _mihf_ip; /**< MIHF IP address */ - odtone::mih::port _mihf_lport; /**< MIHF local port number */ - - odtone::mih::link_id_list _link_id_list; /**< List of network link identifiers */ - odtone::mih::mih_evt_list _subs_evt_list; /**< List of subscribed link events */ - - odtone::mih::link_ac_type _last_link_action_type; - odtone::uint _current_link_action_request, _nb_of_link_action_requests; - odtone::uint link_threshold_request, link_measures_request, link_measures_counter; - odtone::mih::link_id rcv_link_id; - - static const odtone::uint _max_link_action_requests = 4; - odtone::uint _num_thresholds_request; - - void receive_MIH_Link_Detected_indication(odtone::mih::message& msg); - void send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link); - void receive_MIH_Link_Up_indication(odtone::mih::message& msg); - - void receive_MIH_Link_Down_indication(odtone::mih::message& msg); - void receive_MIH_MN_HO_Candidate_Query_request(odtone::mih::message& msg); - - void receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg); - -}; - -//----------------------------------------------------------------------------- -mih_user::mih_user(const odtone::mih::config& cfg, boost::asio::io_service& io) - : _mihf(cfg, io, boost::bind(&mih_user::event_handler, this, _1, _2)), - _last_link_action_type(odtone::mih::link_ac_type_none), - _current_link_action_request(0), _nb_of_link_action_requests(NB_OF_RESOURCES), _num_thresholds_request(0) -//----------------------------------------------------------------------------- -{ - odtone::mih::octet_string user_id = cfg.get(odtone::sap::kConf_MIH_SAP_id); - _mihuserid.assign(user_id.c_str()); - - odtone::mih::octet_string dest_id = cfg.get(odtone::sap::kConf_MIH_SAP_dest); - _mihfid.assign(dest_id.c_str()); - - odtone::mih::octet_string src = cfg.get(odtone::sap::kConf_MIHF_Ip); - boost::asio::ip::address ip = boost::asio::ip::address::from_string(src); - if (ip.is_v4()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv4, src); - _mihf_ip = ip_addr; - } else if (ip.is_v6()) { - odtone::mih::ip_addr ip_addr(odtone::mih::ip_addr::ipv6, src); - _mihf_ip = ip_addr; - } - - _mihf_lport = cfg.get(odtone::sap::kConf_MIHF_Local_Port); - - //_nb_of_link_action_requests = NB_OF_RESOURCES; - if (_nb_of_link_action_requests > _max_link_action_requests) { - _nb_of_link_action_requests = _max_link_action_requests; - } - - _link_id_list.clear(); - _subs_evt_list.clear(); - link_threshold_request = 0; - link_measures_request =0; - link_measures_counter =0; - log_(0, "[MSC_NEW]["+getTimeStamp4Log()+"][MIH-USER="+_mihuserid.to_string()+"]\n"); - - // Send MEDIEVAL specific MIH_User_Register.indication message to the MIH-F - mih_user::send_MIH_User_Register_indication(cfg); -} - -//----------------------------------------------------------------------------- -mih_user::~mih_user() -//----------------------------------------------------------------------------- -{ -} - -//----------------------------------------------------------------------------- -void mih_user::user_reg_handler(const odtone::mih::config& cfg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH-User register result: ", ec.message(), "\n"); - - // - // Let's fire a capability discover request to get things moving - // - mih_user::send_MIH_Capability_Discover_request(); - //send a capability discover request to the remote eNB - mih_user::send_MIH_Capability_Discover_request_remote(); - -} - - -//----------------------------------------------------------------------------- -void mih_user::event_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - case odtone::mih::indication::link_detected: - mih_user::receive_MIH_Link_Detected_indication(msg); - break; - - case odtone::mih::indication::link_up: - mih_user::receive_MIH_Link_Up_indication(msg); - if (_num_thresholds_request == 0) { - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - _num_thresholds_request += 1;; - } - break; - - case odtone::mih::indication::mn_ho_candidate_query: - log_(0, "MIH-User has received a request \"mn_ho_candidate_query\"", msg.mid()); - mih_user::receive_MIH_MN_HO_Candidate_Query_request(msg); - break; - - case odtone::mih::indication::link_down: - mih_user::receive_MIH_Link_Down_indication(msg); - break; - - case odtone::mih::indication::link_going_down: - mih_user::receive_MIH_Link_Going_Down_indication(msg); - break; - - case odtone::mih::indication::link_handover_imminent: - log_(0, "MIH-User has received a local event \"link_handover_imminent\""); - break; - - case odtone::mih::indication::link_handover_complete: - log_(0, "MIH-User has received a local event \"link_handover_complete\""); - break; - - case odtone::mih::indication::link_parameters_report: - //log_(0, "MIH-User has received a local event \"link_parameters_report\""); - mih_user::receive_MIH_Link_Parameters_Report(msg, ec); - /*if (link_threshold_request == 0){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - link_threshold_request =1; - } else if (link_threshold_request == 1){ - link_measures_counter ++; - // Stop measures after 5 reports - if (link_measures_counter == NUM_PARM_REPORT){ - mih_user::send_MIH_Link_Configure_Thresholds_request(msg, ec); - } - }*/ - break; - - case odtone::mih::indication::link_pdu_transmit_status: - log_(0, "MIH-User has received a local event \"link_pdu_transmit_status\""); - break; - - case odtone::mih::confirm::link_configure_thresholds: - mih_user::receive_MIH_Link_Configure_Thresholds_confirm(msg, ec); - break; - - default: - log_(0, "MIH-User has received UNKNOWN local event", msg.mid()); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_handler(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - if (ec) { - log_(0, __FUNCTION__, " error: ", ec.message()); - return; - } - - switch (msg.mid()) { - - case odtone::mih::confirm::capability_discover: - mih_user::receive_MIH_Capability_Discover_confirm(msg); - break; - - case odtone::mih::confirm::event_subscribe: - mih_user::receive_MIH_Event_Subscribe_confirm(msg); - break; - - case odtone::mih::confirm::event_unsubscribe: - mih_user::receive_MIH_Event_Unsubscribe_confirm(msg); - break; - - case odtone::mih::confirm::link_actions: - mih_user::receive_MIH_Link_Actions_confirm(msg); - break; - - default: - log_(0, "MIH-User has received UNKNOWN message (", msg.mid(), ")\n"); - break; - } -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Detected_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Detected.indication - RECEIVED - Begin\n"); - odtone::mih::link_det_info ldi; - odtone::mih::link_det_info_list ldil; - odtone::mih::link_det_info_list::iterator it_ldil; - odtone::mih::link_id lid; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_det_info_list(ldil); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Detected.indication --->]["+msg.destination().to_string()+"]\n"); - for(it_ldil = ldil.begin(); it_ldil != ldil.end(); it_ldil++) { - ldi = *it_ldil; - log_(0, "\tMIH_Link_Detected.indication - network_id:........", ldi.network_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - net_aux_id:........", ldi.net_aux_id.c_str()); - log_(0, "\tMIH_Link_Detected.indication - sig_strength:......TO DO");//, ldi.signal); - log_(0, "\tMIH_Link_Detected.indication - sinr:..............", ldi.sinr); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - data_rate:.........", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - mih_capabilities:..", ldi.data_rate); - log_(0, "\tMIH_Link_Detected.indication - net_capabilities:..TO DO");//, ldi.net_capabilities); - - } - // Display message parameters - // TODO: for each link_det_info in the list {display LINK_DET_INFO} - - // send Link_Action / Power Up - lid.type = odtone::mih::link_type_lte; - lid.addr = ldi.id.addr; - send_MIH_Link_Action_Power_Up_plus_scan_request(lid); - log_(0, "MIH_Link_Detected.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(const odtone::mih::link_id& link) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - //struct null n; - - link_act_req.id = link; - link_act_req.action.type = odtone::mih::link_ac_type_power_up; - link_act_req.action.attr.clear(); - link_act_req.action.attr.set(odtone::mih::link_ac_attr_scan); - - link_act_req.ex_time = 5000; // in ms - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Action_Power_Up_request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Up_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Up.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; -// odtone::mih::tlv_old_access_router oldAR; - - msg >> odtone::mih::indication() & odtone::mih::tlv_link_identifier(link); -// & odtone::mih::tlv_old_access_router(oar); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Up.indication --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); - - log_(0, "MIH_Link_Up.indication - End\n"); -} - - -//MIH_MN_HO_Candidate_Query_request used to forward the parameters report from eNB1 to eNB2 -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_MN_HO_Candidate_Query_request(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::request() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "MIH_MN_HO_Candidate_Query.request - RECEIVED - Begin\n"); - - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - -for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } - - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); - - //forward the Link parameters report to eNB2 - forward_Parameters_Report_indication(msg); -} - - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - boost::optional addr; - odtone::mih::link_dn_reason ldr; - - log_(0, "MIH_Link_Down.indication - RECEIVED - Begin\n"); - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_old_access_router(addr) - & odtone::mih::tlv_link_dn_reason(ldr); - -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Down.indication\\n"+link_down_reason2string(ldr).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - //Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str(), "\n"); -// log_(0, " - LINK_DN_REASON - Link down reason: ", link_down_reason2string(ldr).c_str(), "\n"); - - log_(0, "MIH_Link_Down.indication - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Going_Down_indication(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Going_Down.indication - RECEIVED - Begin\n"); - - odtone::mih::link_tuple_id link; - odtone::mih::link_gd_reason lgd; - odtone::mih::link_ac_ex_time ex_time; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_time_interval(ex_time) - & odtone::mih::tlv_link_gd_reason(lgd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Going_Down.indication\\n"+link_going_down_reason2string(lgd).c_str()+" --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - Time Interval:", (ex_time/256)); - log_(0, " - LINK_GD_REASON - Link going down reason: ", link_going_down_reason2string(lgd).c_str(), "\n"); - - log_(0, "MIH_Link_Going_Down.indication - End\n"); -} - - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_User_Register_indication(const odtone::mih::config& cfg) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - boost::optional supp_cmd = parse_supported_commands(cfg); - - m << odtone::mih::indication(odtone::mih::indication::user_register) - & odtone::mih::tlv_command_list(supp_cmd); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_User_Register.indication --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::user_reg_handler, this, boost::cref(cfg), _2)); - - log_(0, "MIH_User_Register.indication - SENT (towards its local MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Capability_Discover_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards its local MIHF)\n"); -} - -void mih_user::send_MIH_Capability_Discover_request_remote(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - m << odtone::mih::request(odtone::mih::request::capability_discover); - m.source(_mihuserid); - odtone::mih::id mid_enb; - mid_enb.assign("mihf4_enb"); - m.destination(mid_enb); -// m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Capability_Discover.request --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH_Capability_Discover.request - SENT (towards the remote MIHF)\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Capability_Discover_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Capability_Discover.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional ntal; - boost::optional evt; - boost::optional cmd; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_net_type_addr_list(ntal) - & odtone::mih::tlv_event_list(evt) - & odtone::mih::tlv_command_list(cmd); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Capability_Discover.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - "\\nNet type addr list=" + net_type_addr_list2string(ntal).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - if (cmd) { - log_(0, " - MIH_CMD_LIST - Command List: ", cmd2string(cmd.get()).c_str()); - } - if (ntal) { - log_(0, " - LIST(NET_TYPE_ADDR) - Network Types and Link Address: ", net_type_addr_list2string(ntal).c_str()); - //Store link address - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) - { - rcv_link_id.addr = i->addr; - rcv_link_id.type = boost::get(i->nettype.link); - } - } - log_(0, ""); - - // - // event subscription - // - // For every interface the MIHF sent in the - // Capability_Discover.response send an Event_Subscribe.request - // for all availabe events - // - if (ntal && evt) { - _subs_evt_list = evt.get(); // save the list of subscribed link events - for (odtone::mih::net_type_addr_list::iterator i = ntal->begin(); i != ntal->end(); i++) { - if (i->nettype.link.which() == 1) - { - odtone::mih::link_tuple_id li; - - li.addr = i->addr; - li.type = boost::get(i->nettype.link); - _link_id_list.push_back(li); // save the link identifier of the network interface - - mih_user::send_MIH_Event_Subscribe_request(li, evt.get(), msg.source()); - } - } - } - - log_(0, "MIH_Capability_Discover.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Subscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt, odtone::mih::id dest) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_subscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(dest); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Subscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Subscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Subscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Subscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Subscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Subscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - //mih_user::send_MIH_Link_Actions_request(link, odtone::mih::link_ac_type_link_activate_resources); - //log_(0, "TEMP : Resource scenario deactivated\n"); - - log_(0, "MIH_Event_Subscribe.confirm - End\n"); -// - - if (link.type == odtone::mih::link_type_lte) - mih_user::send_MIH_Link_Action_Power_Up_plus_scan_request(link); - -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(void) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id li; - - // For every interface the MIH user received in the - // Capability_Discover.confirm, send an Event_Unsubscribe.request - // for all subscribed events - for (odtone::mih::link_id_list::iterator i = _link_id_list.begin(); i != _link_id_list.end(); i++) { - li.type = i->type; - li.addr = i->addr; - mih_user::send_MIH_Event_Unsubscribe_request(li, _subs_evt_list); - } -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Event_Unsubscribe_request(odtone::mih::link_tuple_id& li, odtone::mih::mih_evt_list& evt) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - - m << odtone::mih::request(odtone::mih::request::event_unsubscribe) - & odtone::mih::tlv_link_identifier(li) - & odtone::mih::tlv_event_list(evt); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Event_Unsubscribe.request"+ - "\\nLink="+link_id2string(li).c_str()+ - "\\nEvent list="+evt2string(evt).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Event_Unsubscribe.request to ", m.destination().to_string()); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(li).c_str()); - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt).c_str(), "\n"); - - log_(0, "MIH_Event_Unsubscribe.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Event_Unsubscribe_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Event_Unsubscribe.confirm(", msg.tid(), ") - RECEIVED - Begin\n"); - - odtone::mih::status st; - odtone::mih::link_tuple_id link; - boost::optional evt; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_event_list(evt); - - if (evt) { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - "\\nEvent list="+evt2string(evt.get()).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } else { - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Event_Unsubscribe.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - "\\nLink="+link_id2string(link).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - } - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - if (evt) { - log_(0, " - MIH_EVT_LIST - Event List: ", evt2string(evt.get()).c_str()); - } - log_(0, ""); - - log_(0, "MIH_Event_Unsubscribe.confirm - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Actions_request(const odtone::mih::link_id& link, odtone::mih::link_ac_type type) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::link_action_list lal; - odtone::mih::link_action_req link_act_req; - - link_act_req.id = link; - link_act_req.action.type = type; - - _last_link_action_type = type; - - // Initialize resource parameters - odtone::mih::resource_desc res; - - res.lid = link; // Link identifier - res.data_rate = 128000; // bit rate - res.jumbo = false; // jumbo disable - res.multicast = false; // multicast disable - - odtone::mih::qos qos; // Class Of Service - qos.value = 56; - res.qos_val = qos; - res.fid = 555 + _current_link_action_request; - -// // Flow identifier -// res.fid.src.ip = _mihf_ip; -// res.fid.src.port_val = _mihf_lport; -// -// if (mih_user::_current_link_action_request == 0) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9150"); -// } -// else if (mih_user::_current_link_action_request == 1) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9151"); -// } -// else if (mih_user::_current_link_action_request == 2) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "FF3E:0020:2001:0DB8:0000:0000:0000:0043"); -// res.multicast = true; -// } -// else if (mih_user::_current_link_action_request == 3) { -// res.fid.dst.ip = odtone::mih::ip_addr(odtone::mih::ip_addr::ipv6, -// "2001:0660:0382:0014:0335:0600:8014:9153"); -// } -// res.fid.dst.port_val = 1235; // DUMMY -// res.fid.transport = odtone::mih::proto_udp; - - link_act_req.action.param.param = res; - - link_act_req.ex_time = 0; - - lal.push_back(link_act_req); - - m << odtone::mih::request(odtone::mih::request::link_actions) - & odtone::mih::tlv_link_action_list(lal); - m.source(_mihuserid); - m.destination(_mihfid); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ m.source().to_string() +"][--- MIH_Link_Actions.request\\n"+link_actions_req2string(link_act_req)+" --->]["+m.destination().to_string()+"]\n"); - - _mihf.async_send(m, boost::bind(&mih_user::receive_handler, this, _1, _2)); - - log_(0, "MIH-User has sent Link_Actions.request to ", m.destination().to_string()); - log_(0, " - LINK_ID - Link identifier: ", link_id2string(link).c_str()); - log_(0, " - FLOW_ID - Flow identifier: ", res.fid); -//TEMP log_(0, " - FLOW_ID - Flow identifier: ", flow_id2string(link_act_req.action.param).c_str()); - log_(0, " - LINK_ACTIONS - Link Actions: " + link_actions_req2string(link_act_req) + "\n"); - - log_(0, "MIH_Link_Actions.request - SENT\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Actions_confirm(odtone::mih::message& msg) -//----------------------------------------------------------------------------- -{ - log_(0, "MIH_Link_Actions.confirm - RECEIVED - Begin\n"); - - odtone::mih::status st; - boost::optional larl; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_action_rsp_list(larl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Actions.confirm"+ - "\\nstatus="+status2string(st).c_str()+ - " --->]["+msg.destination().to_string()+"]\n"); - - // Display message parameters - log_(0, " - STATUS: ", status2string(st).c_str(), " (", st.get(), ")"); - if (larl) { - log_(0, " - LINK ACTION RSP LIST - Length:", larl.get().size()); - for (odtone::mih::link_action_rsp_list::iterator i = larl->begin(); i != larl->end(); i++) - { - log_(0, "\tLINK_ID: ", link_id2string(i->id).c_str(), - ", LINK_AC_RESULT: ", link_ac_result2string(i->result).c_str()); - } - } - log_(0, ""); - - // 1st scenario: Sequentially activate and deactivate each resource -#ifdef SCENARIO_1 - if (larl){ - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - if (rsp->result.get() == odtone::mih::link_ac_success) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - _current_link_action_request += 1; - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_1 - -#ifdef SCENARIO_2 - // 2nd scenario: Activate all resources, then deactivate all resources - if (larl.get().size() > 0) { - odtone::mih::link_action_rsp *rsp = &larl->front(); - if (++_current_link_action_request < _nb_of_link_action_requests) { - if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_activate_resources); - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_deactivate_resources) { - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - } - else if (_last_link_action_type == odtone::mih::link_ac_type_link_activate_resources) { - _current_link_action_request = 0; - mih_user::send_MIH_Link_Actions_request(rsp->id, odtone::mih::link_ac_type_link_deactivate_resources); - } - else { // Ends the scenario - mih_user::send_MIH_Event_Unsubscribe_request(); - } - } -#endif // SCENARIO_2 - - log_(0, "MIH_Link_Actions.confirm - End\n"); -} - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Parameters_Report(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - msg >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, ""); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lprl.size()); - log_(0, "MIH_Link_Parameters_Report.indication - RECEIVED - Begin"); - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Parameters_Report.indication --->]["+msg.destination().to_string()+"]\n"); - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(link).c_str()); - for (odtone::mih::link_param_rpt_list::iterator i=lprl.begin(); i!=lprl.end(); i++) - { - log_(0, "Meausrement Type: --- 0 => RSRP ----- 1=>RSRQ ", i->param.type); - if(odtone::mih::link_param_val *value = boost::get(&i->param.value)) - { - log_(0, "Meausrement Value: ", (short) *value /*- 65536*/); - } - } - log_(0, "MIH_Link_Parameters_Report.indication - End"); -} - -void mih_user::forward_Parameters_Report_indication(odtone::mih::message& m) -{ - - odtone::mih::link_tuple_id link; - odtone::mih::link_param_rpt_list lprl; - - log_(0, "Forward_Parameters_Report.indication - Start"); - - m >> odtone::mih::indication() - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - odtone::mih::message msg; - msg.source(_mihuserid); - odtone::mih::id mid_enb; - mid_enb.assign("mihf4_enb"); - msg.destination(mid_enb); - - - msg << odtone::mih::request(odtone::mih::request::mn_ho_candidate_query) - & odtone::mih::tlv_link_identifier(link) - & odtone::mih::tlv_link_param_rpt_list(lprl); - - log_(0, "[MSC_MSG] ["+getTimeStamp4Log()+"]["+msg.source().to_string()+"][-------- Forward MIH_User_Parameters.indication ---->]["+msg.destination().to_string()+"]\n"); - - _mihf.async_send(msg, boost::bind(&mih_user::event_handler, this, _1, _2)); - log_(0, "Forward_Parameters_Report.indication - End"); -} - -//----------------------------------------------------------------------------- -void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - odtone::mih::message m; - odtone::mih::threshold th1; - std::vector thl1; - odtone::mih::threshold th2; - std::vector thl2; - odtone::mih::threshold th3; - std::vector thl3; - odtone::mih::link_tuple_id lti; - odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; - //List of the link threshold parameters - odtone::mih::link_cfg_param_list lcpl; - odtone::mih::link_cfg_param lcp1; - odtone::mih::link_cfg_param lcp2; - odtone::mih::link_cfg_param lcp3; - odtone::mih::link_param_lte lp1; - odtone::mih::link_param_lte lp2; - odtone::mih::link_param_lte lp3; - //odtone::mih::link_param_gen lp; - - odtone::mih::link_param_type typr; - - log_(0,""); - log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); - - //link_tuple_id - lti.type = rcv_link_id.type; - lti.addr = rcv_link_id.addr; - - //local_l2_3gpp_addr = boost::get(lti.addr); - - //link_param_gen_data_rate = 0, /**< Data rate. */ - //link_param_gen_signal_strength = 1, /**< Signal strength. */ - //link_param_gen_sinr = 2, /**< SINR. */ - //link_param_gen_throughput = 3, /**< Throughput. */ - //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ - //lp = odtone::mih::link_param_lte_bandwidth; - lp1 = odtone::mih::link_param_lte_rsrp; - lp2 = odtone::mih::link_param_lte_rsrq; - lp3 = odtone::mih::link_param_lte_cqi; - lcp1.type = lp1; - lcp2.type = lp2; - lcp3.type = lp3; - - link_measures_request = 0; - if (link_measures_request ==0){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 3000; - lcp2.timer_interval = 3000; - lcp3.timer_interval = 3000; - //th_action_normal = 0, /**< Set normal threshold. */ - //th_action_one_shot = 1, /**< Set one-shot threshold. */ - //th_action_cancel = 2 /**< Cancel threshold. */ - lcp1.action = odtone::mih::th_action_normal; - lcp2.action = odtone::mih::th_action_normal; - lcp3.action = odtone::mih::th_action_normal; - link_measures_request = 1; - } else if ( link_measures_request==1){ - // Set Timer Interval (in ms) - lcp1.timer_interval = 0; - lcp2.timer_interval = 0; - lcp3.timer_interval = 0; - lcp1.action = odtone::mih::th_action_cancel; - lcp2.action = odtone::mih::th_action_cancel; - lcp3.action = odtone::mih::th_action_cancel; - link_measures_request = 0; - } - - //above_threshold = 0, /**< Above threshold. */ - //below_threshold = 1, /**< Below threshold. */ - th1.threshold_val = -105; - th1.threshold_x_dir = odtone::mih::threshold::above_threshold; - th2.threshold_val = -19; - th2.threshold_x_dir = odtone::mih::threshold::above_threshold; - th3.threshold_val = 0; - th3.threshold_x_dir = odtone::mih::threshold::above_threshold; - - thl1.push_back(th1); - thl2.push_back(th2); - thl3.push_back(th3); - lcp1.threshold_list = thl1; - lcp2.threshold_list = thl2; - lcp3.threshold_list = thl3; - - lcpl.push_back(lcp1); - lcpl.push_back(lcp2); - lcpl.push_back(lcp3); - - m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_param_list(lcpl); - - m.destination(msg.source()); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ - // link_tupple_id2string(lti).c_str() + - link_id2string(lti).c_str()+ - " --->]["+m.destination().to_string()+"]\n"); - _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); - - - log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); - - log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); - - //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} - //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} - //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} - //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} - //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} - if(lp1 == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} - if(lp2 == odtone::mih::link_param_lte_rsrq) {log_(0, "\t LTE link parameter LTE RSRQ");} - log_(0, "\t- TIMER INTERVAL - Value: ", lcp1.timer_interval); - - if(lcp1.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} - if(lcp1.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} - if(lcp1.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} - - log_(0, "\t Threshold value: ", (short) th1.threshold_val); - - if(th1.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} - if(th1.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} - - log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -} - -// //----------------------------------------------------------------------------- -// void mih_user::send_MIH_Link_Configure_Thresholds_request(odtone::mih::message& msg, const boost::system::error_code& ec) -// //----------------------------------------------------------------------------- -// { -// odtone::mih::message m; -// odtone::mih::threshold th; -// std::vector thl; -// odtone::mih::link_tuple_id lti; -// odtone::mih::l2_3gpp_addr local_l2_3gpp_addr; -// //List of the link threshold parameters -// odtone::mih::link_cfg_param_list lcpl; -// odtone::mih::link_cfg_param lcp; -// odtone::mih::link_param_lte lp; -// //odtone::mih::link_param_gen lp; -// -// odtone::mih::link_param_type typr; -// -// log_(0,""); -// log_(0, "send_MIH_Link_Configure_Thresholds_request - Begin"); -// -// //link_tuple_id -// lti.type = rcv_link_id.type; -// lti.addr = rcv_link_id.addr; -// -// //local_l2_3gpp_addr = boost::get(lti.addr); -// -// -// //link_param_gen_data_rate = 0, /**< Data rate. */ -// //link_param_gen_signal_strength = 1, /**< Signal strength. */ -// //link_param_gen_sinr = 2, /**< SINR. */ -// //link_param_gen_throughput = 3, /**< Throughput. */ -// //link_param_gen_packet_error_rate = 4, /**< Packet error rate. */ -// //lp = odtone::mih::link_param_lte_bandwidth; -// lp = odtone::mih::link_param_lte_rsrp; -// lcp.type = lp; -// -// link_measures_request = 0; -// if ( link_measures_request ==0){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 3000; -// //th_action_normal = 0, /**< Set normal threshold. */ -// //th_action_one_shot = 1, /**< Set one-shot threshold. */ -// //th_action_cancel = 2 /**< Cancel threshold. */ -// lcp.action = odtone::mih::th_action_normal; -// link_measures_request = 1; -// } else if ( link_measures_request==1){ -// // Set Timer Interval (in ms) -// lcp.timer_interval = 0; -// lcp.action = odtone::mih::th_action_cancel; -// link_measures_request = 0; -// } -// -// //above_threshold = 0, /**< Above threshold. */ -// //below_threshold = 1, /**< Below threshold. */ -// th.threshold_val = -105; -// th.threshold_x_dir = odtone::mih::threshold::above_threshold; -// -// thl.push_back(th); -// lcp.threshold_list = thl; -// lcpl.push_back(lcp); -// -// m << odtone::mih::request(odtone::mih::request::link_configure_thresholds) -// & odtone::mih::tlv_link_identifier(lti) -// & odtone::mih::tlv_link_cfg_param_list(lcpl); -// -// m.destination(msg.source()); -// -// log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ _mihuserid.to_string() +"][--- MIH_Link_Configure_Thresholds.request\\nlink="+ -// // link_tupple_id2string(lti).c_str() + -// link_id2string(lti).c_str()+ -// " --->]["+_mihfid.to_string()+"]\n"); -// -// _mihf.async_send(m, boost::bind(&mih_user::event_handler, this, _1, _2)); -// -// log_(0, " - LINK_TUPLE_ID - Link identifier: ", link_id2string(lti).c_str()); -// -// log_(0, "\t- LINK CFG PARAM LIST - Length: ", lcpl.size()); -// -// //if(lp == odtone::mih::link_param_gen_data_rate) {log_(0, "\t Generic link parameter DATA RATE ");} -// //if(lp == odtone::mih::link_param_gen_signal_strength) {log_(0, "\t Generic link parameter SIGNAL STRENGTH");} -// //if(lp == odtone::mih::link_param_gen_sinr) {log_(0, "\t Generic link parameter SINR");} -// //if(lp == odtone::mih::link_param_gen_throughput) {log_(0, "\t Generic link parameter THROUGHPUT");} -// //if(lp == odtone::mih::link_param_lte_bandwidth) {log_(0, "\t LTE link parameter BANDWIDTH");} -// if(lp == odtone::mih::link_param_lte_rsrp) {log_(0, "\t LTE link parameter LTE RSRP");} -// -// log_(0, "\t- TIMER INTERVAL - Value: ", lcp.timer_interval); -// -// if(lcp.action == odtone::mih::th_action_normal) {log_(0, "\t Normal Threshold");} -// if(lcp.action == odtone::mih::th_action_one_shot) {log_(0, "\t One Shot Threshold");} -// if(lcp.action == odtone::mih::th_action_cancel) {log_(0, "\t Threshold to be canceled");} -// -// log_(0, "\t Threshold value: ", th.threshold_val); -// -// if(th.threshold_x_dir == odtone::mih::threshold::below_threshold) {log_(0, "\t Threshold direction BELOW");} -// if(th.threshold_x_dir == odtone::mih::threshold::above_threshold) {log_(0, "\t Threshold direction ABOVE");} -// -// log_(0, "send_MIH_Link_Configure_Thresholds_request - End"); -// } - -//----------------------------------------------------------------------------- -void mih_user::receive_MIH_Link_Configure_Thresholds_confirm(odtone::mih::message& msg, const boost::system::error_code& ec) -//----------------------------------------------------------------------------- -{ - log_(0, ""); - log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - Begin"); - - odtone::uint iter; - odtone::mih::status st; - - //boost::optional lcsl; - odtone::mih::link_cfg_status_list lcsl; - odtone::mih::link_cfg_status lcp; - odtone::mih::link_param_gen lp; - - odtone::mih::link_tuple_id lti; - - msg >> odtone::mih::confirm() - & odtone::mih::tlv_status(st) - & odtone::mih::tlv_link_identifier(lti) - & odtone::mih::tlv_link_cfg_status_list(lcsl); - - log_(0, "[MSC_MSG]["+getTimeStamp4Log()+"]["+ msg.source().to_string() +"][--- MIH_Link_Configure_Thresholds.confirm\\nstatus="+status2string(st.get()).c_str()+" --->]["+_mihuserid.to_string()+"]\n"); - log_(0, "\t- STATUS: ", status2string(st.get()), " " ,st.get()); - - log_(0, "\t- LINK CFG STATUS LIST - Length: ", lcsl.size()); - - for(iter=0; iter lcsl; -// // Todtone::mih::link_cfg_status_list lcsl; -// // Todtone::mih::link_cfg_status lcp; -// //odtone::mih::link_param_gen lp; -// -// // T odtone::mih::link_tuple_id lti; -// -// //msg >> odtone::mih::confirm() -// // & odtone::mih::tlv_status(st) -// // & odtone::mih::tlv_link_identifier(lti) -// // & odtone::mih::tlv_link_cfg_status_list(lcsl); -// -// -// log_(0, "receive_MIH_Link_Configure_Thresholds_confirm - End"); -// log_(0,""); -// } - -//----------------------------------------------------------------------------- -int main(int argc, char** argv) -//----------------------------------------------------------------------------- -{ - odtone::setup_crash_handler(); - - try { - boost::asio::io_service ios; - - // declare MIH Usr available options - po::options_description desc(odtone::mih::octet_string("MIH Usr Configuration")); - desc.add_options() - ("help", "Display configuration options") - (odtone::sap::kConf_File, po::value()->default_value("ue2_user.conf"), "Configuration file") - (odtone::sap::kConf_Receive_Buffer_Len, po::value()->default_value(4096), "Receive buffer length") - (odtone::sap::kConf_Port, po::value()->default_value(1635), "Listening port") - (odtone::sap::kConf_MIH_SAP_id, po::value()->default_value("user"), "MIH-User ID") - (kConf_MIH_Commands, po::value()->default_value(""), "MIH-User supported commands") - (odtone::sap::kConf_MIHF_Ip, po::value()->default_value("127.0.0.1"), "Local MIHF IP address") - (odtone::sap::kConf_MIHF_Local_Port, po::value()->default_value(1025), "Local MIHF communication port") - (odtone::sap::kConf_MIH_SAP_dest, po::value()->default_value("mihf3_ue"), "MIHF destination"); - - odtone::mih::config cfg(desc); - cfg.parse(argc, argv, odtone::sap::kConf_File); - - if (cfg.help()) { - std::cerr << desc << std::endl; - return EXIT_SUCCESS; - } - - mih_user usr(cfg, ios); - - ios.run(); - - } catch(std::exception& e) { - log_(0, "exception: ", e.what()); - } -} - -// EOF //////////////////////////////////////////////////////////////////////// - diff --git a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/oai_conf/start_ue.bash b/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/oai_conf/start_ue.bash deleted file mode 100644 index 0052bd3352..0000000000 --- a/targets/PROJECTS/SPECTRA/DEMO_SPECTRA/spectra_demo_src/ue2/oai_conf/start_ue.bash +++ /dev/null @@ -1,208 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_ue.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth5" -declare -x EMULATION_DEV_ADDRESS="192.168.15.5" - -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x UE_IPv4="10.0.2.3" -declare -x UE_IPv6="2001:2::3" -declare -x UE_IPv6_CIDR=$UE_IPv6"/64" -declare -x UE_IPv4_CIDR=$UE_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 7 3 0 2 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 - -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x UE_MIHF_IP_ADDRESS="127.0.0.1" -declare -x UE_RAL_IP_ADDRESS="127.0.0.1" -LOG_FILE="/tmp/oai_sim_ue.log" - -#------------------------------------------------ -MIH_LOG_FILE="mih-f_ue.log" - -# EXE options -EXE_MODE="DEBUG" # "PROD" or "DEBUG" - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "service network-manager stop" -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -bash_exec "ifconfig eth0 up 192.168.14.4 netmask 255.255.255.0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - - -################################################## -# LAUNCH UE -################################################## - -echo "Bringup UE interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $UE_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -bash_exec "ip link set $LTEIF up" -sleep 1 -bash_exec "ip addr add dev $LTEIF $UE_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $UE_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip -4 route add default dev $LTEIF table lte -ip -6 route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - -echo "printing the MIH file path" -echo "$ODTONE_MIH_EXE_DIR/$MIH_F $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE" -echo "$ODTONE_MIH_EXE_DIR/$UE_MIH_USER $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE" - -# start MIH-F -xterm -hold -title "[RELAY][UE] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F -sleep 3 - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -UE_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LINK_ID=`trim2 $UE_RAL_LINK_ID` -UE_RAL_LINK_ID=`echo $UE_RAL_LINK_ID | cut -d" " -f1` -UE_RAL_LINK_ID_STRIPPED=${UE_RAL_LINK_ID%%??} - -UE_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LISTENING_PORT=`trim2 $UE_RAL_LISTENING_PORT` -UE_RAL_LISTENING_PORT=`echo $UE_RAL_LISTENING_PORT | cut -d" " -f2` - -UE_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -UE_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -#xterm -hold -e gdb --args -# $EMULATION_DEV_INTERFACE -D192.168.13.2 -#sudo ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE -#$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/rb_tool -a -c0 -i0 -z0 -s 10.0.0.2 -t 10.0.0.1 -r 1 - -if [ $EXE_MODE = "DEBUG" ] ; then - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_INTERFACE \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > log_ue.txt & -else - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -l3 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_INTERFACE \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > /dev/null & - -fi - -wait_process_started oaisim - - -# start MIH-USER - -# wait for emulation start -tshark -c 500 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -sleep 5 - -xterm -hold -title "[RELAY][UE] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$UE_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE & -wait_process_started $UE_MIH_USER - -sleep 100000 - - - - diff --git a/targets/PROJECTS/SPECTRA/build_all.bash b/targets/PROJECTS/SPECTRA/build_all.bash deleted file mode 100755 index 688342049a..0000000000 --- a/targets/PROJECTS/SPECTRA/build_all.bash +++ /dev/null @@ -1,122 +0,0 @@ -#! /bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file build_all.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### - -echo_success "\n###############################" -echo_success "# Check installed utils and libs" -echo_success "###############################" -test_command_install_package "gccxml" "gccxml" "--force-yes" -test_command_install_package "iptables" "iptables" -#test_command_install_package "ebtables" "ebtables" "--force-yes" -test_command_install_package "ip" "iproute" -test_install_package "openssl" -test_install_package "libblas-dev" -# for itti analyser -test_install_package "libgtk-3-dev" -test_install_package "libxml2" -test_install_package "libxml2-dev" -test_install_package "libforms-bin" "--force-yes" -test_install_package "libforms-dev" -test_install_package "libatlas-dev" -test_install_package "libatlas-base-dev" -test_install_package "libpgm-5.1-0" "--force-yes" -test_install_package "libpgm-dev" "--force-yes" -test_install_package linux-headers-`uname -r` -test_install_package "tshark" "--force-yes" -# for ODTONE git clone -test_install_package "git" - -test_install_asn1c_4_rrc_cellular - - -echo_success "\n###############################" -echo_success "# COMPILE oaisim" -echo_success "###############################" -cd $OPENAIR_TARGETS/SIMU/USER -#echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo `" -#make --keep-going oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 Rel10=1 -j`grep -c ^processor /proc/cpuinfo ` - -echo_success "Executing: make oaisim NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 -j`grep -c ^processor /proc/cpuinfo `" -#make --keep-going oaisim NAS= -make --keep-going oaisim DEBUG=1 NAS=1 OAI_NW_DRIVER_TYPE_ETHERNET=1 ENABLE_ITTI=1 USER_MODE=1 OPENAIR2=1 ENABLE_RAL=1 MIH_C_MEDIEVAL_EXTENSIONS=1 USE_3GPP_ADDR_AS_LINK_ADDR=1 RLC_STOP_ON_LOST_PDU=1 -j`grep -c ^processor /proc/cpuinfo ` - -if [[ $? -eq 2 ]] ; then - exit 1 -fi - - -echo_success "\n###############################" -echo_success "# COMPILE IP kernel drivers" -echo_success "###############################" -echo_success "Compiling IP Drivers" -cd $OPENAIR2_DIR -make naslite_netlink_ether.ko -cd $OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/ -make - - -echo_success "\n###############################" -echo_success "# COMPILE MIH-F" -echo_success "###############################" -cd $ODTONE_ROOT -b2 --boost-root=$BOOST_ROOT linkflags=-lpthread - - -echo_success "\n###############################" -echo_success "# COMPILE MIH-USER" -echo_success "###############################" -cd $ODTONE_ROOT/app/lte_test_user/ -b2 --boost-root=$BOOST_ROOT linkflags=-lrt linkflags=-lpthread - - -echo_success "\n###############################" -echo_success "# COMPILE ITTI ANALYSER" -echo_success "###############################" -cd $OPENAIR_DIR/common/utils/itti_analyzer -if [ ! -f $OPENAIR_DIR/common/utils/itti_analyzer/Makefile ] - then - autoreconf -i - mkdir -m 777 objs - cd objs - ../configure - fi -sudo make install -j`grep -c ^processor /proc/cpuinfo ` - - - diff --git a/targets/PROJECTS/SPECTRA/enb.conf b/targets/PROJECTS/SPECTRA/enb.conf deleted file mode 100644 index 8acd6d84af..0000000000 --- a/targets/PROJECTS/SPECTRA/enb.conf +++ /dev/null @@ -1,217 +0,0 @@ -Active_eNBs = ( "eNB_Eurecom_LTEBox"); -# Asn1_verbosity, choice in: none, info, annoying -Asn1_verbosity = "none"; - -eNBs = -( - { - # real_time choice in {hard, rt-preempt, no} - real_time = "no"; - ////////// Identification parameters: - eNB_ID = 0xe00; - - cell_type = "CELL_MACRO_ENB"; - - eNB_name = "eNB_Eurecom_LTEBox"; - - // Tracking area code, 0x0000 and 0xfffe are reserved values - tracking_area_code = "1"; - - mobile_country_code = "208"; - - mobile_network_code = "92"; - - ////////// Physical parameters: - - component_carriers = ( - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - # srs_BandwidthConfig =; - # srs_SubframeConfig =; - # srs_ackNackST =; - # srs_MaxUpPts =; - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; - -# rach_sizeOfRA_PreamblesGroupA = ; -# rach_messageSizeGroupA = ; -# rach_messagePowerOffsetGroupB = ; - - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - }, - { - frame_type = "TDD"; - tdd_config = 3; - tdd_config_s = 0; - prefix_type = "NORMAL"; - eutra_band = 33; - downlink_frequency = 1910000000L; - uplink_frequency_offset = 0; - - Nid_cell = 0; - N_RB_DL = 25; - Nid_cell_mbsfn = 0; - nb_antennas_tx = 1; - nb_antennas_rx = 1; - prach_root = 22; - prach_config_index = 3; - prach_high_speed = "DISABLE"; - prach_zero_correlation = 0; - prach_freq_offset = 0; - pucch_delta_shift = 1; - pucch_nRB_CQI = 1; - pucch_nCS_AN = 0; - pucch_n1_AN = 32; - pdsch_referenceSignalPower = -24; - pdsch_p_b = 0; - pusch_n_SB = 1; - pusch_enable64QAM = "DISABLE"; - pusch_hoppingMode = "interSubFrame"; - pusch_hoppingOffset = 4; - pusch_groupHoppingEnabled = "DISABLE"; - pusch_groupAssignment = 0; - pusch_sequenceHoppingEnabled = "DISABLE"; - pusch_nDMRS1 = 1; - phich_duration = "NORMAL"; - phich_resource = "ONESIXTH"; - srs_enable = "DISABLE"; - /* srs_BandwidthConfig =; - srs_SubframeConfig =; - srs_ackNackST =; - srs_MaxUpPts =;*/ - - pusch_p0_Nominal = -95; - pusch_alpha = "AL08"; - pucch_p0_Nominal = -117; - msg3_delta_Preamble = 6; - pucch_deltaF_Format1 = "deltaF2"; - pucch_deltaF_Format1b = "deltaF3"; - pucch_deltaF_Format2 = "deltaF0"; - pucch_deltaF_Format2a = "deltaF0"; - pucch_deltaF_Format2b = "deltaF0"; - - rach_numberOfRA_Preambles = 52; - rach_preamblesGroupAConfig = "DISABLE"; -/* - rach_sizeOfRA_PreamblesGroupA = ; - rach_messageSizeGroupA = ; - rach_messagePowerOffsetGroupB = ; -*/ - rach_powerRampingStep = 2; - rach_preambleInitialReceivedTargetPower = -104; - rach_preambleTransMax = 6; - rach_raResponseWindowSize = 10; - rach_macContentionResolutionTimer = 48; - rach_maxHARQ_Msg3Tx = 4; - - pcch_default_PagingCycle = 128; - pcch_nB = "oneT"; - bcch_modificationPeriodCoeff = 2; - ue_TimersAndConstants_t300 = 1000; - ue_TimersAndConstants_t301 = 1000; - ue_TimersAndConstants_t310 = 1000; - ue_TimersAndConstants_t311 = 10000; - ue_TimersAndConstants_n310 = 20; - ue_TimersAndConstants_n311 = 1; - - } - ); - - ////////// MME parameters: - mme_ip_address = ( { ipv4 = "192.168.13.11"; - ipv6 = "192:168:30::17"; - active = "yes"; - preference = "ipv4"; - } - ); - - NETWORK_INTERFACES : - { - ENB_INTERFACE_NAME_FOR_S1_MME = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.13.10/24"; - - ENB_INTERFACE_NAME_FOR_S1U = "eth1"; - ENB_IPV4_ADDRESS_FOR_S1U = "192.168.13.10/24"; - }; - - log_config : - { - global_log_level ="debug"; - global_log_verbosity ="medium"; - hw_log_level ="debug"; - hw_log_verbosity ="medium"; - phy_log_level ="info"; - phy_log_verbosity ="medium"; - mac_log_level ="debug"; - mac_log_verbosity ="high"; - rlc_log_level ="info"; - rlc_log_verbosity ="medium"; - pdcp_log_level ="info"; - pdcp_log_verbosity ="medium"; - rrc_log_level ="info"; - rrc_log_verbosity ="medium"; - }; - - } -); diff --git a/targets/PROJECTS/SPECTRA/env_802dot21.bash b/targets/PROJECTS/SPECTRA/env_802dot21.bash deleted file mode 100755 index 0c181ed384..0000000000 --- a/targets/PROJECTS/SPECTRA/env_802dot21.bash +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file env_802dot21.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# - -##################################################### -# VARIABLES TO BE FILLED WITH RIGHT VALUES: -##################################################### -export BOOST_ROOT=/home/nikaia/DEMO_SPECTRA/boost_1_49_0/ -export ODTONE_ROOT=/home/nikaia/DEMO_SPECTRA/ODTONE/ - -export MIH_F=odtone-mihf -export ENB_MIH_F_CONF_FILE=odtone_enb.conf -export UE_MIH_F_CONF_FILE=odtone_ue.conf - -export ODTONE_MIH_USER_DIR=$ODTONE_ROOT/app/lte_test_user -export ODTONE_MIH_EXE_DIR=$ODTONE_ROOT/dist - -#export ENB_MIH_USER=enb2_lte_user -#export ENB_MIH_USER_CONF_FILE=enb2_lte_user.conf -export ENB_MIH_USER=enb_lte_user -export ENB_MIH_USER_CONF_FILE=enb_lte_user.conf - -export UE_MIH_USER=ue_lte_user -export UE_MIH_USER_CONF_FILE=ue_lte_user.conf -##################################################### - - -ENV_SCRIPT_SOURCED="?" -ENV_SCRIPT_ERRORS="no" - -if [[ $BASH_SOURCE != $0 ]]; then - THIS_SCRIPT_PATH=${BASH_SOURCE%env_802dot21.bash} - [[ x"$THIS_SCRIPT_PATH" == x ]] && THIS_SCRIPT_PATH="./" - ENV_SCRIPT_SOURCED="yes" -else - THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -fi - -ENV_SCRIPT_STARTED="yes" -source $THIS_SCRIPT_PATH/utils.bash - -if [ -d $ODTONE_ROOT ]; then - echo_success "ODTONE_ROOT = $ODTONE_ROOT." >&2 -else - echo_error "ODTONE_ROOT variable was not set correctly, please update ($ODTONE_ROOT)." >&2 -fi -if [ ! -d $BOOST_ROOT ]; then - echo_error "BOOST_ROOT variable was not set correctly, please update (may be you also need to install boost), exiting." - ENV_SCRIPT_ERRORS="yes" -else - command -v b2 >/dev/null 2>&1 - if [ $? -ne 0 ]; then - echo_warning "Program b2 is not installed or not in the PATH variable. Trying to resolve..." >&2 - if [[ -x "$BOOST_ROOT/b2" ]]; then - echo_success "Program b2 found in dir $BOOST_ROOT." >&2 - export PATH=$PATH:$BOOST_ROOT - else - echo_warning "Program b2 not found in dir $BOOST_ROOT. Trying to install..." >&2 - cd $BOOST_ROOT; ./bootstrap.sh; - cd - - export PATH=$PATH:$BOOST_ROOT - fi - command -v $BOOST_ROOT/b2 >/dev/null 2>&1 - if [ $? -eq 0 ]; then - echo_success "Program b2 is now reachable by the PATH variable during the execution of this script." >&2 - else - echo_error "Built of b2 failed. Please help yourself" >&2 - fi - fi -fi - - -if [ ! -d $ODTONE_ROOT ]; then - echo_error "ODTONE_ROOT variable was not set correctly, please update (may be you also need to install odtone), exiting." - ENV_SCRIPT_ERRORS="yes" -fi - - -[[ x"$ENV_SCRIPT_ERRORS" == "xyes" ]] && [[ x"$ENV_SCRIPT_SOURCED" == "xyes" ]] && return 1 -[[ x"$ENV_SCRIPT_ERRORS" == "xyes" ]] && [[ x"$ENV_SCRIPT_SOURCED" == "xno" ]] && exit 1 - diff --git a/targets/PROJECTS/SPECTRA/libcrmclient.so b/targets/PROJECTS/SPECTRA/libcrmclient.so deleted file mode 120000 index 6d8d7fc711..0000000000 --- a/targets/PROJECTS/SPECTRA/libcrmclient.so +++ /dev/null @@ -1 +0,0 @@ -libcrmclient.so.1.0 \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/libcrmclient.so.1 b/targets/PROJECTS/SPECTRA/libcrmclient.so.1 deleted file mode 120000 index 6d8d7fc711..0000000000 --- a/targets/PROJECTS/SPECTRA/libcrmclient.so.1 +++ /dev/null @@ -1 +0,0 @@ -libcrmclient.so.1.0 \ No newline at end of file diff --git a/targets/PROJECTS/SPECTRA/libcrmclient.so.1.0 b/targets/PROJECTS/SPECTRA/libcrmclient.so.1.0 deleted file mode 100755 index de5d84398b..0000000000 Binary files a/targets/PROJECTS/SPECTRA/libcrmclient.so.1.0 and /dev/null differ diff --git a/targets/PROJECTS/SPECTRA/loadcasablancalib b/targets/PROJECTS/SPECTRA/loadcasablancalib deleted file mode 100755 index 1b968dfef5..0000000000 --- a/targets/PROJECTS/SPECTRA/loadcasablancalib +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -export LD_LIBRARY_PATH=/usr/local/lib/:/usr/lib/:/opt/casablanca/Binaries/Release32 diff --git a/targets/PROJECTS/SPECTRA/start_enb.bash b/targets/PROJECTS/SPECTRA/start_enb.bash deleted file mode 100755 index 23d02bd58b..0000000000 --- a/targets/PROJECTS/SPECTRA/start_enb.bash +++ /dev/null @@ -1,196 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_enb.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# ENB CONFIG FILE -#------------------------------------------------ -#declare -x ENB_CONFIG_FILE="CONF/enb.sfr.yang.conf" -declare -x ENB_CONFIG_FILE="enb.conf" - -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth1" -declare -x EMULATION_DEV_ADDRESS="192.168.13.1" -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x ENB_IPv4="10.0.0.1" -declare -x ENB_IPv6="2001:1::1" -declare -x ENB_IPv6_CIDR=$ENB_IPv6"/64" -declare -x ENB_IPv4_CIDR=$ENB_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 6 2 0 0 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x ENB_RAL_IP_ADDRESS="127.0.0.1" -declare -x ENB_MIHF_IP_ADDRESS=127.0.0.1 -MIH_LOG_FILE="mih-f_enb.log" - -#------------------------------------------------ -LOG_FILE="/tmp/oai_sim_enb.log" - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -bash_exec "ifconfig eth2 up 192.168.14.3 netmask 255.255.255.0" -bash_exec "ip r d default via 192.168.14.4 dev eth2" -bash_exec "ip r a default via 192.168.12.100 dev eth0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - -bash_exec "/sbin/iptables -t mangle -F" -bash_exec "/sbin/iptables -t nat -F" -bash_exec "/sbin/iptables -t raw -F" -bash_exec "/sbin/iptables -t filter -F" -bash_exec "/sbin/ip6tables -t mangle -F" -bash_exec "/sbin/ip6tables -t filter -F" -bash_exec "/sbin/ip6tables -t raw -F" - -################################################## -# LAUNCH eNB executable -################################################## - -echo "Bringup eNB interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $ENB_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -bash_exec "ip link set $LTEIF up" -sleep 1 -bash_exec "ip addr add dev $LTEIF $ENB_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $ENB_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" -bash_exec "sysctl -w net.ipv4.ip_forward=1" -assert " `sysctl -n net.ipv4.ip_forward` -eq 1" $LINENO - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ebtables -t nat -A POSTROUTING -p arp -j mark --mark-set 3 - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - - -# start MIH-F -xterm -hold -title "[RELAY][eNB1] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -ENB_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LINK_ID=`trim2 $ENB_RAL_LINK_ID` -ENB_RAL_LINK_ID=`echo $ENB_RAL_LINK_ID | cut -d" " -f1` - -ENB_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -ENB_RAL_LISTENING_PORT=`trim2 $ENB_RAL_LISTENING_PORT` -ENB_RAL_LISTENING_PORT=`echo $ENB_RAL_LISTENING_PORT | cut -d" " -f2` - -ENB_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -ENB_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$ENB_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` -#remove 2 last digits (vitualization, index on 2 digits) -ENB_RAL_LINK_ID_STRIPPED=${ENB_RAL_LINK_ID%%??} - -#xterm -hold -e gdb --args -$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l9 -u0 -b1 -M0 -p2 -g1 -D $EMULATION_DEV_INTERFACE \ - --enb-ral-listening-port $ENB_RAL_LISTENING_PORT \ - --enb-ral-link-id $ENB_RAL_LINK_ID_STRIPPED \ - --enb-ral-ip-address $ENB_RAL_IP_ADDRESS \ - --enb-mihf-remote-port $ENB_MIHF_REMOTE_PORT \ - --enb-mihf-ip-address $ENB_MIHF_IP_ADDRESS \ - --enb-mihf-id $ENB_MIHF_ID \ - -O $ENB_CONFIG_FILE > log_enb.txt & -# -O $ENB_CONFIG_FILE | grep "RAL\|PDCP" & - -wait_process_started oaisim - -# start MIH-USER -# wait for emulation start -tshark -c 150 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -sudo xterm -hold -title "[RELAY][eNB1] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$ENB_MIH_USER_CONF_FILE & -wait_process_started $ENB_MIH_USER - -xterm -hold -title "[RELAY][eNB1] CRM Client" -e tail -f outputGET.txt & - -sleep 100000 - - diff --git a/targets/PROJECTS/SPECTRA/start_ue.bash b/targets/PROJECTS/SPECTRA/start_ue.bash deleted file mode 100755 index 77caa99b6c..0000000000 --- a/targets/PROJECTS/SPECTRA/start_ue.bash +++ /dev/null @@ -1,213 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file start_ue.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# -#------------------------------------------------ -# OAI NETWORKING -#------------------------------------------------ -declare -x EMULATION_DEV_INTERFACE="eth2" -declare -x EMULATION_DEV_ADDRESS="192.168.14.3" - -declare -x IP_DRIVER_NAME="oai_nw_drv" -declare -x LTEIF="oai0" -declare -x UE_IPv4="10.0.2.3" -declare -x UE_IPv6="2001:2::3" -declare -x UE_IPv6_CIDR=$UE_IPv6"/64" -declare -x UE_IPv4_CIDR=$UE_IPv4"/24" -declare -a NAS_IMEI=( 3 9 1 8 3 6 7 3 0 2 0 0 0 0 ) -declare -x IP_DEFAULT_MARK="1" # originally 3 - -#------------------------------------------------ -# OAI MIH -#------------------------------------------------ -declare -x UE_MIHF_IP_ADDRESS="192.168.14.3" -declare -x UE_RAL_IP_ADDRESS="192.168.14.3" -LOG_FILE="/tmp/oai_sim_ue.log" - -#------------------------------------------------ -MIH_LOG_FILE="mih-f_ue.log" - -# EXE options -EXE_MODE="DEBUG" # "PROD" or "DEBUG" - -########################################################### -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -source $THIS_SCRIPT_PATH/env_802dot21.bash -########################################################### -bash_exec "service network-manager stop" -bash_exec "ifconfig $EMULATION_DEV_INTERFACE up $EMULATION_DEV_ADDRESS netmask 255.255.255.0" -#bash_exec "ifconfig eth1 up 192.168.57.3 netmask 255.255.255.0" -########################################################### -IPTABLES=/sbin/iptables -THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green - - -################################################## -# LAUNCH UE -################################################## - -echo "Bringup UE interface" -pkill oaisim > /dev/null 2>&1 -pkill oaisim > /dev/null 2>&1 -pkill $MIH_F > /dev/null 2>&1 -pkill $UE_MIH_USER > /dev/null 2>&1 -rmmod -f $IP_DRIVER_NAME > /dev/null 2>&1 - -bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" -bash_exec "ip route flush cache" -#bash_exec "ip link set $LTEIF up" -#sleep 1 -#bash_exec "ip addr add dev $LTEIF $UE_IPv4_CIDR" -#bash_exec "ip addr add dev $LTEIF $UE_IPv6_CIDR" -sleep 1 -bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" -assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO -bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" -assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO -bash_exec "ip route flush cache" - -# Check table 200 lte in /etc/iproute2/rt_tables -fgrep lte /etc/iproute2/rt_tables > /dev/null -if [ $? -ne 0 ]; then - echo '200 lte ' >> /etc/iproute2/rt_tables -fi -ip rule add fwmark $IP_DEFAULT_MARK table lte -ip -4 route add default dev $LTEIF table lte -ip -6 route add default dev $LTEIF table lte -ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE - -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type broadcast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type multicast -j MARK --set-mark $IP_DEFAULT_MARK - -#All other traffic is sent on the RAB you want (mark = RAB ID) -/sbin/ip6tables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/ip6tables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A POSTROUTING -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK -/sbin/iptables -A OUTPUT -t mangle -o oai0 -m pkttype --pkt-type unicast -j MARK --set-mark $IP_DEFAULT_MARK - -rotate_log_file $MIH_LOG_FILE - -echo "printing the MIH file path" -echo "$ODTONE_MIH_EXE_DIR/$MIH_F $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE" -echo "$ODTONE_MIH_EXE_DIR/$UE_MIH_USER $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE" - -# start MIH-F -xterm -hold -title "[RELAY][UE] MIHF" -e $ODTONE_MIH_EXE_DIR/$MIH_F --log 4 --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE > $MIH_LOG_FILE 2>&1 & -wait_process_started $MIH_F -sleep 3 - -NOW=$(date +"%Y-%m-%d.%Hh_%Mm_%Ss") -rm -f $LOG_FILE - -UE_RAL_LINK_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LINK_ID=`trim2 $UE_RAL_LINK_ID` -UE_RAL_LINK_ID=`echo $UE_RAL_LINK_ID | cut -d" " -f1` -UE_RAL_LINK_ID_STRIPPED=${UE_RAL_LINK_ID%%??} - -UE_RAL_LISTENING_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep links | grep \= | grep -v \# | cut -d"=" -f2` -UE_RAL_LISTENING_PORT=`trim2 $UE_RAL_LISTENING_PORT` -UE_RAL_LISTENING_PORT=`echo $UE_RAL_LISTENING_PORT | cut -d" " -f2` - -UE_MIHF_REMOTE_PORT=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep local_port | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -UE_MIHF_ID=`cat $ODTONE_MIH_EXE_DIR/$UE_MIH_F_CONF_FILE | grep id | grep \= | grep -v \# | tr -d " " | cut -d'=' -f2` - -#xterm -hold -e gdb --args -# $EMULATION_DEV_INTERFACE -D192.168.13.2 -#sudo ip route add 239.0.0.160/28 dev $EMULATION_DEV_INTERFACE -#$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/rb_tool -a -c0 -i0 -z0 -s 10.0.0.2 -t 10.0.0.1 -r 1 - -if [ $EXE_MODE = "DEBUG" ] ; then - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -K $LOG_FILE -l7 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_INTERFACE \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > log_ue.txt & - -bash_exec "ip link set $LTEIF up" -bash_exec "ip addr add dev $LTEIF $UE_IPv4_CIDR" -bash_exec "ip addr add dev $LTEIF $UE_IPv6_CIDR" - -else - echo "$OPENAIR_TARGETS/SIMU/USER/oaisim -a -l3 -u1 -b0 -M1 -p2 -g3 -D $EMULATION_DEV_ADDRESS --ue-ral-listening-port $UE_RAL_LISTENING_PORT --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED --ue-ral-ip-address $UE_RAL_IP_ADDRESS --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS --ue-mihf-id $UE_MIHF_ID " - - $OPENAIR_TARGETS/SIMU/USER/oaisim -a -u1 -b0 -M1 -p2 -g1 -D $EMULATION_DEV_INTERFACE \ - --ue-ral-listening-port $UE_RAL_LISTENING_PORT \ - --ue-ral-link-id $UE_RAL_LINK_ID_STRIPPED \ - --ue-ral-ip-address $UE_RAL_IP_ADDRESS \ - --ue-mihf-remote-port $UE_MIHF_REMOTE_PORT \ - --ue-mihf-ip-address $UE_MIHF_IP_ADDRESS \ - --ue-mihf-id $UE_MIHF_ID > /dev/null & - -fi - -wait_process_started oaisim - - -# start MIH-USER - -# wait for emulation start -tshark -c 500 -i $EMULATION_DEV_INTERFACE > /dev/null 2>&1 -sleep 5 - -xterm -hold -title "[RELAY][UE] MIH_USER" -e $ODTONE_MIH_EXE_DIR/$UE_MIH_USER --conf.file $ODTONE_MIH_EXE_DIR/$UE_MIH_USER_CONF_FILE & -wait_process_started $UE_MIH_USER - -sleep 100000 - - - - diff --git a/targets/PROJECTS/SPECTRA/utils.bash b/targets/PROJECTS/SPECTRA/utils.bash deleted file mode 100755 index 821bbfee64..0000000000 --- a/targets/PROJECTS/SPECTRA/utils.bash +++ /dev/null @@ -1,377 +0,0 @@ -#!/bin/bash -################################################################################ -# OpenAirInterface -# Copyright(c) 1999 - 2014 Eurecom -# -# OpenAirInterface is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# -# OpenAirInterface 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 OpenAirInterface.The full GNU General Public License is -# included in this distribution in the file called "COPYING". If not, -# see . -# -# Contact Information -# OpenAirInterface Admin: openair_admin@eurecom.fr -# OpenAirInterface Tech : openair_tech@eurecom.fr -# OpenAirInterface Dev : openair4g-devel@eurecom.fr -# -# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE -# -################################################################################ -# file utils.bash -# brief -# author Lionel Gauthier -# company Eurecom -# email: lionel.gauthier@eurecom.fr -# - -cidr2mask() { - local i mask="" - local full_octets=$(($1/8)) - local partial_octet=$(($1%8)) - - for ((i=0;i<4;i+=1)); do - if [ $i -lt $full_octets ]; then - mask+=255 - elif [ $i -eq $full_octets ]; then - mask+=$((256 - 2**(8-$partial_octet))) - else - mask+=0 - fi - test $i -lt 3 && mask+=. - done - - echo $mask -} - - -black='\E[30m' -red='\E[31m' -green='\E[32m' -yellow='\E[33m' -blue='\E[34m' -magenta='\E[35m' -cyan='\E[36m' -white='\E[37m' -reset_color='\E[00m' - -ROOT_UID=0 -E_NOTROOT=67 - -HOSTNAME=$(hostname -f) - -trim () -{ - echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' -} - -trim2() -{ - local var=$@ - var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters - var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters - echo -n "$var" -} - -cecho() # Color-echo -# arg1 = message -# arg2 = color -{ - local default_msg="No Message." - message=${1:-$default_msg} - color=${2:-$green} - echo -e -n "$color$message$reset_color" - echo - return -} - -echo_error() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $red -} - -echo_warning() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $yellow -} - -echo_success() { - local my_string="" - until [ -z "$1" ] - do - my_string="$my_string$1" - shift - done - cecho "$my_string" $green -} - -bash_exec() { - output=$($1 2>&1) - result=$? - if [ $result -eq 0 ] - then - echo_success "$1" - else - echo_error "$1: $output" - fi -} - - -extract() { - if [ -f $1 ] ; then - case $1 in - *.tar.bz2) tar xvjf $1 ;; - *.tar.gz) tar xvzf $1 ;; - *.bz2) bunzip2 $1 ;; - *.rar) unrar $1 ;; - *.gz) gunzip $1 ;; - *.tar) tar xvf $1 ;; - *.tbz2) tar xvjf $1 ;; - *.tgz) tar xvzf $1 ;; - *.zip) unzip $1 ;; - *.Z) uncompress $1 ;; - *.7z) 7z x $1 ;; - *) echo_error "'$1' cannot be extracted via >extract<" ; return 1;; - esac - else - echo_error "'$1' is not a valid file" - return 1 - fi - return 0 -} - - -set_openair() { - path=`pwd` - declare -i length_path - declare -i index - length_path=${#path} - - for i in 'openair1' 'openair2' 'openair3' 'openair-cn' 'targets' - do - index=`echo $path | grep -b -o $i | cut -d: -f1` - #echo ${path%$token*} - if [[ $index -lt $length_path && index -gt 0 ]] - then - declare -x OPENAIR_DIR - index=`expr $index - 1` - openair_path=`echo $path | cut -c1-$index` - #openair_path=`echo ${path:0:$index}` - export OPENAIR_DIR=$openair_path - export OPENAIR1_DIR=$openair_path/openair1 - export OPENAIR2_DIR=$openair_path/openair2 - export OPENAIR3_DIR=$openair_path/openair3 - export OPENAIRCN_DIR=$openair_path/openair-cn - export OPENAIR_TARGETS=$openair_path/targets - return 0 - fi - done - return -1 -} - -test_install_asn1c_4_rrc_cellular() { - if [ -d $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c ]; then - if [ -x $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c/asn1c/asn1c ]; then - if [ -x /usr/local/bin/asn1c ]; then - diff /usr/local/bin/asn1c $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c/asn1c/asn1c >/dev/null 2>&1; - if [ $? -eq 0 ]; then - echo_success "asn1c for RRC cellular installed" - return 0 - fi - fi - echo_warning "Installing asn1c for RRC cellular..." - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c - make install - return 0 - fi - else - echo_warning "asn1c for RRC cellular is not installed in $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/. Installing it" - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c - svn co https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk asn1c - fi - echo_warning "Configuring and building and installing asn1c for RRC cellular..." - cd $OPENAIR2_DIR/RRC/LITE/MESSAGES/asn1c/asn1c - ./configure - make - make install -} - -wait_process_started () { - if [ -z "$1" ] - then - echo_error "WAITING FOR PROCESS START: NO PROCESS" - return 1 - fi - ps -C $1 > /dev/null 2>&1 - while [ $? -ne 0 ]; do - echo_warning "WAITING FOR $1 START" - sleep 2 - ps -C $1 > /dev/null 2>&1 - done - echo_success "PROCESS $1 STARTED" - return 0 -} - -is_process_started () { - if [ -z "$1" ] - then - echo_error "WAITING FOR PROCESS START: ERROR NO PROCESS NAME IN ARGUMENT" - return 1 - fi - ps -C $1 > /dev/null 2>&1 - if [ $? -ne 0 ] - then - echo_success "PROCESS $1 NOT STARTED" - return 1 - fi - echo_success "PROCESS $1 STARTED" - return 0 -} - -assert() { - # If condition false - # exit from script with error message - E_PARAM_ERR=98 - E_PARAM_FAILED=99 - - if [ -z "$2" ] # Not enought parameters passed. - then - return $E_PARAM_ERR - fi - - lineno=$2 - if [ ! $1 ] - then - echo "Assertion failed: \"$1\"" - echo "File \"$0\", line $lineno" - exit $E_ASSERT_FAILED - fi -} - - -test_install_package() { - # usage: test_install_package package_name_to_be_installed optional_option_to_apt_get_install - dpkg --get-selections $1 | grep -i install > /dev/null 2>&1 - if [ $? -ne 0 ]; then - echo_warning "Package $1 is not installed. Installing it." >&2 - apt-get install $2 $1 -y - dpkg --get-selections $1 | grep -i install > /dev/null 2>&1 - if [ $? -ne 0 ]; then - exit 1 - fi - else - echo_success "$1 is installed" - fi - return 0 -} - - - -test_command_install_package() { - # usage: test_command_install_package searched_binary package_to_be_installed_if_binary_not_found optional_option_to_apt_get_install - if [ $# -eq 2 ]; then - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it." >&2; apt-get install $2 -y; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - else - if [ $# -eq 3 ]; then - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it (apt-get install $3 $2)." >&2; apt-get install $3 $2 -y; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - else - echo_success "test_command_install_package: BAD PARAMETER" - exit 1 - fi - fi - echo_success "$1 available" -} - -test_command_install_script() { - # usage: test_command_install_script searched_binary script_to_be_invoked_if_binary_not_found - command -v $1 >/dev/null 2>&1 || { echo_warning "Program $1 is not installed. Trying installing it." >&2; bash $2; command -v $1 >/dev/null 2>&1 || { echo_error "Program $1 is not installed. Aborting." >&2; exit 1; };} - echo_success "$1 available" -} - -start_openswitch_daemon() { - rmmod -s bridge - if [[ -e "/lib/modules/`uname -r`/extra/openvswitch.ko" ]] ; then - bash_exec "insmod /lib/modules/`uname -r`/extra/openvswitch.ko" - else - echo_error "/lib/modules/`uname -r`/extra/openvswitch.ko not found, exiting" - exit -1 - fi - is_process_started "ovsdb-server" - if [ $? -ne 0 ] - then - ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,manager_options --pidfile --detach - wait_process_started "ovsdb-server" - fi - # To be done after installation - # ovs-vsctl --no-wait init - is_process_started "ovs-vswitchd" - if [ $? -ne 0 ] - then - ovs-vswitchd --pidfile --detach - wait_process_started "ovs-vswitchd" - fi -} - -check_enb_config() { - if [ ! -f $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf ] - then - echo "Cannot find file $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf" - echo "Please make sure to create one that fits your use (you can use mme_default.conf file as template)" - exit -1 - fi -} - - -check_for_root_rights() { - if [[ $EUID -ne 0 ]]; then - echo "This script must be run as root" 1>&2 - exit -1 - fi -} - -rotate_log_file () { - if [ -f $1 ]; then - TIMESTAMP=`date +%Y-%m-%d.%Hh_%Mm_%Ss` - NEWLOGFILE=$1.$TIMESTAMP - mv $1 $NEWLOGFILE - cat /dev/null > $1 - sync - nohup gzip -f -9 $NEWLOGFILE & - fi -} - -########################################################### -declare -x OPENAIR_DIR="" -declare -x OPENAIR1_DIR="" -declare -x OPENAIR2_DIR="" -declare -x OPENAIR3_DIR="" -declare -x OPENAIRCN_DIR="" -declare -x OPENAIR_TARGETS="" -########################################################### - -set_openair -cecho "OPENAIR_DIR = $OPENAIR_DIR" $green -cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green -cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green -cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green -cecho "OPENAIRCN_DIR = $OPENAIRCN_DIR" $green -cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green

=SVa?(+bD$pPPP2v-W)3cC5mML4pad -zIZgljcyJEl!%&n|zl2lV+gS2cF5VYmm=Z)eE{`|Ie)Z+3~XwMg8DsD{3vYiaK3=l-K0eU16l0dUXxlEFgy+ -z!IaikBIAujJNl$DUxzqGYxJqQ7%eo>D1H>;4J5c`2d)nusn5O&K#cc)=yPg#fn_8W+m-QuP -zKEVuR1(y^GLpCGi?w`Vtl`t9xX_g`6e1TMB_Ms*szMZA6fR_X@4r~?vhbWAT@W1c_ -zT2~=k51T>kn`1cJKP4yVfrO4{Tk^SidxE=VkjsXPL)hYj@m>?6f4x_PqitVZ0%_Pe -zo0{ESw;@kL08One@lSdd7HF0t{Z3CUV9WVEB_q(k{q1-4eXx)??I-9F>as1ku6#9& -z+s5R+cJ;-H-`WW|4AnveYeBfg%#xeqlY32*JKaW99$YnN$UAcC+MbYcd$*HtR>z%v02(q-($7dI=1cny6q2~wx7C4+l&3KKe39^ -zV*J3Ew(EP(vF(y*TaG;QgMH=wIA5?ta18rZk6}xZaH!D|b0Y@6#i`PZb>70Vo30a7 -zD2!GaWSyHJe#I!Q(~Tdml|MJ)6h -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 -zS#tZ>LXz?K&(%vRTo%kwPCF(6z~O5% -z#0hi>W3|6AsmJ*TGz8Vl$m*N;K#?3+OYk-mqr1Xzz(>?~OsnTV1Z|{2p|=mvb!;~o -zj|c4`W-VsN1<{<@764l&c%4Y&_-Ddk4(_|}L8nzB)F8rIA~4RraNfA89rN-NX0i`6 -zs-;7Q%c)JheY4pA3BPM -zEO8kCHNE`E0QewBSu483Hu0P{}&Ba`CT;BS+*JZ -z8u}2CMZy3z)J_`9QA7I?M*|vq`q;UEhQ?tUDtxBlUtdF%=?e0>VwtFgGJS_aTc|Ic -zLjf!jeba|o_m)JY99M3?znh&{TKmjuMS3NBhF(#{w}_;ljgGhL4Y>bK!l?GgP4!r^TsxBnAmZa>_-*@^s_am2=p@`V3b!3X1ek06Tf -zbMfA9=uMI6FrrX(hYNr<<_0v^Px260Y_?js_-b>>PjFa7V5O_o_lC2T@`|z1JQI{L -zb_z0Q*^~siWH0x+r<73UqfnhS2z_`769SPvxu0qnSbBr( -z$;+hDdrW@Zf{?@nQdS~WXp1L-4?#d{t6?9&n7yi=V7>H&m8Hf{@Vvkd-+}-apm!z0 -z@|VEQSg5a$j&FKRM(U3?dBKUEY?H41i$w^PiwM1Wj{+>P=QqojW39iZY$LoixG|kP -zzt@0TPLeWqHu(dbUiy4V{YH)UehshHMs(i?&!Q%S{a=f%P7=Y4-du}~X6>BsMV}9C -zB~SWOZ6&W;(CX|!Zz9X4VSUWuEsTtst;U#>Y)am5l)ntHLFE^G+!C6k2w_9Ae685! -zBCcrAmkk%QrBkXn*F|%oY*a_TZG*R)nqOm%LNvjnbTZA{U?dM<&K!kkdyS=5QUGD4 -zS%|QslMf6Zx<60J5sOqWbxe9I`Xo%6)lW`Pq+F*P{iYXm-XGh!4+@EUf55nee_#Fc -zT+HXhmVbdrUsVIv(tte_pglYB?A2mf(y9r|!pIH>)xV}wiRCF5!PX%gmlF`ZQSK@E -z$$(hoZ%=K-MBeua -z-$cVh@Ms#Eb@w7nt?gs#Ed$Qns~hppETnVFRS%r>T)#d=Y^tBz7vrftJ@1_geG{sH -zj>H`bgfEqNsx%B0+-q_gizTT4upLJDFEAwu@cDVNK{C3C5~s6|^Hvz=k`t^r_-zSe -zZU#x6zCbz&O2&c`{l!D()C#wE58<*G*p6B@E)e;*e5V39lcTJHOrqTQnc$Tog*l3X -zo^@pSQ>a3B(1C@?;FsKfct^DJjNk=^@B84SwgsTs5kJwJNt9+l(W|bXgFApY`&~S| -z;WUmbu7}adoE6tS(&re)7rjD*2KHi5Z!Oux-uYp!#+G+9r{-Yg2)al>F|46)m~8!2 -z2jwl}mm@jTA1jFq9-jMJGX_kt%l;mQv2tL{scSHrV*@R&R5uM{~ -z449XKE;p1S3+L=-5Ui&rXLq1e+L00yzex70!rp#l7Ln)+L}#a%dHCD~rUwYhH8PT4 -zRRl?_-(4V)T|nmwuL|qCE5M@44e?DR9#<+c7FhCIB@C@udB=iv`5dQrQwu1SJ9Aqi -zuS^>-J0p3lfR$0@Z57S940|my*o@=}86C%(kujNKwK0G*kYX=z^U5f{b;xIJ~qVq!x=t -z2h4u?uaYB1$}6mlb|{5b@NZ2F6j>=`B%1m`~ghvVC~XELpqJ_1(Szhi~KSa -zJJLJOPU{GBEHRn_8@Q82Yysvz5T+!F9RgpVk*M6&n4P62e;@$D;{^33!~>Q92zIgZVo!pt{>?{X=k#YRM%?t{sqo+Cab&TLA3o+f#7GD*zSGL!6T6+ -z$)$#}>qQGw5A0|TmOKjxp5h}He_}{ikJNf~aALCA3M1(tfiH2f3(v(=4)>qUF|j7* -z&X_zKAicRW#?Ql2h*wYMv%h-l6v$p|thJ3RBy81e -zD~4#AfLXzfWyN-J8SOpys)~*1D>}P)9??NJP>($*UU-^-A}{7J@QBOBQSjy^ywOuC -z4IY0PlvXx9wE29}O>7=2cQ&0b&2Odnu~k@FbszpNI2P}5aM0@3C9Sk$vDMOVaU+-J -zqtg}Oqqq11HFldka^nXTFljejgO=v6w`2AruAzb3ft#!{=0qnU3JbpPG_O33UUN(| -z5I+J!_*pfbVAce2g66Zu35p3&t>*#m<~@_Hf()hz46XQe`F_MLK-@UNU2vZRO7gc7 -z1$ -z%p4ykxrl*Lrb_aTj1#d&5rp+zr#4q36+M8mRwmmqySf(`y#F?9R(1ELL -zBP*MQqvIshTr!e#ijH}Zu!2@j(J>i$mS+1g>|}7F<3sZ3N5>)G2BKpfq*G3GtP5^J -z(Xpc7`_ZxUbtXEVco9w7!|&`~(m%MoFvJ^%iUjIE(^TJt3Kt9W!3}d`F)cx0PHigH -z2FWLotDHqJ%WcD4^X{Un1Tn~;C^$F?>ul#N)r!{Cl1^A>3v>-JjY(MN+FXOb_4@|$ -z%Lm3m_qEda7vGCnXj0a$NG@R^O|1F#j@OWU -zUA(bgvqea(ECJSvX5cy@JPe~1w}>wEO@Hs=XQ9tG%v?S~rkRmE%i(S-Mtn9Z6QD{+ -zr}C()qRXkh=?NJfXMw-?bbj?Tht243%VMW=8`7`H4!|1+6EU)D&dTu5g~H@N;z3=U -zl#OakLWKfqM3Q!cjI|`S1CUyd@0vnP4$2gClYJz~SpYQY*E>i+;Y@+_OZ!wUlr19B -z4Ifya>IQ3te5z@?Sf83Lv-MmyVPZuI}tr~Z@)u=T0Ua1QMV+itKvwT^$%0cMK##Q4+>5DEL#5T8^8_>ND> -zeOv00B<}&B@u@b?$NCh<`X4aUNB!eH>rwOI1A%NVdngoPvN__+AkNLikv%ceCw@bx -z3_=YfR5=ADAf++I2xVyx5$4pp90E0^$uX1~5$Y=iC6vlzXRc34FXxsd)NDdAFMYNW -z{D?;1DM$$ep!cCWF)vR2R? -zT6qm}$Vjx4qA7UOpd3wNH-?O$wZ{?qY6Y#^{6-RwfamlhQ~{snYsfG{?Y1FI<~y!W -zjE)?=Q2n9}`wSuM9<*v)k0=vuvxF=EiNn^q)PebyS;yL^i3LYKqUwalFsYA3(-gQ<-KvbyMnp=@ -zY=|-hWOL^}Pp -zt)qT}DH>XL>Zr|oYrV3L`mx-T;-4FwhDXIxU$7*IzJ41aQ8x8%(b;g_-E#~9+BS9xp-Yn88wY47D2qO$Zc^6 -zNRD?eT&l#7_GbMF3jUH>pO1wgIr%al?Bd_O@Fa*TCG<>@fTp2l0ZP4YkJo;ZO3(Qf -z0RZ>EO|+hK=n+7p)oakI;~FiVbZkblqmzK+-_rm$GS4-`*k@AP}#D~C!nwv$QrJdDQ0DtdXf>)aK=8_)!&?xj}F^lPi -z${VsV%Zo%`_Q4i5Vq&6~^EROhsP$JC3Dc(JpG{40HdbDO%Xy7E*v{4uL{tuDZY>)O -zaNJs^=Wr4rPGb<&9jh~bbZ#wck4H61(Y)`SWW#2u?)@@yYuV3Olq*l>@bMwL&id>f -zl<|;Ua;XQb4%aF}dRSo*wI*h=#EDzWGHGA^^H%(fOxZ3K{EZwttG(uLWlu6Mb15D5 -zDu|IKl_8OA88|_E1c*3=t1=z&sLD}oS>Pn_&uiEd9Io4AU?VZ^0?;%EkpF@^Sl%O2L^ISXj`*{RaJM*Nz@H|v+p^5WWjzwX*L(xUau+NVQjj?ag{!#6?=cKJpZzi)hJjeN_>>`TsaBgiOes -zoY5{(Ri+zP*`4DWISI -zU5tKaKOWEzya(=&nsD-2F`hiAi;p{=O^Y`>FjI%dxh|v=mGCW+kAR(Zf^xgY0SI761{kOEuEqsfu%JKNj -z135lca#5+Y^(7~)Bg<)9Qr&YHIR8NU1;|mH&>hAia9nKl(_C?Fb4KPLwTQprHTGyn -z6z?X{pS}f_ka-C?36QMw<8~OC$E#bj{m#(gH`pYn?F8#z5Y;`zhTPuMO^!D4AZchH -z!8jsZ9mClejD?mnCt5yC_z)jlPe&rY5a*tXWWowhzAJfs36zgO -zWc6Jb%HEkhRvygSZK^ytd{=ELoX{2~1DH?}@SLuqta6~*-N#9qGzBu*E1vHgF<1Lc?oO`3v-4+b{AGYZ9?y+p7s@@g31>NZV*5 -zhGeXNDO_o0E3)vk&8Qs7MhUMUDn8iJp-V=qRHh|hC(7Z6`au)n(}<)NulN_RipWPL -zwqrf)R46{)PS}I5P*#C`>O<3itYkF^v(|^XJr*WEVI~vCw?eEQ;xRc4OTQTdZY0`W -z;R+A^N`v1fM*1f%ccp&~6*37L06SGSB)uBt2a#MUpWSVMORxX(Un%iYal2WHl=ye# -zS`pN2g$7CE<4Im)QrMoRlp;Hci{VQKy{06<7|`N1YxTDxs$w~epG-=_Ou6GR`7#06 -zDlTu^A5=f&O}op?=>L?mT>DJ_J*?5|+JZt9_qU%OlwY4%RB5Kq&Flf9o?A3GXkahO -z5Zas!H{0Y{MN&Dx1&9^;4F+*#Z_w1P_8_U994)dD`^BZuhq#(-Yw_}+T7d3YDD4uh -zs(;-+q5`D=BEk4V5n9tP)0(J4Z>Lm2U1<2K7 -zNRa|ueJW8S$fC&x=+z@!vt>u2BS#yR#J8cf^Cb!vb;>lDgqhUQ}_*h -z9A=J*ek;s-H%U10j?}Ib5QYN&LMpD>>1H -z20jLtgS>kGyNBg!AUJQn$2k=J<3}81{F}PS(Q!=XBhgn#k>hU1wxlR&tCI!{D{4d$ -zZAb)5^gbc#oj}bCW9Qxb5z2+-&{50$Ie(3&l}sE(Ky?vXIto#eQXUISfbX$z``sq*5mE6m -zVPcES1o3a;Jy7q^>^uW%iuLefJM#Z90WJP?cw3fSK_YO4AO*|>Yh^2IF|b~t1&BEg -zIS~%#UCZvnW11%VWg+#$`L9&^Rm?7q{r8H5vHrc{O1^iq6LvGd`hiaukn+`vvT)o{ -z3g*7YzNz=~_-`g`vmU!uR|K3LFdT4nmez>0zj{fyrtf|zYjoy2E7_mm0Tm#AKcyM! -zmZGxQ@2r%8rqSm#+;tzBQaaIU;!#AYv2y-|hG7@G0Z0nN2)j$NKC@wzy@U#0QVi|c#G -zP!YiThiV{pdc`213vzQXt<`_7K_AqAo@&QGo!vGkFm6z#?rxi#Bp8aGS^i%jD*-XP -zZLVJ;rYFD=m|iz9ZL!#n2984}8QhEb7qTWvqUk@LIM@j6la1YNQ$hwXY2Ga)UWKed -zH*!ZM`m#f3rPOhA+->tZdLU@!wA*IabyhEXF=KUh+k7dHEyN)yUkS*k>Z@dW4T^5g -zZkx3g0UX?mm?8M8Od?WNk;5X4AtN3_lm5DsSha&EpB9fq7Z0-o#f#D#fOkn0|6*gx -z4iil`cBC-rp|b71(pq0TluGsr@@+Lmy6y63-J%)|fv+5BRZ`Z(&XT=&!p@TI_y;>n -z^to)=lIo6h7f@iJIY@UMQUz^?O%fWp6f`_Tb>LXnbp@yu*NYsROgG1pV531Y{qqjEFaU{AL@~>-^!1Fa^^{Y4_ -zp`&q@(WbmIhU)4W9W&tvOaksejYPwIyV6>J3;K7KS=+t+YgbuykV*uUmC}q_NogXQ -z7zR7ZzxN|nWL1}5#^wiswA0J_%0!f%=FUzq`G)#(Re{cDI(WbJ5n~P;V*5-5E!#Je -z#khTD+}+w?f=eB9;`v&CbyY5QgzCy5?&&`BPa%cID2bXHi`UYr?C7@$-WiFueL*P=ZVLbrdo@C`*}d?WiJvagECznkbbKCUFZHsWq8Yz_ZahTYGNqBaM$lZ&d5O{I20778Zw3xsXUO(&WmEt`>{ESC-Jx{^BCs0GoUdLSMTtRY9!oHCYZ|xB!Ojc0zb?0(7o9$^KDG*{f}G{* -zBV&aiIk^W%aGaeNr%-lNQROhgq=aHZ)scfbjJ@CDwZDE$P4>e|dL&w4ptaCbD6EK- -zZP2P?sV#^S)-Exzs2ZuPeopz5Z_TOs9W1u@?<3OQ1PzIHx~)Qc?pX~P&umNo9c`Fl -zH1(#DZd0G`F67CfeW**WpjHBVn-j6kBe#91J<(B9hbH71fat?sau0F}(M>J6Vgg6R -zl4bo-UfjUoR>?`&=M^)){Peg6*i1F%}nwl@B-16aeWYd%K{h$n3BAaWLY -zxe_TG&WOh$4+xxqAKeO`kcZDZ0vlH-IV=4r%gC|Jp||F9-9 -z9&w(7R&BuhobcU?!%9^=4_l5078k -zU!En+Vv43Hc^2jmA%7Wx>=eBy;4jC-(z)zgZg@?|U#jj@2K*QI*#-RN`5B@>*I)Wz -zn8?vz7C;Q0&?L+hESl~rgc9L;9Lj9gUzT9Yq`Z6;&0XAI4vVP)c{k8w{iPUYY}&jJ -z3rXWIO9adJmp_qI{crxVr->yPuX*$&kxo$=X*W1q#JHX^D4dHbV5_lbYwW6=*U(`*VZx;Bb_Yiin?q2)zjhYsU+k~+ -z>rVntfTWciO*6|N#$sZ$BL)R*BkK_EIPyJmY>VrC)J=BBRMIVst7$gW`V=1~#ebd( -zdQEIx`3m&|OP9RVAm&=Z3{Y|WR>r03{!#P6kMwo|xnx0i~;BgfPB -zs4?hYS|FV^6$|}pI~v2;5>*Z2gun7TmKc-REkbkmdb~WAR|Hhgh<=*Fm-v(Cu@Z5i -zyF=%@Nt(_!Auy}09hZhwHACmK$R#A6c(=)XAGFDTHVhzt`nK0|=4mJx>N&e42T3c` -zBd8xj9;C5lzjAu&DY@}X2&7_m#4@&EtVhPJwXzF`a+$ZGP{E!pfpO5WdxB3;nu_N2U}`F+rBls0~em1c<~FyOvtb3 -z>p7isU&<`yec&&&&*?+rwa|^icW#1e10%uQyt+Y|R*I#Bi29B^C3}<<@(6{1=I;&7 -zL^xKsb5S)G*ChJ7zM{MY=^A_ARwE-5XSG9xyT>J(_h$q$y9(I6hY5Zp8Uem7b*Qew -zNvFhG(3Jaht-p{F6}CPiaw{O~NOk9F##86W!cUjEQR-)8ZBCThfkzdkK0%BPMJcj( -z8(Y}l$NEN{>trb)@b%gX>Q(MvuO+1m_llqseM3bYgq$`xfPH4^=l2yq#DyS7bZMzvR+FmSWpOKQ1PELaxf -ziF32wY`6yIyHY?;^oumP-K~gnD_rDrUbZZ(dp;MwmSXc@ -z=(N5Bs#L+1zq9|Mt-#9PD_AgyUHMD+Tl3_u{4Kad+M_`C<`I{mhv+vaV1b-h{+1)G -zLB5<;{xUEQY5WEYz=wYeNmY6DSN;+ppR*>h5oKIwyR-RH4ukuc)!^Y~RJ)Bzm3&!fl{ -z3K99*L-iwO=_kAAE*EE*Oya|7y^E9~zUBTVwaT+5=SOq%!-Ue*D&*O5*hMBo$ -z;~y-toDy=ksrf+cwb#ecalG5#6I%xMdE`g6A`+eaa5$Qdm05IP@+6XC29C}4*ROxJ -zApXe8k5~RY^-~1WNc3(}!pvxFZZo4z;Karqdg3r*mQ$D_#kDfFs)TQ12pac)68dm= -z$t)0Q?A_l-qy^Zr79%L?u -zs*gStodJNWHkIFnwCA5REO>X^splYC6+;oB@TXr`LetP6N;zzJcQ>sOSy`v>wLwq` -z?})QmiZ)!@)-gAOdxD6NrDkMkB#_JE(`lGsWBf-85*ML{UrIw5oc8UAoA-}7s{H{` -zn>^xzdMAf|m-vl|@2*VTFvu_yYVdI)6f`1PV-!~0qfuv8dJ6SN%E@@H*S8j6yfp@b -zmKu8HN%G^aqNUx=VAL4XW2Gf^Rvr9V4gQF#Ab-PY!ed6QZ^%-RcC_8*{m6AxgKkg_D*L|1sKUD{YGCQQdJ^}fT7||A`0@h6%Y{* -zminLTRc%Njv$K`&g`*AJ -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 -zx}Dw8SproIkvF_Ja@P(&aDee7jvC)VHY -zHt(gb%u@u-cSNvCW6v`RpCD$!c^+eQ+ZNwlIxW0KB3AOe|75f4-|>tG7?@^WwQ9ZJ8S?p -zPRM_4w$s!r#kS_$AWC%tD}y?7-;RgWyh18|X -zUT0`7BDu(rqjQnrpN-)`LSFnGhEoA1N~Ni -zC&qEi&2j(N_0*3rwDEJ}m!d^GUM6^(3E7>H951t;GLXharW52QfY{3NZ%9Xk?7o2j -z&Z)9Y*VW5CJ&Av=i7-PAPy9{9*XF+w`%0i{mPJ)x3a)$J4nwKz_h~HdLJxse2pMPN -zy?kup9k#&E+54PofioDB{*If#nOiZl7P4-PNE$dU@hM6Q*#AgE>E=u{=o@R~S*C|}tI0h5#@*hb -zyi5IG=ZFuJ@;{A5R`$5>Fgvk5u3SHmMLuo4fb#jfmv*CwqbCA7ZY6moNpUtQ+6bVg -zt#l>K+PMeHRM=s$FfhG&*V3%yf#+r#Ve+NokQ8D8)m4|j8pb8o%SfE`jP19MvMRs -zXOppwhMYZaPIlrc$k~S&KS(tJlMN|$3X|AW2QWCDt!_?54M{UO3Kbq<^1_ZBm|TIB -zjO6_4reU%znLN(Xe&P=Dp%njb5{YH*eBYfAU#Djc@Vb8sepHw>WO)fm8JaOImX -zfu#o5YngAEee*glZAFy<`CkK3E(eaAG5~M3oDG+Z0hBl=U5pV_>=nD^Y;ZSdOp-9d -zRkS4lJ{Ggn@sD9;5b*CBg!!yqVT&a1Msl2uvjQ+K?JaLV?AlX3gzNOHbi7Jknbt!D5OISB702q&7QHEN0G{>(>V(1MH -zGzs2JlpG?_X7$}PM2>Gbhu -z0}Exy3g{WKP&ON5Rj|E>N#&oqN{Infq_kqZ35fLtKR~uF57((Upnv)y#d=v4)IGwd -z^l#`DZtWzB1=#cpdcAATZa -z-#lG%vTsM?9jOzx@7?YmIa;X}AvXx5a_VLiweHX4s{2EzSKbxtTR%YpfiHvT1Dhwai{py&kb0Axb_j&%Pz196#7n)I~k|$RQMxvRuDWe)n -zkgv;vk9QoCOc^7UU!gkOf14szKdY6x@uwLG;tQns2)uVtrsE8RZR1oVnkrSUp~d*s -z5FB{IvV}~YigCu|733%v{JOwORK&6V4_54!Zp1pIJTj7^WhZ8$+7s`$TB=XvhPTqib2Dp|dC1kNk?0f>;lR3Abi~@U*-Fb}ja-lJj*6Ae -zE@Uj1nC0HKr{n%oOnFfMB}rNAkq%US1~9ob(=H}NzZdK1DRA#RQbW~iTycM?&-?0l -zTVZZsG2xwKHWGJFvx^BcuxBqlmo={IJuy33p&b~8rVm9FuWOgS%7B!!o^YRR0ffiQ -z-y;qp5;Vlv0f8^Fo{;2yhLxyD^xmr-UjzzGnd6*dcnA7p%$%YRDscbfoZ^Xx#3X?^ -zMI&qKtn -zz%NC$RI^v(j{o5t_%{fovFE@a$9z*$nSy}toCBWY^`(|PsA -z)9? -zG`NKdoMWkY+T7gSOuxA~^GekVY)|^!P53Aa_K&c*D`Q22WH3=Fs{+6UR$l##*`xm4$|+1=gWtMI -z@Y2~@5?gZ>I@>LwYRIZpnzJw&_aZS_Wp#Te; -zD#5#e$^q8@NuN}n#Y8ORH+u+^;=>%p$QtyKHe} -zsbVM!{c=YN{lAnAKyP$2^*r91>3AcDx0cMPeD{IM!YLw{(ywv4Yd3nhI+&E -z)=Oe|UQC9DeQ)@mNy+UUL$->!ZV)d9}JtDc-|TgZ7YXAOjDF%D~H{7 -zg0QU|j{6zD#?3>l9KM7{3I3R}y~X(Lb}U -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 -z`>#!~@sZ;t#L=2Km3R~)}^97aDGIA8f -zf88}&o5;6Z$}K{~TBH9W1i1wi*JyiLm1dX2Zj`Ia1nnjD-G`iNdr5BXsF&m{v>nuv -z?E6i;CHeE0Sd!n=6G3%*bR34OCAkwm!i}!3=W!nehbEfncYnw-KV -zuxUvx^ea7;ZGX^Mc&_qNgww^KO9V9gHRmy2t1NpP*3 -z2-Jy~PMtH$;D!YbRRePeVYa$3pUrY$oYhp6ARhuGc9hzUm2PCAfmDqiKm#Kb8BDYc -zj*PWMu*G}Q+{r?)R -z9Npsa+H+Qkh4IT3t5^M$Guu{~ukVq17#YdLMRW#m{wdK=j@4q(fk>Qar%4>RmIEK= -zKzjV6a450))ymA|h^ibxW#&m$`eQI?b}RVJqVj#Eg`hVYbc_wWl#kXW=5Nm$U1UrF -zGOO|(CfAJ -zWbk6x$zc4}2DnGv{d>J -zoWvDoG<)GGq0+z;knMu+$}*bWaEyMpGv$ydur3*;0=J8M4_MbX_F`2zcTbMI^pBa+ -zIlYu*s-JcpF8->5w*nLEu2$b_!Q&!Qm{ydMh_yc_P)?`d3Aylp72xn&0QP(p;2wb4 -zUj?WEvi4U2%HcZZR{=i#Swy`b40Crm&h5x+{EWN3d=Y})6@C>!e4EG0A0&n2f9Lj{ -zW|Hs%6ffnNeVWO!A^cH-k^9ZdFrJaPrT>P>5Z*r2M7D;7B4H5l28l0kmYKC%q8kYL -zNC0vIvK`k4&`(SzXl;OIvFrXq*dAy5I_*2!6U&Ly!Ws=-_7j*`do{}PtbE6OtfzRs -zhIOpsOp -zF;?$MH1cn?MyL!SjYCQiD?>ng1WB1wuH!q4;KEeNb}UWkBdDBufDG0ls%&#|-Wwo6 -zz}G#CFl~6@z!x~MC&o4YnZaAxj0ekuN7m!jjU -zc)4rq)yQ2xL%27&>qU4)74O!3E!r`8I`z{DoeP}*{-;Q4+rj8!eoa;<z0}Lt{%TkD2w~3U`(`^k~sRbC{k*c -zYs2_<9cSDG{Tg*l(65Yy&Qq)`SqDX$VkMts^Cu*3eYx3Hg2`}G_lXvMKVjDVLoeI1 -zQB&0k^OXxTVZ8(6WWiSxWEMbTuhYyg{Ui476~Y6FluBw1^9Fc;RF+DLm-u({;~5hp-03@^BPYTw -ztpQ9hl{Rv;maxG6z~bYe%{@b*+M41a|B=hRkKi(iW~q;W{E4@)is^^X!Dfs?pj+vgMc& -za?ZV$kiXqv37I@8Dz5{Xz}>Zuz2fbe${o-VWR -zJ0R)Cm0Pb-K>?jH6G<9FxM+nY!l$opOvtUEA^BQ_UQY-auoAj4A!H_QtJORdp~aFy -z=M06&*PLIuVw{|TCNVTc2x}|-@_HKPmAu8)_9I$hpl*Ce@LgHmIJKm(>UP4Z@m@Pb -z;|b){Ho=-OU2l|WK*$|OjTe|Y#{n_fQq^cNLM?EiUO-JFu^@9yzzs0;*SlK_1~+iT -zaRcp8rsxWO(`)K}za*~v0xNuBj -z%wSx29D|(^Uayp8XM`miLo(@RzBC_yFe7ZbBwj{%{k4b%ACwn*I(gk|x|ttGT=URg -zJt^9ByNG)5h=|GsHWUt8n5C|r=HgBu!KP7ja^WZ@4xYl{(szPrA`#Jh6?qbfu+nZ` -zYFiO)@;k!zabeeEGOb-Ebs#A?(A)f;fCKkhY9_~5<#^ks`#s7jC$M!$ue7p5kqf^l -z83XB)?AP| -zlzI3C{QUuQV2XSLRplD<+(}enqd60_1h(Vb3Zdug@o2 -zyna^Vig{g$ER~Di_m$X*g73fd-w)*EY -zYlKeD{=+fFh?Z9PR|9bBBxki?!)9jApy2cRV0)E+^_n2}%2k%gm;V&Ug|x43@k1d` -zpbZ_0q+@_Nv-b6hpbA6!Diy%7cA0bF5)N!lN;X$Ba{5VR5V9g6>2arG`M4IN)zXVl -z2`<#8a$IEL%;T}+bxA~hEk*0+K4|Q3*!lDJ>fS#~u*&LA -zcc10t8|3KCvA^4iX43&R-5@*@PE6_w9Ty?Lu(LG~InH7o!TvdrtGG0Mr`_?Dr51`j -z?c$y@DHiUcg)OF31@;a{*5XLgZ!I1M?uHkcSK%UdCw~`|prQH-lryB8T=+ZrCDWiH -zPba@F!0b-`?(DqoFYl0u8aCoOW+(p`<`Cb%`7!HGe#Z$I&bQvI@8Iz*qal0PIzGKkU>50cCw$wb=;&RsjCi -z9<*XrA((+GdVKwrXs0K~FnW}&s^*3(=a3|EF{6i^XX_S$dYKO=vJyl_@3$z7@s9Ts -z|75&hM_5*T@3$Et%voYs4l)nw?dGMcuI=OL`4u3^nfuHlsV*el2$UTi5s4{g*TODap#=6?)*n^?6Hx0T~q%p}y?4Q;tm -z^#99V{~TY}%bH`(ZaG4(AS5mRAB4n!r@erd0s8+g)FV>;No8~@wx@jt4^~FEVr@vuppNFXE2~p4qB44oS%9vL9>s7a`^3c}yRi;yT~}EzbGrHmzm3eC -zNN#-Vn#S@s8U~@rYk?t|HEf$9=q7@8Cn)XeBNVExT@hv$VUk^#l214=PP7_9kkSB& -zoh{vmWng@d_7|-==ICw_jQ(OxO*Jo^iab}Vd7&p7B2mUOFSbXVhj3x}3-Ww&t*BrO -zk;iz5^ug;EKOC@{13Ga474h<13k0S{Tg>XTqT$3)A|A;>f1Y<$K$5LEAi7JW3$xxQZs&I#j9B)s~{BH@95&fAgjU=1kA -z6A2skC0>!0-(%s-zOq0>GWB1e#<+&k&EHOYmZ8f&^>h%1ye&x4WnUp&;=bp6L#?8% -zXg7x*1EO)St)`iJVo)n^!rrq*6K> -zDnXkP^x$_!nBy=NGv`($yn%pA324*rQ=ck~6$y`{L4fmLIfP4KibRq?6?NShi(=pj -zz$_w3c9E16-{)qTd+#;t$omAKoG8@)1YrLZV^g0z<6AP%&W0o=cN~w~YRL?l@6oVI -z-jm4I2j80IeJCvCbhY60P2aoK+c$l>kD&7OP1k=RO6o>LTv5&M03ujTjxvr~%sPFW -zur*!St|&mQ-c<_$ya*M1lD!{cR;^Z-O$4mA^shkA`vt{vvkqb782hK^zrwPXCWw`S(x%EMYF|N@Pk4V@)GdeAZMR5!JP(p17^7sp>otz{E^0 -z!U)_V_J42n&r3o_OK*gnM9A9-No)D-E(gT&zx@f7=tAv;Bd7nJ=bnFO```A$tiKW| -zjE5ZB|2}ty24ehgl{o&FGdbiYQJi*OpJU0#eKeck_0NSs#pj>jAz!i_#=qof@K@yc -z0sl;396c_#K9C -z>5dGg5c&SEMFlaI`P>iu5)|ct4>`aN1>+E&rBF3n3%2XorS-EqUPJ8y;I`#^wMhsOwq~6B;0)=SmSQ!Z%HY}ywSvdS|S>G0U)t$eiSCr=vik-^Esvo(Q>A5 -ztO!XRo9}^;Wt_}J(MH^v9&(Q$H~AbHdVt7({VI;lA3^TmS~5r6z!6J1g4(+0-@xiW -zhdu)0p9^zaLkEweiCqMF1|YFDu@5fMuZbBP(|~BHiQ=-x9Zht)Xldf=##w2i47P*# -zHPM8~4{VI1iLc>Xe44n1Bj$62z5G|d>wr4K9z$Y`{x2b^v!{__x!BZdSx2C*F3?T+ -z>8-<=Lj%EzJ9zGF&->neMHPn03gZ2a_wxRFym*WM)+ZNL|H$?tv2<%E5p#{3(NBr_ -zh@vo}yR~sB2he(>Q`x6TNLJt9FF@~Hk1b}1h_TL--?vD#F=&JGE^d|e>n{whv7*x) -z4!I{VWK=&}k4s;g*xA#W?ayI}97Y-Q^Z|QrKC~2RqeOPonJp%54U-QoyAjZKJ|u-q -z^t*ESHS2t6?8hc!NCieuL0WV&lx4E(+Cq@}Dm7h1@#aIHd?K1^v0m9E)Y}WI0{r_P -zzZ^W^tQF&n26JR#j=H7sD -z@`y{>F&413Lg@$*y0m|9a~&ERiyTMzV?_S -zJpW#6wqWF*~Vk8WAGUV8gynbFNG>38k>(NnUOh9Djw5~rVR6C6p -zf*gb+U=xUGWsV|pb->-{B?~&*pscpa;$a?+3KL-mNM3Jj^c=M0Jy8GEw?s`m3S~M< -zK}R{lh4Myq$i%iaMm_H!9pi+@+2uF}okiUDdZT~9mG(w`>Z%EE{r}nJ_{TFMosQ?P -z7XzkvyByzd4p}P*EDoKej?2{`VX=q~P=s1->ivya-l-wF9-+vthzM@4oX)osjn6x& -zA}&A2%-|T#(Tmqx{H~To8}kX)(wU-qPZ_-OBO(7#fP91ZorNoN6v!#lIqXIb<0}4o -zzvp@H@9Dz5wd1jL2M3>Pc#Vl<-)a$^@pUP@g^91{B#m_D;9?2fiJNH*hvRfi3h0?P -z96|R0=N}R|=OzDHd%e;2OGQ@^s-r-eE=CKn?=I9Rc57TE7X984cvY`OuXs}=q(yIo -zi**k75p4zHLMKu=wMqnKTzKyo{i@TG><9FoxNu2&mL@JtEd}8Nap5yjR@QN$GE!Y# -zNy_;p9S*n&jWM(b;I@UFo~G?TO>WO3{IS_jXwx -z%O>zE9iX!CDuiB5XwF_2WH4N15>A~q&r&GH-X1p^xwy5zCt$VTp$CBXe-#h1K$n06 -ztB+G>l(t&g5h?e3rCJ-)gH9`Bz_x -zmMC{BR)L$j1tiKw__qkpbvO{t%95z(%RY%Fv<*rmTd(l_Ga{ix)vmK7>VMLbs3N>- -ze2GS5mHH);Pt}GZXTC5JrNOrS5^=@WBIGw3(#_MpMKK8L@OeTG$<85fa|jpKj;`P@ -zkg!ZCUn4iGCiBr=wi8+zc>igI$joUf_?!4Q>+3vY#OEF* -zbMU$L*LfPl{Cuvr(d$B)uD2cOm6Gq1$p=K#`cVEK4g>z5G;N<%v|U_lTErnO149m) -ztltSPuMn~vAvx9eS9hiwAS$EjNtjEYDWUQ00_OzB)$P?Bup99ysvD;pu?$f`cO$;2 -z2z-GP9G{1$!Qt}e1jlH|(fj>~MlusKUlHl-Zp4Ul=PyMIqQmEQBb19>H%k=MmHg2* -z{(W5W#TlA>HTe?F`Lh2AT!5QIC|pB`tB8y1_iHR%)&Ib3$4p2@A-8mKX=}NK$kr`~ -z;!I4gDfY4PT0!c>tvXdHAOhMknY(BzIUL46`(p$uFddU8p?LMg$GI>q$q0w~iN) -zjbBn$y9Od3F@`iC?zxcz?j`@OP=%6Ph2`}1R?Zrco*iN+#=E-%c -z42C~U71i_)kS~U=iPu>yAmn`k$YD`L5a*a3$R?g4&M7;6i6S>q=uE#MvSLFAL#<4| -zA)$9IQkub{&FrnD^qjKu4MevyeHCw=N>=IXG#U$-e`2D(syu4xYjYl4#0)|=(jd%R -z0knwv(OJZnOl(})PeKE7LV&{o5rx+(F+ -zv&znr<%lW)S)W{0|Ftf;n*6XXxjMF6sS*p~WP~8y2@&k%s{wNglUR8Yv#og|T!5Ko -z8r~y>{P$zS*4jH95G(f7Bh+>m>OI&CcnW7G$BsRJ!2RLAH}(waVEjl!B(HMc>Goy$ -z-1Kf#2WDA~l%{aJoVdeKPwd&<-yeIHbRu0*TW2&Jl>$G8Kel3zP<517aF`37HEv> -z8FZ@Su8BjkdBCj`2ZD-MgOQzF%c8-i;*jZ7-bI~aX^=j*YP1Gs1Mh#%7tPS;=0T=v -z`PkXnwU4#lI!=TkL_Z?C@Uix3Rj>3?&>&o}5xBCq>0K0MNTyBadLr53E4P;~&g^9L -zu0xU9HTOIO9mxAyr5HM{ejy -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 -zhfY(*Dgp -zpw_XTLcDNCAmDdPG|>k@6jJlsCIawC4&W#S97i9+EXglFJ|si%RTJ1h)posa$gMKu -zXlo3qriaYK5Y5vgiD2TmJoeI~51=wpUGtoR{Tbxt8nm{sKUMHVrHR<%Os9vf?&|bG -zVng*`kqJx`Twoel1;^Jj)yzoi-a5MH8IHJ$BVcvNa!i|8TU||r1dXEv8k>Hr>#;Im -zb)|`OaXQUNXfK2Z&?ssfaAS494-}?HDR8ZThDe~5)y->ld8;d{>Q_B>I!X|s+Pu5p -z>NcVY;Iq0x05(>)yPV^(tg|OjwJxcOyDq9*PBButDEf`vQ&ojmm!YT)y5Fb)3JO$ -zt9t^YEvq|suK`^NyNKQ_cw$-IEdyi%*Nuu{b?s-ww7PRhdU5`R8lk_M28)%m=VcA# -zbUu5&0Y$$2VxBj#`~Nvdx0BJS_{^dp-`S_j!2G;<5Kl*D>lEFMAHHf#_o3F!nx}Lo9or -z=o_*@hNQ_5$KLP75Y5xM+&+8nh|!k4=Z9%%(5+R#em%hx%ibG2BNMn|L=1axf?lL! -zu$Gt2&k-{?0ydc7dHzEi{LfN7rL@7Z#m&T2h|!PzlZB%543<{@0g}B?y4;)sw7&oQ`LsL^tNk*(-94o8_n01Hu$>v;mpJGgPz3vFzM(Zb8j#1`E9Ur8=nm> -z!LxkZ=RSx2QuKDtk$iHHK)Op3CX8!Fw^Z2N4cZ%DWacu^^TvFdJus8;h#uE+Yg(0H -z0{;|<*co=wXeHub88Tk**arqfasc`)3K^V#rl7Ig17zwU>vlaocUyFhZX?_i0@o6c -z43R$;4G+wlK5)(GmMcf6t{9!NRNik)S=3{yoZf@&vej3vOWA_-XN^2qWnsHjkY9i2 -zg-gSStw<<1;x=TR1sA8RWI{R+`>)r?{k!n|75ORB+&+C>3(K;po) -z$g4207Emr#Ij#@K!#*7SG>$$lj!cFEJKBPa}O;67wmq -zHx*d4Fu5;MwySZOwz7^)*NCFBumpK_rOI4W@UPq%g2nx%sHouLfuCjIJC^wEUPQ38 -zOW6jt9Xov3mV^OKT|9en<_509$yL!SsfNFlb#IqZCs0d>+meHQx$h=IiP9HEk2Or7p=KnzC@66W|&27b2S;^ZXutkmCy__ywkp&?e84KXZA-3^O>M~yGc@opznwgi-^Kpb>mbR#RUfGDUtZd#>g0_`u4I;^ -zZ_zC}ua}6F@`8NjW3w37R&2Wh#f;R=P9<^mB&;j>;0N!IMW!L^MK-+Y-I;xna$#ZN -z4Q7x}TS@j4HTzyh;kxP(ik~70=gml&=Wc2zgZM>s1`dRo9O$geFZi?0rz*XWb*kx} -zM#I*kO9jQFTX4h{4kX(8+3D!ID^`@YGEx==SXq&gx=6jWVG5;3P!~`cD=aoUGyPp5 -zY>q?w45;MKm+|MZ&RT7QnOP*Jr>w|8te|oeGg4Rhu$PnlTB2%tD6NExSX}Z8P}U%J -z&O_e2umSA_@ix3X+W@ZTguvW}{*e4ktz{P;lI4=zo%{rscxgy;ct|d9luKg&9+z}w -z_<=}g0I9VX{Zrl-8k@^|V%bv}z6u$NoPM5XFLHY%zVt3bo(EgdH(%rAnH3Ty -zGtuf1@`QM!w1@x`xkkasn -zgd!cmnkW{SakLO@A|d)42)n+L*;9*XCZVemI!Tse>Kd_+)Rm)CR#+KRIAx_-oGWSb -zDwC-aUBYa4Gop=}Zt%R)SyG+w`UvLvsFyQ(cn;rl6l=kcOaB& -zgcxz&f?uS&d~`Q%`6qBbYDV7#Zejug -zE_00*e&F|Jhf|Bn6opgY@iL~TafW9a{mhqKU~?k-L-YjQeiGBzM3}8C=7(t{uY1tn -zP~M@C{c~dsRPKNo%W14KXLhCE3N3hM_tWnF*~Plb8SRY@MJSSeVD5xy1br?!kxIUx -zn^T`W$hDV3nEe9+^Zuu2FOOb(#R$DXL&L^o-dB2NoU4wJ#=Ghofde_2BG#%qEH8Xu -z)h&uKX=mY|eUp~EqOYY46UtW^~FyoOyOB=6BS_6ea|Xz2gS#`dAR70<>( -z=tjn~u?dR$kC0-D2C=fG(o!0?!0&Y%GXD|K2!17aOE)8=HGgTpQb3&DhvT*a2-w=agO>Yv0VZ -zv5E0)tT3j^vauSZEABBLWcAtDR5VdSkvsdr#?IXr$Hs;c=32n`Y;5q~kkA{yT0~nB -zI{LJN{;zCoFgS>3W2N`Ux3TJoUOqo|7oS3jjlJ{#w6V^KwvFwtYHaMme;gZIhS@MS -zwgM2Ajokt$$HvA1&TnH~9`@UqFKfutNoHosQvt2t^Lq@f@9rqj&uZxZO6xh$R*0wd -zS$pGa{j-k)TAz*GCu(I+`G0Etm#b{8KaTQQ2l;()8Y+6+BUa)>k9z@OX?+Qx9IclG -zoL}olI{USrHY_m#q1&x@Uqj;}6sg=dp!X+lkk#XK(RH@=2%-P&qpkfi*&3t96=!R2 -z%~Hw_WNT%)x5>%x>}+i(RsvI9W|i+_V}>FR -zJ{j=bJBY;Rx&M@h&Q^BtXF=f&MOrXBxR!!3mT$s3itD+#xR0R^AlZQ==#m}S<($*} -zupIXgk`>3@8jn`B<2JpfBke?_;ZG=$tj@%DdDtN+p=(FloazuTQyEyz$=!8FVY-5c -zY^*h{j)Kl?d~Mm1(QPQsC$UVGVoY@{8jQiTUN1P3i!X`=Ja~bX2RrtTe?@Baa9GH%2n&G)4oZi-b|3HJZiafVHu61< -zf2SU|2$##G+gW$#iv{ZL9GbK4y8gMA3E~kO3y!FTJ9=DL#-*$j@=DufWNLcgDWU4e -zEHHhb1+2$lFaC~pZ;dM1u&`ZlRCiez3Km`j3xgaM2GoK>RSDz*fjx|@f@1o$yh!dY -zc?HkC-UsjQ9Fxm0b9uPr9LMFdv6te>&xE4Q!y{SpPy;+1D<7SQM^l!OkiFu#HTGCu -z;dB^m2+s~Ywbp&@O}kiE(y)opalTc5=0P#{alMpTj2wVnF=81b`|*#Y^pTJAkD}=# -zWhYdY<}yO)XQV?aHQHye87bohppONhtkgBB83NE;08)yloyk^k#3-md?M(K9BTnIu -zkt++1>hVUraIoC+9M{_H9(6t%Le>|YF!#Cpt=?R -z#G?8ZWcJCrJvP-D4%I)<0}IM3{Too-rKs*zR1d_adaP2k8M?Brg;8xXFQ1GuMphg) -zsP$=gY!0^dM+xC2C2@4hdHU&%?rx9}S_h%Xbvo*r;$v;fD8d#=5a0=Y4;NBjl7cK5zWnlwj|IxzRPJ2wwWEsRvMzZ -zr519DbC7IhN;q{aEQM=f8}ZNfbd!WWY|DX(wtPcbps@I!+_S`e1|CnNfF$KWUUOTV -zf6`}{eg|HzpGjYys^p|EGccp_GsTnh*R^=^d|o9uFKGx$y%tHHN?G=th*0IRE=m+8rJi6+tu_|Hy_4xYcK4Lg)DAP->HB^Swtv!?KV`Fc&`I?#Y>a7j9yKu5Uvq%i(H -zBb4i+Rqq_KX1W|zqhF&M$M?@4F|w;X#)$tDDm$5>p9RNA>|>BWDgI_7{vqN=?<@mH -zcWLpjy;_qa?HL|$3Q5&7Qw -zuE_8>>@)6bA@UCDCh{ga2Q?%)e<1&h)k;ta>3y6WoXF-jt0XPWj?^$LZ?u<}`^gAH -zc=y^on0S2x`~xO3yOS7V&FW(yOm=!7dHSiV?7UA*7=VZVcmjxLhe_GCiaK#A3N9|q -zWtLQqEQL634#q(i?NK!FTxCmE1}V9Ha&&)l5&t<3Ng9nO=a@?2Nb)<9N)%EbN+o+H -z+rWJA;A;wgvGQ21=vC4nPT8QJ`)r;pUQa&*)Ui*zN%Z7u?G5;NXe9ia%F%f_2$yPA -z&qHfm#ygLPAd%wlF7mhYVe_={QBo3hB6-$(ZpmXl@Ca3BwA_pXsra-8&OMq#m4TYg -zTweNr-{{b<8jt=L=stuZ?Opmm!F7p`6(vb*fs8K#O_1{0Rkq||z*v$GHIzSw9(|Il -z{x=El@1iOcMUB&52t(Dhi@hi<6({gQ0Bb?(Yc9d0!{zR>vABHD!{uSXSX}PFrJA3_ -zI9$GmHbE#-M{}vDk;^AB)X(L!1kUdfi3+?6z?$(i?12#VT8x*$-Jp8kk}}ggW3CDq -zi}BL9RE$4Z$E#lB>4rvsM#+iypE}diWsxa7E)h}|Mp3C;@UJ9_@^4;bkiu-D{Od+X -zHu|H#;z^0guXG*N?my!Aw#&lO_0tSI-$!t%oslw8ENSFh*v_^9Bg3iVGg?lx4S5cn -z8|5WneQee^hCMw@Wg6oFXX;o)H#>wMD|xJt_-TR{0Ju~6H$uqrN5TTl{gF`F)ygKK -zqK7&eyE=p?`y#Qj#~72X!=;+6nQB{{?FG0N>XMCbJ8~@~ -zD$|gqFB=w=m!i!z0d2p{T}0Hy{$C8$26iJPa6J`dF^=NqsATJHEGMz_}-u^c~Ng_Kr5q$mY3U0h;~ -zAWhvUFuWc?G)DhJV{ng>0)4T=-y|%nKMQ9I?nm4o;OI@_tETV?hUV^$#svZB-h|Gs -zsV4~hTs$ap=T3Js8WHY?4v_PI+K>1uGJvf1BhJUeQLIAj$rlDoC7nr -z_anaYk%(&cBi0+nOJ_ggiYZjY73@d6n|RC)!b}9-pz7o8M|>Y8L{|F|Q(|I^w;!=R -zuw}g;(bitP{fLEtMVrGQw4xx4wIA`+G2V=^AMsasJ^y~h#oMuNW9~<60q-yE_*nZ9 -zx0VX*N1Swz1XLD5kM_UZe#B%@b%I0r>Tq+28XQ^)LzT}ffS;q$#-_n!-VuGTk@%51 -zsmc?%$BJp^@jj|!{pVNbgRghIfxel)pw+(S -z$MCQ+;787)jK}_Gf%~8Q$h~ljS^1Hk^Em(TBZ-wR??-lFORqMZ-v)D_*N@mZ;`x#B -zE{^*U*VRh02gdUwoz%c9_9HgVczz_0!s+!RkKXR}BX`dgQH>ut35SbI$Bzs^-U=bE -zz>oY3FAPX$UvqP~tDyAp{74tPDV3EUxquWbh%KHUDF|#?`w?4v@%+d}_VT*KZKa!K}=-7T_;sJNRr1k(0G&FwXx~DJaN6u_<{m9;` -zmLK`?DaVhj#m~_x$w5ET9?b}R|FpICBlhur;sv_oq8BjlOSJq|)WKBc*)u`Ea@Q!o -zU-<`>e<(6m;TMd1*o7yCqyY3rLO-gxVSbVyekkBqrV{Q>f%~8Q%J1moW#w0{Mu<`7 -z*aD6M8E=;P$?&PhkR}Y|K(Al1am4d0^<5l)VgUz<$MY*W)W9qDD>gIn{K`j2F0eAZ -ze&woLy?*6aJTkTX%G(2Y>G+jW6RC(R@GH}Z$M}_#hUzxJW^(!OL<~I4sC=6BkNniXNZCXF*S1zIa4@D-n(0;`}m{Yt! -zE)+NLBgU^(!0r(3SFSr1^eeweC*RX?dyn|*DExx4|44&jX#n~eLSLo1p -zAK`w&d;kBNUwI>E)_!F%LXI--%>^&-S1Pmf#=57$GaTskD>jaJe&rD2yEev2SinKz -z@%+kMHSmi4ip@+sztUde^!k;L@r1>$d*u0yd-o7Q4 -z^zr=4hvfmE>Yl3QEx&RbhAO{u4StTExWnUD -zq%&3~IuqO6Ly?9}rLS}X4KLk#i$<{Rgl#&$SuyYxu%CpJSMj9;JZAn@To-Tby%zLN -zsQwav*u)>igG@z_T6Msr%2L$oklMB;erl;6YI!uZBtNyM{M5P_YBgd|`wG37P~@=y -zwIg_jp@P|NS3_W5WfTd8nicwm0u!ZUrP{X`QD(Vxm15uN^gndtMRS|~tOz8~dk -zw27u#MyMu9^VcS>EoU0u$FQW$#HF&;-Y#KdHwmOWDaEhb(jK~7kN}I7miOznHj!J@ -zDi~_#u=xBl`8u+jP~_$SwT}{QDId|)D*LHzDB@caOZbDVi3|@l-5o4Paw{5(aMqhx -z(PW3*A{qJ;o|4gZGS;Z~toFaG1g;vs6H8a?S{li+9bhLWu>raKCn|kT%JOldr2dr=hEW`juRU_3SVOLeg(yv9|ClvYU -zZb|g;9P<#pG9Q2aVDU%a{Ja4nTimWCSsRTZ}9Lz;0%w6eSGzWFUx6=TNf`LSz9m<|0O?ZBihmZGg -zsn-0!xP0U$AMZ8t^HI*j$Mjwfde5V2;u -zfuUI>uADQ_%LqjpIFyZ?t6WU3K+Bqhc7}9S -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 -zX_mM+#>UPt2W}*J2-pZwFOZ>H4VG -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 -zOZFP{RQMQ(uCTVs*s7xh4Bt(ZWA?Ec