pax_global_header00006660000000000000000000000064145450241050014512gustar00rootroot0000000000000052 comment=ad2249eef4c9367259dfc1c4e7fa8dbaa1a16100 libioth-0.1.2/000077500000000000000000000000001454502410500131445ustar00rootroot00000000000000libioth-0.1.2/CMakeLists.txt000066400000000000000000000036251454502410500157120ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) project("libioth" DESCRIPTION "Internet of Threads library" HOMEPAGE_URL "https://github.com/virtualsquare/libioth" VERSION 0.1.0 LANGUAGES C) include(GNUInstallDirs) include(CheckIncludeFile) include(CheckSymbolExists) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_FORTIFY_SOURCE=2 -O2 -pedantic -Wall -Wextra") set(SYSTEM_IOTH_PATH ${CMAKE_INSTALL_FULL_LIBDIR}/ioth) set(LIBS_REQUIRED fduserdata vdeplug mhash) set(HEADERS_REQUIRED nlinline+.h fduserdata.h libvdeplug.h mhash.h) set(CMAKE_REQUIRED_QUIET TRUE) foreach(THISLIB IN LISTS LIBS_REQUIRED) find_library(LIB${THISLIB}_OK ${THISLIB}) if(NOT LIB${THISLIB}_OK) message(FATAL_ERROR "library lib${THISLIB} not found") endif() endforeach(THISLIB) foreach(HEADER IN LISTS HEADERS_REQUIRED) check_include_file(${HEADER} ${HEADER}_OK) if(NOT ${HEADER}_OK) message(FATAL_ERROR "header file ${HEADER} not found") endif() endforeach(HEADER) add_definitions(-D_GNU_SOURCE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR}) add_library(ioth SHARED ioth.c ioth_getifaddrs.c checklicense.c) target_link_libraries(ioth dl fduserdata) set_target_properties(ioth PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) install(TARGETS ioth DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ioth.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) add_library(iothaddr SHARED iothaddr.c) target_link_libraries(iothaddr mhash) set_target_properties(iothaddr PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) install(TARGETS iothaddr DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES iothaddr.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) configure_file(config.h.in config.h) add_subdirectory(test) add_subdirectory(modules) add_subdirectory(man) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${PROJECT_SOURCE_DIR}/Uninstall.cmake") libioth-0.1.2/COPYING000066400000000000000000000635041454502410500142070ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser 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 Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "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 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY 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 LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! libioth-0.1.2/COPYING.test000066400000000000000000000431231454502410500151600ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libioth-0.1.2/README.md000066400000000000000000000242461454502410500144330ustar00rootroot00000000000000# libioth ## The unified API for the Internet of Threads * the API is minimal: Berkeley Sockets + msocket + newstack/delstack. * the stack implementation can be chosen as a plugin at run time. * netlink based stack/interface/ip configuration via _nlinline_. * ioth sockets are real file descriptors, poll/select/ppoll/pselect/epoll friendly * plug-ins are loaded in private address namespaces: libioth supports several stacks of the same type (same plugin) even if the stack implementation library was designed to provide just one stack. ## Compile and Install Pre-requisites: `fduserdata`, `nlinline`. Libioth uses cmake. The standard building/installing procedure is: ```bash mkdir build cd build cmake .. make sudo make install ``` An uninstaller is provided for your convenience. In the build directory run: ``` sudo make uninstall ``` ## The API ### newstack There are three flavours of `ioth_newstack`: ```C struct ioth *ioth_newstack(const char *stack, const char *vnl); struct ioth *ioth_newstackl(const char *stack, const char *vnl, ... /* (char *) NULL */); struct ioth *ioth_newstackv(const char *stack, const char *vnlv[]); ``` * `ioth_newstack` creates a new stack without any interface if `vnl` is NULL, otherwise the new stack has a virtual interface connected to the vde network identified by the VNL (Virtual Network Locator, see [vdeplug4](https://github.com/rd235/vdeplug4) ). * `ioth_newstackl` and `ioth_newstackv` (l = list, v = vector) support the creation of a new stack with several interfaces. It is possible to provide the VNLs as a sequence of arguments (as in execl) or as a NULL terminated array of VNLs (as the arguments in execv). The return value is the ioth stack descriptor, NULL in case of error (errno provides the caller with a more detailed description of the error). ### delstack ```C int ioth_delstack(struct ioth *iothstack); ``` This function terminates/deletes a stack. It returns -1 in case of error, 0 otherwise. If there are file descriptors already in use, this function fails and errno is EBUSY. ### msocket ```C int ioth_msocket(struct ioth *iothstack, int domain, int type, int protocol); ``` This is the multi-stack supporting extension of `socket`(2). It behaves exactly as `socket` except for the added heading argument that allows the choice of the stack among those currently available (previously created by a `ioth_newstack*`. ### default stack ```C void ioth_set_defstack(struct ioth *iothstack); struct ioth *ioth_get_defstack(void); ``` These functions define and retrieve the default stack, respectively. The default stack is implicitely used by `ioth_msocket` when its first argument `iothstack` is NULL. The default stack is initially defined as the native stack provided by the kernel. Use `ioth_set_defstack(mystack)` to define `mystack` as the current default stack. `ioth_set_defstack(NULL)` to revert the default stack to the native stack. ### socket ```C int ioth_socket(int domain, int type, int protocol); ``` `ioth_socket` opens a socket using the default stack: `ioth_socket(d, t, p)` is an alias for `ioth_msocket(NULL, d, t, p)` ### for everything else... Berkeley Sockets `ioth_close`, `ioth_bind`, `ioth_connect`, `ioth_listen`, `ioth_accept`, `ioth_getsockname`, `ioth_getpeername`, `ioth_setsockopt`, `ioth_getsockopt`, `ioth_shutdown`, `ioth_ioctl`, `ioth_fcntl`, `ioth_read`, `ioth_readv`, `ioth_recv`, `ioth_recvfrom`, `ioth_recvmsg`, `ioth_write`, `ioth_writev`, `ioth_send`, `ioth_sendto` and `ioth_sendmsg` have the same signature and functionalities of their counterpart without the `ioth_` prefix. ### extra features for free: nlinline netlink configuration functions [`nlinline+`](https://github.com/virtualsquare/nlinline) provides a set of inline functions for the stack interface/ip address and route configuration: ```C int ioth_if_nametoindex(const char *ifname); int ioth_linksetupdown(unsigned int ifindex, int updown); int ioth_ipaddr_add(int family, void *addr, int prefixlen, unsigned int ifindex); int ioth_ipaddr_del(int family, void *addr, int prefixlen, unsigned int ifindex); int ioth_iproute_add(int family, void *dst_addr, int dst_prefixlen, void *gw_addr, unsigned int ifindex); int ioth_iproute_del(int family, void *dst_addr, int dst_prefixlen, void *gw_addr, unsigned int ifindex); int ioth_iplink_add(const char *ifname, unsigned int ifindex, const char *type, const char *data); int ioth_iplink_del(const char *ifname, unsigned int ifindex); int ioth_linksetaddr(unsigned int ifindex, void *macaddr); int ioth_linkgetaddr(unsigned int ifindex, void *macaddr); ``` a detailed description can be found in `nlinline`(3). ### License management. `liblwip` verifies that the program and the stack implementation plugin have compatible licenses. A program can specify its license by the `ioth_set_license` function. Licenses are encoded using SPDX. e.g.: ``` #define SPDX_LICENSE "SPDX-License-Identifier: GPL-2.0-or-later" ... ioth_set_license(SPDX_LICENSE); ``` If a program does not specify its license it can load a stack plugin only if the plugin can be linked to proprietary programs. The license of a plugin is defined by a global variable named `ioth_xxxx_license` (where xxxx is the name of the plugin). e.g.: ``` const char *ioth_vdestack_license = "SPDX-License-Identifier: LGPL-2.1-or-later"; ``` or ``` const char *ioth_picox_license = "SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only"; ``` If a plugin does not specify any license tag it means that has no license requirements. Note: the current implementation of the license checker supports the following plugin licenses: `LGPL-*`, `GPL-2.0-or-later`, `GPL-3.0-or-later`, `GPL-2.0-only OR GPL-3.0-only`. ## Example: an IPv4 TCP echo server The complete source code of this example is provided in this git repository: [`iothtest_server.c`](https://github.com/virtualsquare/libioth/blob/master/test/iothtest_server.c). The code creates a virtual stack, activates the interface named `vde0`, sets the interface's address to 192.168.250.50/24 and runs a TCP echo server on port 5000. When a new connection begins, i.e. when `accept`(2) returns a new file descriptor, `iothtest_server` creates a thread to process the new stream. ## Example: an IPv4 TCP terminal client The complete source code of this example is provided in this git repository: [`iothtest_client.c`](https://github.com/virtualsquare/libioth/blob/master/test/iothtest_client.c). The code creates a virtual stack, activates the interface named `vde0`, sets the interface's address to 192.168.250.51/24 and runs a TCP terminal emulation client trying to get connected to 192.168.250.50 port 5000. Please note that `iothtest_client.c` uses a `poll`(2) system call to wait for available input on a ioth socket and on `stdin`. ## testing * start a vde switch: ```bash vde_plug null:// switch:///tmp/sw ``` * in a second terminal run the server using one of the following commands: ```bash ./iothtest_server vdestack vde:///tmp/sw vdens vde:// ./iothtest_server kernel ``` * in a third terminal run the client, again the stack implementation can be decided by choosing one of the following commands: ```bash ./iothtest_client vdestack vde:///tmp/sw vdens vde:// ./iothtest_client kernel ``` * now whatever is typed in the client is echoed back, the serveer produces a log of open/closed connections and echoed messages. ## The API for plugin development The structure of the source code a `ioth` plugin for the stack `foo` is the following: ```C file ioth_foo.c: #include static typeof(getstackdata_prototype) *getstackdata; void *ioth_foo_newstack(const char *vnlv[], struct ioth_functions *ioth_f) { // create a new foo stack and save some data for the other functions struct vdestack *stackdata = ... // save getstackdata for the other functions getstackdata = ioth_f->getstackdata; // set the handler for all the functions // example 1: use the system call ioth_f->bind = bind; // example 2: provide a specific function (implicit assignment). // just name the function as ioth_foo_bind. // in such a case the following assignment is automatic: // ioth->bind = ioth_foo_bind; // example 2: provide a specific function (explicit assignment) ioth_f->bind = mybind; .... and so on for all the other functions return stackdata; } int ioth_foo_delstack(void *stackdata) { // delete the foo stack return .... // 0 = success, -1 = failure (+ errno) } // example for socket int ioth_foo_socket(int domain, int type, int protocol) { struct foodata *stackdata = getstackdata(); return foo_msocket(stackdata, domain, type, protocol); } ``` This plugin can be compiled using the following command: ```sh gcc -o ioth_foo.so -fPIC -shared ioth_foo.c ``` The plugin does not need any ioth specific library. The plugin `ioth_foo.so` must be installed: * in the global plugin directory: `/usr/lib/ioth` or `/usr/local/lib/ioth` or `/usr/lib/x86_64-linux-gnu/ioth` (or similar) depending on where `libioth.so` is installed (`/usr/lib` or `/usr/local/lib` or `/usr/lib/x86_64-linux-gnu` respectively). * in the user local directory: the hidden subdirectory named `.ioth` of the user's home directory. When libioth is required to create a new stack of type `foo`, it loads the plugin named `ioth_foo.so`. If the plugin has a `-r` suffix in its name (e.g. `ioth_foo-r.so`) it means that the plugin is reentrant, it is able to manage several stacks concurrently in the same address space (otherwise `libioth` creates a new memory address space for each stack). When the plugin has been loaded, ioth searches and runs the function `ioth_foo_newstack` passing it two parameters: the array on VNLs to define the virtual interfaces, and a structure whose fields are function pointers: `ioth_functions`. This structure includes `getstackdata`, `newstack`, `delstack` and all the functions of the Berkeley Sockets API. The function `getstackdata` is provided by libioth and can be saved (all the other function can call `getstackdata()` to retrieve the pointer returned by `ioth_foo_newstack`). All the other function pointers (except `getstackdata`) can be assigned to their implementation. Alternatively, if the plugin defines functions prefixed by `ioth_foo_`, these are automatically recognized and used. libioth-0.1.2/Uninstall.cmake000066400000000000000000000010361454502410500161170ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) set(MANIFEST "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt") if(NOT EXISTS ${MANIFEST}) message(FATAL_ERROR "Cannot find install manifest: '${MANIFEST}'") endif() file(STRINGS ${MANIFEST} files) foreach(file ${files}) if(EXISTS ${file} OR IS_SYMLINK ${file}) message(STATUS "Removing: ${file}") execute_process( COMMAND rm -f ${file} RESULT_VARIABLE retcode ) if(NOT "${retcode}" STREQUAL "0") message(WARNING "Failed to remove: ${file}") endif() endif() endforeach(file) libioth-0.1.2/checklicense.c000066400000000000000000000044771454502410500157440ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * * Copyright (C) 2022 Renzo Davoli VirtualSquare team. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include #include #define SPDX_PREFIX "SPDX-License-Identifier: " #define SPDX_PREFIXLEN (sizeof(SPDX_PREFIX) - 1) /* This implementation manages only a small subset of possible license * combinations. */ int checklicense(const char *prglicense, const char *liblicense) { /* No lib license restrictions: ok to load */ if (liblicense == NULL) return 1; if (strncmp(liblicense, SPDX_PREFIX, SPDX_PREFIXLEN) == 0) liblicense += SPDX_PREFIXLEN; /* It is a permissive library */ if (strncasecmp(liblicense, "LGPL-", 5) == 0) return 1; /* Lib has requirements, no license spec from prg -> deny */ if (prglicense == NULL) return 0; if (strncmp(prglicense, SPDX_PREFIX, SPDX_PREFIXLEN) == 0) prglicense += SPDX_PREFIXLEN; /* It is the very same license: OK */ if (strcasecmp(prglicense, liblicense) == 0) return 1; if (strcasecmp(liblicense, "GPL-2.0-or-later") == 0) { if (strcasecmp(prglicense, "GPL-2.0-only") == 0 || strcasecmp(prglicense, "GPL-3.0-only") == 0 || strcasecmp(prglicense, "GPL-2.0-or-later") == 0 || strcasecmp(prglicense, "GPL-3.0-or-later") == 0) return 1; return 0; } if (strcasecmp(liblicense, "GPL-3.0-or-later") == 0) { if (strcasecmp(prglicense, "GPL-3.0-only") == 0 || strcasecmp(prglicense, "GPL-3.0-or-later") == 0) return 1; return 0; } if (strcasecmp(liblicense, "GPL-2.0-only OR GPL-3.0-only") == 0) { if (strcasecmp(prglicense, "GPL-2.0-only") == 0 || strcasecmp(prglicense, "GPL-3.0-only") == 0 || strcasecmp(prglicense, "GPL-2.0-or-later") == 0 || strcasecmp(prglicense, "GPL-3.0-or-later") == 0) return 1; return 0; } /* in doubt deny */ return 0; } #if 0 int main(int argc, char *argv[]) { printf("%d\n", licensecheck(argv[1], argv[2])); } #endif libioth-0.1.2/checklicense.h000066400000000000000000000001701454502410500157330ustar00rootroot00000000000000#ifndef CHECKLICENSE_H #define CHECKLICENSE_H int checklicense(const char *prglicense, const char *liblicense); #endif libioth-0.1.2/config.h.in000066400000000000000000000001311454502410500151620ustar00rootroot00000000000000#ifndef CONFIG_H #define CONFIG_H #define SYSTEM_IOTH_PATH "@SYSTEM_IOTH_PATH@" #endif libioth-0.1.2/ioth.c000066400000000000000000000400431454502410500142540ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * * Copyright (C) 2020 Renzo Davoli VirtualSquare team. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include static FDUSERDATA *fdtable; static __thread void *stackdata; static const char *proglicense; void ioth_set_license(const char *license) { proglicense = license; } #define FOREACHDEFFUN \ __MACROFUN(newstack) \ __MACROFUN(delstack) \ FOREACHFUN #define FOREACHFUN \ __MACROFUN(socket) \ __MACROFUN(close) \ __MACROFUN(bind) \ __MACROFUN(connect) \ __MACROFUN(listen) \ __MACROFUN(accept) \ __MACROFUN(getsockname) \ __MACROFUN(getpeername) \ __MACROFUN(setsockopt) \ __MACROFUN(getsockopt) \ __MACROFUN(shutdown) \ __MACROFUN(ioctl) \ __MACROFUN(fcntl) \ __MACROFUN(read) \ __MACROFUN(readv) \ __MACROFUN(recv) \ __MACROFUN(recvfrom) \ __MACROFUN(recvmsg) \ __MACROFUN(write) \ __MACROFUN(writev) \ __MACROFUN(send) \ __MACROFUN(sendto) \ __MACROFUN(sendmsg) struct ioth { void *handle; void *stackdata; _Atomic unsigned int count; struct ioth_functions f; }; static struct ioth native_iothstack = { #define __MACROFUN(X) .f.X = X, FOREACHFUN #undef __MACROFUN }; static struct ioth *default_iothstack = &native_iothstack; static void *getstackdata(void) { return stackdata; } #define SYMBOL_PREFIX "ioth_" #ifndef USER_IOTH_PATH #define USER_IOTH_PATH "/.ioth" #endif /* this whould be defind by cmake in config.h */ #ifndef SYSTEM_IOTH_PATH #define SYSTEM_IOTH_PATH "/usr/local/lib/ioth" #endif static inline char *gethomedir(void) { char *homedir = getenv("HOME"); /* If there is no home directory, use CWD */ if (!homedir) homedir = "."; return homedir; } static void *ioth_dlopen(const char *modname, int flags) { char path[PATH_MAX]; char *homedir = gethomedir(); #define TRY_DLOPEN(LMID, ...) \ do { \ void *handle; \ snprintf(path, PATH_MAX, __VA_ARGS__); \ if ((handle = dlmopen(LMID, path, flags))) { \ return handle; \ } \ } while(0) TRY_DLOPEN(LM_ID_BASE, "%s%s/ioth_%s-r.so", homedir, USER_IOTH_PATH, modname); TRY_DLOPEN(LM_ID_NEWLM, "%s%s/ioth_%s.so", homedir, USER_IOTH_PATH, modname); TRY_DLOPEN(LM_ID_BASE, "%s/ioth_%s-r.so", SYSTEM_IOTH_PATH, modname); TRY_DLOPEN(LM_ID_NEWLM, "%s/ioth_%s.so", SYSTEM_IOTH_PATH, modname); #ifdef DEBUG TRY_DLOPEN(LM_ID_BASE, "./ioth_%s-r.so", modname); TRY_DLOPEN(LM_ID_NEWLM, "./ioth_%s.so", modname); #endif #undef TRY_DLOPEN return NULL; } static void *ioth_dlsym(void *handle, const char *modname, const char *symbol) { size_t extended_symbol_len = sizeof(SYMBOL_PREFIX) + 1 + strlen(modname) + strlen(symbol); char extended_symbol[extended_symbol_len]; snprintf(extended_symbol, extended_symbol_len, SYMBOL_PREFIX "%s_%s", modname, symbol); // printf("%s\n", extended_symbol); return dlsym(handle, extended_symbol); } #define gotoerr(err, label) do {errno = err; goto label;} while(0) static struct ioth *_ioth_newstackv(const char *stack, const char *options, const char *vnlv[]) { struct ioth *iothstack = calloc(1, sizeof(struct ioth)); if (iothstack == NULL) gotoerr (ENOMEM, retNULL); if (stack == NULL || *stack == '\0') { *iothstack = native_iothstack; iothstack->count = 0; } else { char **pstacklicense = NULL; char *stacklicense = NULL; iothstack->handle = ioth_dlopen(stack, RTLD_NOW); // printf("dlopen %p\n", iothstack->handle); if (iothstack->handle == NULL) gotoerr (ENOTSUP, errdl); iothstack->f.getstackdata = getstackdata; pstacklicense = ioth_dlsym(iothstack->handle, stack, "license"); if (pstacklicense != NULL) stacklicense = *pstacklicense; if (checklicense(proglicense, stacklicense) != 1) gotoerr (EPERM, errnoioth); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpedantic" #define __MACROFUN(X) iothstack->f.X = ioth_dlsym(iothstack->handle, stack, #X); { FOREACHDEFFUN } #undef __MACROFUN #pragma GCC diagnostic pop if (iothstack->f.newstack == NULL) gotoerr (ENOENT, errnoioth); iothstack->stackdata = iothstack->f.newstack(vnlv, options, &iothstack->f); if (iothstack->stackdata == NULL) goto errnoioth; } return iothstack; errnoioth: dlclose(iothstack->handle); errdl: free(iothstack); retNULL: return NULL; } struct ioth *ioth_newstackv(const char *stack, const char *vnlv[]) { char *options; if (stack == NULL || (options = strchr(stack, ',')) == NULL) return _ioth_newstackv(stack, "", vnlv); else { char stacklen = (++options) - stack; char _stack[stacklen]; snprintf(_stack, stacklen, "%s", stack); return _ioth_newstackv(_stack, options, vnlv); } } struct ioth *ioth_newstack(const char *stack, const char *vnl) { if (vnl == NULL) { const char *vnlv[] = {(char *) NULL}; return ioth_newstackv(stack, vnlv); } else { const char *vnlv[] = {vnl, (char *) NULL}; return ioth_newstackv(stack, vnlv); } } struct ioth *ioth_newstackl(const char *stack, const char *vnl, ... /* (char *) NULL */) { if (vnl == (char *) NULL) return ioth_newstack(stack, NULL); else { va_list ap; int countargs; va_start(ap, vnl); for (countargs = 1; va_arg(ap, const char *) != (char *) NULL; countargs++) ; va_end(ap); const char *vnlv[countargs + 1]; vnlv[0] = vnl; va_start(ap, vnl); for (countargs = 1; (vnlv[countargs] = va_arg(ap, const char *)) != (char *) NULL; countargs++) ; va_end(ap); return ioth_newstackv(stack, vnlv); } } int ioth_delstack(struct ioth *iothstack) { int retval; if (iothstack == NULL) return errno = EINVAL, -1; if (iothstack->count > 0) return errno = EBUSY, -1; if (iothstack->f.delstack == NULL) retval = 0; else retval = iothstack->f.delstack(iothstack->stackdata); if (retval == 0) { if (iothstack->handle != NULL) dlclose(iothstack->handle); free(iothstack); } return retval; } void ioth_set_defstack(struct ioth *iothstack) { if (iothstack == NULL) default_iothstack = &native_iothstack; else default_iothstack = iothstack; } struct ioth *ioth_get_defstack(void) { return default_iothstack; } int ioth_msocket(struct ioth *iothstack, int domain, int type, int protocol) { int fd; if (iothstack == NULL) iothstack = default_iothstack; iothstack->count++; stackdata = iothstack->stackdata; if (iothstack->f.socket == NULL) return errno = ENOSYS, -1; fd = iothstack->f.socket(domain, type, protocol); if (fd < 0) iothstack->count--; else { struct ioth **ioth = fduserdata_new(fdtable, fd, struct ioth *); *ioth = iothstack; fduserdata_put(ioth); } return fd; } int ioth_socket(int domain, int type, int protocol) { return ioth_msocket(NULL, domain, type, protocol); } /* get the ioth stack from fduserdata */ static inline struct ioth *ioth_getstack(int fd) { struct ioth **ioth = fduserdata_get(fdtable, fd); if (ioth == NULL) return NULL; struct ioth *iothstack = *ioth; fduserdata_put(ioth); stackdata = iothstack->stackdata; return iothstack; } /* get the ioth stack from fduserdata assign it to "iothstack" * and check if fun exists */ #define IOTH_getiothstack_ck(fd, fun) \ struct ioth *iothstack = ioth_getstack(fd); \ if (iothstack == NULL) \ return errno = EBADF, -1; \ if (iothstack->f.fun == NULL) \ return errno = ENOSYS, -1 /* get the ioth stack from fduserdata assign it to "iothstack" * do not check if fun exists and call _ioth_xxx where xxx is fun stringified. * e.g. "IOTH_stackfun(fd, read)" calls _ioth_read. * This maxro has been designed as a prefix to the arguments of the called function */ #define IOTH_stackfun(fd, fun) \ struct ioth *iothstack = ioth_getstack(fd); \ if (iothstack == NULL) \ return errno = EBADF, -1; \ return _ioth_ ## fun /* get the ioth stack from fduserdata assign it to "iothstack" * check if fun exists and call the implementation of fun provided by the stack. * This maxro has been designed as a prefix to the arguments of the called function */ #define IOTH_fwfun(fd, fun) \ IOTH_getiothstack_ck(fd, fun); \ return iothstack->f.fun int ioth_close(int fd) { int retval; struct ioth **ioth = fduserdata_get(fdtable, fd); if (ioth == NULL) return errno = ENOSYS, -1; struct ioth *iothstack = *ioth; if (iothstack->f.close == NULL) return errno = ENOSYS, -1; retval = iothstack->f.close(fd); if (retval == 0) { iothstack->count--; fduserdata_del(ioth); } else fduserdata_put(ioth); return retval; } int ioth_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) { int newfd; IOTH_getiothstack_ck(fd, accept); newfd = iothstack->f.accept(fd, addr, addrlen); if (newfd >= 0) { struct ioth **ioth = fduserdata_new(fdtable, newfd, struct ioth *); *ioth = iothstack; iothstack->count++; fduserdata_put(ioth); } return newfd; } static ssize_t _ioth_read(struct ioth *iothstack, int fd, void *buf, size_t len); static ssize_t _ioth_readv(struct ioth *iothstack, int fd, const struct iovec *iov, int iovcnt); static ssize_t _ioth_recv(struct ioth *iothstack, int fd, void *buf, size_t len, int flags); static ssize_t _ioth_recvfrom(struct ioth *iothstack, int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); static ssize_t _ioth_recvmsg(struct ioth *iothstack, int fd, struct msghdr *msg, int flags); static ssize_t _ioth_write(struct ioth *iothstack, int fd, const void *buf, size_t size); static ssize_t _ioth_writev(struct ioth *iothstack, int fd, const struct iovec *iov, int iovcnt); static ssize_t _ioth_send(struct ioth *iothstack, int fd, const void *buf, size_t size, int flags); static ssize_t _ioth_sendto(struct ioth *iothstack, int fd, const void *buf, size_t size, int flags, const struct sockaddr *to, socklen_t tolen); static ssize_t _ioth_sendmsg(struct ioth *iothstack, int fd, const struct msghdr *msg, int flags); static ssize_t _ioth_read(struct ioth *iothstack, int fd, void *buf, size_t len) { if (iothstack->f.read) return iothstack->f.read(fd, buf, len); else return _ioth_recv(iothstack, fd, buf, len, 0); } static ssize_t _ioth_readv(struct ioth *iothstack, int fd, const struct iovec *iov, int iovcnt) { if (iothstack->f.readv) return iothstack->f.readv(fd, iov, iovcnt); else if (iothstack->f.recvmsg) { struct msghdr mhdr = { .msg_iov = (struct iovec *)iov, .msg_iovlen = iovcnt }; return iothstack->f.recvmsg(fd, &mhdr, 0); } else // map to read return errno = ENOSYS, -1; } static ssize_t _ioth_recv(struct ioth *iothstack, int fd, void *buf, size_t len, int flags) { if (iothstack->f.recv) return iothstack->f.recv(fd, buf, len, flags); else return _ioth_recvfrom(iothstack, fd, buf, len, flags, NULL, NULL); } static ssize_t _ioth_recvfrom(struct ioth *iothstack, int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { if (iothstack->f.recvfrom) return iothstack->f.recvfrom( fd, buf, len, flags, from, fromlen); else if (iothstack->f.recvmsg) { struct iovec iov[] = {{buf, len}}; struct msghdr mhdr = { .msg_name = from, .msg_namelen = (fromlen) ? *fromlen : 0, .msg_iov = iov, .msg_iovlen = 1}; ssize_t retval = iothstack->f.recvmsg(fd, &mhdr, flags); if (retval >= 0 && fromlen) *fromlen = mhdr.msg_namelen; return retval; } else return errno = ENOSYS, -1; } static ssize_t _ioth_recvmsg(struct ioth *iothstack, int fd, struct msghdr *msg, int flags) { if (iothstack->f.recvmsg) { return iothstack->f.recvmsg(fd, msg, flags); } else return errno = ENOSYS, -1; } static ssize_t _ioth_write(struct ioth *iothstack, int fd, const void *buf, size_t len) { if (iothstack->f.write) return iothstack->f.write(fd, buf, len); else return _ioth_send(iothstack, fd, buf, len, 0); } static ssize_t _ioth_writev(struct ioth *iothstack, int fd, const struct iovec *iov, int iovcnt) { if (iothstack->f.writev) return iothstack->f.writev(fd, iov, iovcnt); else if (iothstack->f.sendmsg) { struct msghdr mhdr = { .msg_iov = (struct iovec *)iov, .msg_iovlen = iovcnt }; return iothstack->f.sendmsg(fd, &mhdr, 0); } else // map to write return errno = ENOSYS, -1; } static ssize_t _ioth_send(struct ioth *iothstack, int fd, const void *buf, size_t len, int flags) { if (iothstack->f.send) return iothstack->f.send(fd, buf, len, flags); else return _ioth_sendto(iothstack, fd, buf, len, flags, NULL, 0); } static ssize_t _ioth_sendto(struct ioth *iothstack, int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { if (iothstack->f.sendto) return iothstack->f.sendto( fd, buf, len, flags, to, tolen); else if (iothstack->f.sendmsg) { struct iovec iov[] = {{(void *)buf, (size_t)len}}; struct msghdr mhdr = { .msg_name = (struct sockaddr *) to, .msg_namelen = tolen, .msg_iov = iov, .msg_iovlen = 1}; return iothstack->f.sendmsg(fd, &mhdr, flags); } else return errno = ENOSYS, -1; } static ssize_t _ioth_sendmsg(struct ioth *iothstack, int fd, const struct msghdr *msg, int flags) { if (iothstack->f.sendmsg) { return iothstack->f.sendmsg(fd, msg, flags); } else return errno = ENOSYS, -1; } ssize_t ioth_read(int fd, void *buf, size_t len) { IOTH_stackfun(fd, read) (iothstack, fd, buf, len); } ssize_t ioth_readv(int fd, const struct iovec *iov, int iovcnt) { IOTH_stackfun(fd, readv) (iothstack, fd, iov, iovcnt); } ssize_t ioth_recv(int fd, void *buf, size_t len, int flags) { IOTH_stackfun(fd, recv) (iothstack, fd, buf, len, flags); } ssize_t ioth_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { IOTH_stackfun(fd, recvfrom) (iothstack, fd, buf, len, flags, from, fromlen); } ssize_t ioth_recvmsg(int fd, struct msghdr *msg, int flags) { IOTH_stackfun(fd, recvmsg) (iothstack, fd, msg, flags); } ssize_t ioth_write(int fd, const void *buf, size_t len) { IOTH_stackfun(fd, write) (iothstack, fd, buf, len); } ssize_t ioth_writev(int fd, const struct iovec *iov, int iovcnt) { IOTH_stackfun(fd, writev) (iothstack, fd, iov, iovcnt); } ssize_t ioth_send(int fd, const void *buf, size_t len, int flags) { IOTH_stackfun(fd, send) (iothstack, fd, buf, len, flags); } ssize_t ioth_sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { IOTH_stackfun(fd, sendto) (iothstack, fd, buf, len, flags, to, tolen); } ssize_t ioth_sendmsg(int fd, const struct msghdr *msg, int flags) { IOTH_stackfun(fd, sendmsg) (iothstack, fd, msg, flags); } int ioth_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { IOTH_fwfun(fd, bind) (fd, addr, addrlen); } int ioth_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) { IOTH_fwfun(fd, connect) (fd, addr, addrlen); } int ioth_listen(int fd, int backlog) { IOTH_fwfun(fd, listen) (fd, backlog); } int ioth_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) { IOTH_fwfun(fd, getsockname) (fd, addr, addrlen); } int ioth_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) { IOTH_fwfun(fd, getpeername) (fd, addr, addrlen); } int ioth_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) { IOTH_fwfun(fd, setsockopt) (fd, level, optname, optval, optlen); } int ioth_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) { IOTH_fwfun(fd, getsockopt) (fd, level, optname, optval, optlen); } int ioth_shutdown(int fd, int how) { IOTH_fwfun(fd, shutdown) (fd, how); } int ioth_ioctl(int fd, unsigned long cmd, void *argp) { IOTH_fwfun(fd, ioctl) (fd, cmd, argp); } int ioth_fcntl(int fd, int cmd, long val) { IOTH_fwfun(fd, fcntl) (fd, cmd, val); } __attribute__((constructor)) static void init(void) { fdtable = fduserdata_create(0); } __attribute__((destructor)) static void fini(void) { FDUSERDATA *oldfdtable = fdtable; fdtable = NULL; fduserdata_destroy(oldfdtable); } libioth-0.1.2/ioth.h000066400000000000000000000115411454502410500142620ustar00rootroot00000000000000#ifndef LIBIOTH_H #define LIBIOTH_H #include #include #include #include #include #include #include #include struct ioth; /* ioth stack create/destroy */ /* License Management: set program license (SPDX Specification) */ void ioth_set_license(const char *license); /* one interface (or no interfaces if vnl == NULL) */ struct ioth *ioth_newstack(const char *stack, const char *vnl); /* up to several interfaces */ struct ioth *ioth_newstackl(const char *stack, const char *vnl, ... /* (char *) NULL */); struct ioth *ioth_newstackv(const char *stack, const char *vnlv[]); int ioth_delstack(struct ioth *iothstack); void ioth_set_defstack(struct ioth *iothstack); struct ioth *ioth_get_defstack(void); /* communication primitives */ int ioth_msocket(struct ioth *iothstack, int domain, int type, int protocol); int ioth_socket(int domain, int type, int protocol); int ioth_close(int fd); int ioth_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); int ioth_connect(int fd, const struct sockaddr *addr, socklen_t addrlen); int ioth_listen(int fd, int backlog); int ioth_accept(int fd, struct sockaddr *addr, socklen_t *addrlen); int ioth_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen); int ioth_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen); ssize_t ioth_read(int fd, void *buf, size_t len); ssize_t ioth_readv(int fd, const struct iovec *iov, int iovcnt); ssize_t ioth_recv(int fd, void *buf, size_t len, int flags); ssize_t ioth_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); ssize_t ioth_recvmsg(int fd, struct msghdr *msg, int flags); ssize_t ioth_write(int fd, const void *buf, size_t len); ssize_t ioth_writev(int fd, const struct iovec *iov, int iovcnt); ssize_t ioth_send(int fd, const void *buf, size_t len, int flags); ssize_t ioth_sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); ssize_t ioth_sendmsg(int fd, const struct msghdr *msg, int flags); int ioth_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen); int ioth_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen); int ioth_shutdown(int fd, int how); int ioth_ioctl(int fd, unsigned long cmd, void *argp); int ioth_fcntl(int fd, int cmd, long val); NLINLINE_LIBMULTI(ioth_) int ioth_getifaddrs(struct ioth *stack, struct ifaddrs **ifap); void ioth_freeifaddrs(struct ifaddrs *ifa); /* ----------------------------------- for ioth plugins */ struct ioth_functions; void *newstack_prototype(const char *vnlv[], const char *options, struct ioth_functions *ioth_f); int delstack_prototype(void *stackdata); void *getstackdata_prototype(void); /* libc + _GNU_SOURCE uses a transparent union for sockaddr * (__SOCKADDR_ARG __CONST_SOCKADDR_ARG) * Unfortunately this choice generates warnings for gcc in pedantic mode. * so ioth_X is used instead of X as protoype for all X in Berkeley * sockets API using sockaddr. */ struct ioth_functions { typeof(getstackdata_prototype) *getstackdata; typeof(newstack_prototype) *newstack; typeof(delstack_prototype) *delstack; typeof(socket) *socket; typeof(close) *close; typeof(ioth_bind) *bind; typeof(ioth_connect) *connect; typeof(listen) *listen; typeof(ioth_accept) *accept; typeof(ioth_getsockname) *getsockname; typeof(ioth_getpeername) *getpeername; typeof(setsockopt) *setsockopt; typeof(getsockopt) *getsockopt; typeof(shutdown) *shutdown; typeof(ioctl) *ioctl; typeof(fcntl) *fcntl; typeof(read) *read; typeof(readv) *readv; typeof(recv) *recv; typeof(ioth_recvfrom) *recvfrom; typeof(recvmsg) *recvmsg; typeof(write) *write; typeof(writev) *writev; typeof(send) *send; typeof(ioth_sendto) *sendto; typeof(sendmsg) *sendmsg; }; /* ------------------ MAC address conversions --------------- */ #define MAC_ADDRSTRLEN 18 /* This function converts a 6 byte MAC address family into a character string. The buffer dst must be at least MAC_ADDRSTRLEN bytes */ static inline const char *ioth_ntomac(const void *src, char *dst, size_t size) { const unsigned char *mac = src; snprintf(dst, size, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return dst; } /* This function converts the character string src into a 6 byte MAC address. src points to a characteer string in the form "xx:xx:xx:xx:xx:xx" or "xx-xx-xx-xx-xx-xx" where xx is a sequence of two hexadecimal digits (not case sensitive) */ static inline int ioth_macton(const char *src, void *dst) { unsigned char *mac = dst; if (sscanf(src, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5) != 6) if (sscanf(src, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", mac, mac + 1, mac + 2, mac + 3, mac + 4, mac + 5) != 6) return 0; return 1; } #endif libioth-0.1.2/ioth_getifaddrs.c000066400000000000000000000244431454502410500164560ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * ioth_getifaddrs: getifaddrs(3)/freeifaddrs(3) replacements for ioth * * Copyright (C) 2021 Renzo Davoli VirtualSquare team. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #define FORALL_NLMSG(nlmsg, buf, len) \ for(nlmsg = (struct nlmsghdr *) buf; NLMSG_OK (nlmsg, len); nlmsg = NLMSG_NEXT (nlmsg, len)) #define NLA_OK(nla, len) ((len) >= (int)sizeof(struct nlattr) && \ ((nla)->nla_len & NLA_TYPE_MASK) >= sizeof(struct nlattr) && \ ((nla)->nla_len & NLA_TYPE_MASK) <= (len)) #define NLA_NEXT(nla,attrlen) ((attrlen) -= RTA_ALIGN(((nla)->nla_len & NLA_TYPE_MASK)), \ (struct nlattr*)(((char*)(nla)) + RTA_ALIGN(((nla)->nla_len & NLA_TYPE_MASK)))) /* scan netlink attributes -> load pointers in the attrs array */ static void nl_getattrs(void *attrbase, size_t attrlen, struct nlattr **attrs, int nattrs) { struct nlattr *scan; memset(attrs, 0, nattrs * sizeof(struct attr *)); for (scan = attrbase; NLA_OK(scan, attrlen); scan = NLA_NEXT(scan, attrlen)) { if (scan->nla_type < nattrs) attrs[scan->nla_type] = scan; } } /* delete a struct ifaddrs element */ #define ck_n_free(x) if (x) free(x) static void _freeifaddr(struct ifaddrs *ifa) { ck_n_free(ifa->ifa_name); ck_n_free(ifa->ifa_addr); ck_n_free(ifa->ifa_netmask); ck_n_free(ifa->ifa_broadaddr); ck_n_free(ifa->ifa_data); free(ifa); } /* add an element at the end of the ifap list */ static void add_ifaddrs(struct ifaddrs *new, struct ifaddrs **ifap) { new->ifa_next = NULL; for (; *ifap != NULL; ifap = &((*ifap)->ifa_next)) ; *ifap = new; } /******************** first netlink request (GETLINK/AF_PACKET) */ /* add name */ static char *add_ifla_ifname(struct nlattr *attr) { if (attr) return strndup((char *)(attr + 1), attr->nla_len); return NULL; } /* add a sockaddr_ll (ifa_addr, ifa_broadaddr) */ static void *add_sockaddr_ll(struct nlattr *attr, int ifindex, unsigned ifi_type) { struct sockaddr_ll *ll; if (attr != NULL && attr->nla_len > sizeof(*attr) && attr->nla_len <= sizeof(*attr) + sizeof(ll->sll_addr)) { int halen = attr->nla_len - sizeof(*attr); ll = calloc(1, sizeof(*ll)); if (ll) { ll->sll_family = AF_PACKET; ll->sll_ifindex = ifindex; ll->sll_hatype = ifi_type; ll->sll_halen = halen; memcpy (ll->sll_addr, attr + 1, halen); return ll; } } return NULL; } /* add ifa_data from IFLA_STATS */ static void *add_ifla_data(struct nlattr *attr) { if (attr != NULL && attr->nla_len == sizeof(*attr) + sizeof(struct rtnl_link_stats)) { void *data = malloc(sizeof(struct rtnl_link_stats)); if (data) { memcpy(data, attr + 1, sizeof(struct rtnl_link_stats)); return data; } } return NULL; } /* process a GETLINK reply item -> create an AF_PACKET ifaddrs elemet */ static void add_af_packet(struct nlmsghdr *nlmsg, struct ifaddrs **ifap) { struct ifinfomsg *info = (struct ifinfomsg *) (nlmsg + 1); int32_t len = nlmsg->nlmsg_len - sizeof(*info); if (len < 0) return; struct ifaddrs *new = calloc(1, sizeof(*new)); if (new) { struct nlattr *attrs[IFLA_MAX + 1]; nl_getattrs(info + 1, len - sizeof(*info), attrs, IFLA_MAX + 1); if ((new->ifa_name = add_ifla_ifname(attrs[IFLA_IFNAME])) == NULL) goto err; new->ifa_flags = info->ifi_flags; if ((new->ifa_addr = add_sockaddr_ll(attrs[IFLA_ADDRESS], info->ifi_index, info->ifi_type)) == NULL) goto err; new->ifa_broadaddr = add_sockaddr_ll(attrs[IFLA_BROADCAST], info->ifi_index, info->ifi_type); new->ifa_data = add_ifla_data(attrs[IFLA_STATS]); add_ifaddrs(new, ifap); } return; err: _freeifaddr(new); } /******************** second netlink request (GETADDR/AF_INET{6}) */ /* add a sockaddr_in/AF_INET field (ifa_addr, ifa_broadaddr, ifa_dstaddr)*/ static void *add_sockaddr_in(struct nlattr *attr) { if (attr != NULL && attr->nla_len == sizeof(*attr) + sizeof(struct in_addr)) { struct sockaddr_in *in = calloc(1, sizeof(*in)); if (in) { in->sin_family = AF_INET; memcpy(&in->sin_addr, attr + 1, sizeof(struct in_addr)); return in; } } return NULL; } /* add a sockaddr_in6/AF_INET6 field (ifa_addr, ifa_broadaddr, ifa_dstaddr)*/ static void *add_sockaddr_in6(struct nlattr *attr, uint32_t scope_id) { if (attr != NULL && attr->nla_len == sizeof(*attr) + sizeof(struct in6_addr)) { struct sockaddr_in6 *in = calloc(1, sizeof(*in)); if (in) { in->sin6_family = AF_INET6; if (IN6_IS_ADDR_LINKLOCAL(attr + 1) || IN6_IS_ADDR_MC_LINKLOCAL(attr + 1)) in->sin6_scope_id = scope_id; memcpy(&in->sin6_addr, attr + 1, sizeof(struct in6_addr)); return in; } } return NULL; } /* convert IPv4 prefix to add_sockaddr_in (ifa_netmask) */ static void *add_sockaddr_netmask(unsigned prefixlen) { struct sockaddr_in *in = calloc(1, sizeof(*in)); if (in) { uint32_t mask = (~0U) << (32 - prefixlen); in->sin_family = AF_INET; in->sin_addr.s_addr = htonl(mask); return in; } return NULL; } /* convert IPv6 prefix to add_sockaddr_in6 (ifa_netmask) */ static void *add_sockaddr_netmask6(unsigned prefixlen) { struct sockaddr_in6 *in = calloc(1, sizeof(*in)); if (in) { in->sin6_family = AF_INET6; for (int i = 0; i < 16 && prefixlen > 0; i++, prefixlen -= 8) { if (prefixlen > 7) in->sin6_addr.s6_addr[i] = 0xffu; else in->sin6_addr.s6_addr[i] = 0xffu << (8 - prefixlen); } return in; } return NULL; } /* search the AF_PACKET element, the key is if_index. Some data must be copied to AF_INET{6} fields */ static struct ifaddrs *search_iface(int index, struct ifaddrs *scan) { for (; scan != NULL; scan = scan->ifa_next) { struct sockaddr_ll *addr_ll = (void *) scan->ifa_addr; if (index == addr_ll->sll_ifindex) return scan; } return NULL; } /* process a GETADDR reply item -> create an AF_INET/AF_INET6 ifaddrs elemet */ static void add_af_inet(struct nlmsghdr *nlmsg, struct ifaddrs **ifap) { struct ifaddrmsg *info = (struct ifaddrmsg *) (nlmsg + 1); int32_t len = nlmsg->nlmsg_len - sizeof(*info); if (len < 0) return; switch (info->ifa_family) { // select supported AF only case AF_INET: break; case AF_INET6: break; default: return; } struct ifaddrs *ifa_iface = search_iface(info->ifa_index, *ifap); if (ifa_iface == NULL) return; struct ifaddrs *new = calloc(1, sizeof(*new)); struct nlattr *attrs[IFA_MAX + 1]; nl_getattrs(info + 1, len, attrs, IFA_MAX + 1); new->ifa_name = strdup(ifa_iface->ifa_name); new->ifa_flags = ifa_iface->ifa_flags; switch (info->ifa_family) { case AF_INET: { if (ifa_iface->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) { if ((new->ifa_addr = add_sockaddr_in(attrs[IFA_LOCAL])) == NULL) goto err; new->ifa_dstaddr = add_sockaddr_in(attrs[IFA_ADDRESS]); } else { if ((new->ifa_addr = add_sockaddr_in(attrs[IFA_ADDRESS])) == NULL) goto err; new->ifa_broadaddr = add_sockaddr_in(attrs[IFA_BROADCAST]); } if ((new->ifa_netmask = add_sockaddr_netmask(info->ifa_prefixlen)) == NULL) goto err; } break; case AF_INET6: { if (ifa_iface->ifa_flags & IFF_POINTOPOINT) { if ((new->ifa_addr = add_sockaddr_in6(attrs[IFA_LOCAL], info->ifa_index)) == NULL) goto err; new->ifa_dstaddr = add_sockaddr_in6(attrs[IFA_ADDRESS], info->ifa_index); } else { if ((new->ifa_addr = add_sockaddr_in6(attrs[IFA_ADDRESS], info->ifa_index)) == NULL) goto err; new->ifa_broadaddr = add_sockaddr_in6(attrs[IFA_BROADCAST], info->ifa_index); } if ((new->ifa_netmask = add_sockaddr_netmask6(info->ifa_prefixlen)) == NULL) goto err; } break; } add_ifaddrs(new, ifap); return; err: _freeifaddr(new); } typedef void add_af_generic(struct nlmsghdr *nlmsg, struct ifaddrs **ifap); /* ioth_getifaddrs, see getifaddrs(3) */ int ioth_getifaddrs(struct ioth *stack, struct ifaddrs **ifap) { struct sockaddr_nl sanl = {AF_NETLINK, 0, 0, 0}; /* pre-baked netlink request packets */ struct { struct nlmsghdr h; struct ifinfomsg i; } ifquery = { .h.nlmsg_len = sizeof(ifquery), .h.nlmsg_type = RTM_GETLINK, .h.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, .h.nlmsg_seq = 1, }; struct { struct nlmsghdr h; struct ifaddrmsg i; } adquery = { .h.nlmsg_len = sizeof(adquery), .h.nlmsg_type = RTM_GETADDR, .h.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP, .h.nlmsg_seq = 2, }; struct nlmsghdr *query[] = {&ifquery.h, &adquery.h}; add_af_generic *add_af[] = {add_af_packet, add_af_inet}; #define NQR (sizeof(query)/sizeof(query[0])) int fd; ssize_t replylen; *ifap = NULL; if ((fd = ioth_msocket(stack, AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)) < 0) return -1; if (ioth_bind(fd, (struct sockaddr *) &sanl, sizeof(struct sockaddr_nl)) < 0) goto err; // first request: GETLINK // second request: GETADDR for (int nq = 0; nq < 2; nq++) { if (ioth_send(fd, query[nq], query[nq]->nlmsg_len, 0) < 0) goto err; while (1) { if ((replylen = ioth_recv(fd, NULL, 0, MSG_PEEK|MSG_TRUNC)) < 0) replylen = 16384; unsigned char replybuf[replylen]; if ((replylen = ioth_recv(fd, replybuf, replylen, 0)) < 0) goto err; struct nlmsghdr *nlmsg; FORALL_NLMSG(nlmsg, replybuf, replylen) { if (nlmsg->nlmsg_type == NLMSG_DONE) break; if (nlmsg->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *nlerr = (struct nlmsgerr *)(nlmsg + 1); if (nlmsg->nlmsg_len < NLMSG_LENGTH (sizeof (*nlerr))) errno = EIO; else errno = -nlerr->error; goto err; } add_af[nq](nlmsg, ifap); } if (nlmsg->nlmsg_type == NLMSG_DONE) break; } } close(fd); return 0; err: close(fd); ioth_freeifaddrs(*ifap); *ifap = NULL; return -1; } /* ioth_freeifaddrs: see freeifaddrs(3) */ void ioth_freeifaddrs(struct ifaddrs *ifa) { while (ifa != NULL) { struct ifaddrs *next = ifa->ifa_next; _freeifaddr(ifa); ifa = next; } } libioth-0.1.2/iothaddr.c000066400000000000000000000047271454502410500151200ustar00rootroot00000000000000/* * iothaddr.c: utility library for ioth address management * hash (md5sum) based mac and ipv6 host address + eui64 conversion * * Copyright 2021 Renzo Davoli - Virtual Square Team * University of Bologna - Italy * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include #include #include #include #include void iothaddr_hash(void *addr, const char *name, const char *passwd, uint32_t otiptime) { struct in6_addr *addr6 = addr; size_t namelen = strlen(name); MHASH td; char out[mhash_get_block_size(MHASH_MD5)]; int i; memset(out, 0, mhash_get_block_size(MHASH_MD5)); if (name[namelen-1] == '.') namelen--; td=mhash_init(MHASH_MD5); mhash(td, name, namelen); if (passwd != NULL) mhash(td, passwd, strlen(passwd)); if (otiptime != 0) { uint32_t otiptime_n = htonl(otiptime); mhash(td, &otiptime_n, sizeof(otiptime_n)); } mhash_deinit(td, out); for (i=8; i<16; i++) addr6->s6_addr[i] ^= out[i-8]; addr6->s6_addr[8] &= ~0x3; // locally adm, unicast } void iothaddr_hashmac(void *mac, const char *name, const char *passwd) { unsigned char *umac = mac; size_t namelen = strlen(name); MHASH td; char out[mhash_get_block_size(MHASH_MD5)]; int i; memset(out, 0, mhash_get_block_size(MHASH_MD5)); if (name[namelen-1] == '.') namelen--; td=mhash_init(MHASH_MD5); mhash(td, name, namelen); if (passwd != NULL) mhash(td, passwd, strlen(passwd)); mhash_deinit(td, out); for (i=0; i<3; i++) umac[i] = out[i]; for (i=3; i<6; i++) umac[i] = out[i+2]; umac[0] |= 0x2; // locally adm umac[0] &= ~0x1; // unicast } void iothaddr_eui64(void *addr, void *mac) { struct in6_addr *addr6 = addr; unsigned char *umac = mac; int i; for (i=0; i<3; i++) addr6->s6_addr[i + 8] = umac[i]; addr6->s6_addr[11] = 0xff; addr6->s6_addr[12] = 0xfe; for (i=3; i<6; i++) addr6->s6_addr[i + 10] ^= umac[i]; addr6->s6_addr[8] ^= 0x2; // L bit has inverse meaning. } void iothaddr_hasheui64(void *addr, const char *name, const char *passwd) { unsigned char mac[6]; iothaddr_hashmac(mac, name, passwd); iothaddr_eui64(addr, mac); } libioth-0.1.2/iothaddr.h000066400000000000000000000047231454502410500151210ustar00rootroot00000000000000#ifndef IOTHADDR_H #define IOTHADDR_H #include #include /* hash based IPv6 address: the rightmost 64 bits of the address are XORed with the first 64 bit of the md5sum of the concatenation of: * name * passwd, if passwd != NULL * the big-endian 4 byte representation of otiptime, if otiptime != 0. bits 71 and 72 of addr are cleared (locally adm unicast address. */ /* e.g. addr: 2000:760::/64, name = "test.v2.cs.unibo.it", passwd = NULL, otiptime = 0 the md5sum of "test.v2.cs.unibo.it" is 69d62fac095a5a2ee4c2c79f211e57e3 The resulting address is 2000:760::68d6:2fac:95a:5a2e */ void iothaddr_hash(void *addr, const char *name, const char *passwd, uint32_t otiptime); /* One Time IP address (OTIP), computation of otiptime: ((seconds since the epoch) / otip_period) + otip_offset. otip_period is the address expiration period. otip_offset can be used on servers to anticipate the validity of addresses to tolerate negative drifts or clients' clocks. */ static inline uint32_t iothaddr_otiptime(int otip_period, int otip_offset) { if (otip_period == 0) return 0; return (uint32_t) ((time(NULL) + otip_offset) / otip_period); } /* hash based mac address Let H be the md5sum of the concatenation of: * name * passwd, if passwd != NULL. The mac address is set to: H'[0] : H[1] : H[2] : H[5] : H[6] : H[7] (the first byte has the 7th bit set and the 8th cleared: locally adm unicast address) e.g. name = "test.v2.cs.unibo.it", passwd = NULL the md5sum of "test.v2.cs.unibo.it" is 69d62fac095a5a2ee4c2c79f211e57e3 the mac address is: 69:d6:2f:5a:5a:2e */ /* Hash based defined MAC address can avoid delays due to old info in arp tables for process migration or restarting */ void iothaddr_hashmac(void *mac, const char *name, const char *passwd); /* compute the EUI64 based IPv6 address from the mac address. the rightmost 64 bits of the address are XORed with the EUI64 extension of the 6 bytes mac address. */ void iothaddr_eui64(void *addr, void *mac); /* compute the EUI64 based IPv6 address from the hash computed mac address. This function computes iothaddr_eui64 on the result of iothaddr_hashmac */ /* e.g. addr: 2000:760::/64, name = "test.v2.cs.unibo.it", passwd = NULL the md5sum of "test.v2.cs.unibo.it" is 69d62fac095a5a2ee4c2c79f211e57e3 the mac address is: 69:d6:2f:5a:5a:2e The resulting address is 2000:760::68d6:2fff:fe5a:5a2e */ void iothaddr_hasheui64(void *addr, const char *name, const char *passwd); #endif libioth-0.1.2/man/000077500000000000000000000000001454502410500137175ustar00rootroot00000000000000libioth-0.1.2/man/CMakeLists.txt000066400000000000000000000017421454502410500164630ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.7) set(PANDOC_ORG "VirtualSquare") # ### pandoc pages file(GLOB VU_PANDOC_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8].md) set(VU_MAN_FILES) foreach(VU_PANDOC_PATH IN LISTS VU_PANDOC_PAGES) # VU_PANDOCPAGE: basename of VU_PANDOC_PATH get_filename_component(VU_PANDOCPAGE ${VU_PANDOC_PATH} NAME) # VU_MANPAGE: VU_PANDOCPAGE without the suffix string(REGEX REPLACE "\.md$" "" VU_MANPAGE ${VU_PANDOCPAGE}) list(APPEND VU_MAN_FILES ${VU_MANPAGE}) endforeach(VU_PANDOC_PATH) add_custom_target(${PROJECT_NAME}_manpages ALL make PANDOC_ORG="${PANDOC_ORG}" ${VU_MAN_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) ### man pages file(GLOB VU_MAN_PAGES ${CMAKE_CURRENT_SOURCE_DIR}/*.[1-8]) foreach(VU_MAN_PATH IN LISTS VU_MAN_PAGES) get_filename_component(VU_MANPAGE ${VU_MAN_PATH} NAME) string(REGEX REPLACE ".*\\." "" MAN_CHAPTER ${VU_MANPAGE}) install(FILES ${VU_MAN_PATH} DESTINATION ${CMAKE_INSTALL_MANDIR}/man${MAN_CHAPTER}) endforeach(VU_MAN_PATH) libioth-0.1.2/man/Makefile000066400000000000000000000023031454502410500153550ustar00rootroot00000000000000MAKEFLAGS += --silent PANDOC=pandoc PANDOCOK := $(shell command -v ${PANDOC} 2> /dev/null) PANDOCMINVER=3.1.7 ifdef PANDOCOK PANDOCVER := $(shell ${PANDOC} -v | head -1 | cut -d ' ' -f 2) PANDOCVEROK := $(shell printf '%s\n' ${PANDOCMINVER} ${PANDOCVER} | sort -C -V; echo $$?) none: endif % : %.md ifdef PANDOCOK ifeq (${PANDOCVEROK}, 1) echo "${PANDOC} ${PANDOCVER} < ${PANDOCMINVER}. $@ can create font warnings with man/groff" >/dev/stderr >&2 endif # copy copyright notice grep "^\.\\\\\"" $< > $@ || true # run pandoc $(eval SECTION := $(subst .,,$(suffix $@))) $(eval BASENAME := $(basename $@)) $(eval TITLE := $(shell echo "${BASENAME}\(${SECTION}\)" | tr [:lower:] [:upper:])) $(eval HEADER := "$(shell man ${SECTION} intro | head -1 | sed -e 's/^[^[:blank:]]*[[:blank:]]*//' -e 's/[[:blank:]]*[^[:blank:]]*$$//' )") $(PANDOC) -standalone -M title=${TITLE} -M section=${SECTION} -M header=${HEADER} -M footer=${PANDOC_ORG} -M "date=`date +\"%B %Y\"`" --to man $< >> $@ # workaround for boldface rendering sed -i -e 's/\\f\[CR\]/\\f\[CB\]/g' $@ || true echo "$@ manpage updated" >/dev/stderr >&2 else echo "${PANDOC} is not available. Manpage $@ cannot be updated" >/dev/stderr >&2 endif libioth-0.1.2/man/ioth.3000066400000000000000000000276301454502410500147560ustar00rootroot00000000000000.\" Copyright (C) 2022 VirtualSquare. Project Leader: Renzo Davoli .\" .\" This is free documentation; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License, .\" as published by the Free Software Foundation, either version 2 .\" of the License, or (at your option) any later version. .\" .\" The GNU General Public License's references to "object code" .\" and "executables" are to be interpreted as the output of any .\" document formatting or typesetting system, including .\" intermediate and printed output. .\" .\" This manual 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 manual; if not, write to the Free .\" Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, .\" MA 02110-1301 USA. .\" .\" Automatically generated by Pandoc 3.1.11 .\" .TH "IOTH" "3" "January 2024" "VirtualSquare" "Library Functions Manual" .SH NAME ioth_newstack, ioth_newstackl, ioth_newstackv, ioth_delstack, ioth_msocket, ioth_set_defstack, ioth_get_defstack, ioth_socket, ioth_close, ioth_bind, ioth_connect, ioth_listen, ioth_accept, ioth_getsockname, ioth_getpeername, ioth_setsockopt, ioth_getsockopt, ioth_shutdown, ioth_ioctl, ioth_fcntl, ioth_read, ioth_readv, ioth_recv, ioth_recvfrom, ioth_recvmsg, ioth_write, ioth_writev, ioth_send, ioth_sendto ioth_sendmsg, ioth_if_nametoindex, ioth_linksetupdown, ioth_ipaddr_add, ioth_ipaddr_del, ioth_iproute_add, ioth_iproute_del, ioth_iplink_add, ioth_iplink_del, ioth_linksetaddr, ioth_linkgetaddr \- Internet of Threads (IoTh) library .SH SYNOPSIS \f[CB]#include \f[R] .PP \f[CB]struct ioth *ioth_newstack(const char *\f[R]\f[I]stack\f[R]\f[CB], const char *\f[R]\f[I]vnl\f[R]\f[CB]);\f[R] .PP \f[CB]struct ioth *ioth_newstackl(const char *\f[R]\f[I]stack\f[R]\f[CB], const char *\f[R]\f[I]vnl\f[R]\f[CB], ... );\f[R] .PP \f[CB]struct ioth *ioth_newstackv(const char *\f[R]\f[I]stack\f[R]\f[CB], const char *\f[R]\f[I]vnlv\f[R]\f[CB][]);\f[R] .PP \f[CB]int ioth_delstack(struct ioth *\f[R]\f[I]iothstack\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_msocket(struct ioth *\f[R]\f[I]iothstack\f[R]\f[CB], int\f[R] \f[I]domain\f[R]\f[CB], int\f[R] \f[I]type\f[R]\f[CB], int\f[R] \f[I]protocol\f[R]\f[CB]);\f[R] .PP \f[CB]void ioth_set_defstack(struct ioth *\f[R]\f[I]iothstack\f[R]\f[CB]);\f[R] .PP \f[CB]struct ioth *ioth_get_defstack(void);\f[R] .PP \f[CB]int ioth_socket(int\f[R] \f[I]domain\f[R]\f[CB], int\f[R] \f[I]type\f[R]\f[CB], int\f[R] \f[I]protocol\f[R]\f[CB]);\f[R] .IP \[bu] 2 Berkeley Sockets API .PP \f[CB]int ioth_close(int\f[R] \f[I]fd\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_bind(int\f[R] \f[I]sockfd\f[R]\f[CB], const struct sockaddr *\f[R]\f[I]addr\f[R]\f[CB], socklen_t\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_connect(int\f[R] \f[I]sockfd\f[R]\f[CB], const struct sockaddr *\f[R]\f[I]addr\f[R]\f[CB], socklen_t\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_listen(int\f[R] \f[I]sockfd\f[R]\f[CB], int\f[R] \f[I]backlog\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_accept(int\f[R] \f[I]sockfd\f[R]\f[CB], struct sockaddr *restrict\f[R] \f[I]addr\f[R]\f[CB], socklen_t *restrict\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_getsockname(int\f[R] \f[I]sockfd\f[R]\f[CB], struct sockaddr *restrict\f[R] \f[I]addr\f[R]\f[CB], socklen_t *restrict\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_getpeername(int\f[R] \f[I]sockfd\f[R]\f[CB], struct sockaddr *restrict\f[R] \f[I]addr\f[R]\f[CB], socklen_t *restrict\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_getsockopt(int\f[R] \f[I]sockfd\f[R]\f[CB], int\f[R] \f[I]level\f[R]\f[CB], int\f[R] \f[I]optname\f[R]\f[CB], void *restrict\f[R] \f[I]optval\f[R]\f[CB], socklen_t *restrict\f[R] \f[I]optlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_setsockopt(int\f[R] \f[I]sockfd\f[R]\f[CB], int\f[R] \f[I]level\f[R]\f[CB], int\f[R] \f[I]optname\f[R]\f[CB], const void *\f[R]\f[I]optval\f[R]\f[CB], socklen_t\f[R] \f[I]optlen\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_shutdown(int\f[R] \f[I]sockfd\f[R]\f[CB], int\f[R] \f[I]how\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_ioctl(int\f[R] \f[I]fd\f[R]\f[CB], unsigned long\f[R] \f[I]request\f[R]\f[CB], ...);\f[R] .PP \f[CB]int ioth_fcntl(int\f[R] \f[I]fd\f[R]\f[CB], int\f[R] \f[I]cmd\f[R]\f[CB], ... /* arg */ );\f[R] .PP \f[CB]ssize_t ioth_read(int\f[R] \f[I]fd\f[R]\f[CB], void *\f[R]\f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]count\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_readv(int\f[R] \f[I]fd\f[R]\f[CB], const struct iovec *\f[R]\f[I]iov\f[R]\f[CB], int\f[R] \f[I]iovcnt\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_recv(int\f[R] \f[I]sockfd\f[R]\f[CB], void *\f[R]\f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]len\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_recvfrom(int\f[R] \f[I]sockfd\f[R]\f[CB], void *restrict\f[R] \f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]len\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB], struct sockaddr *restrict\f[R] \f[I]src_addr\f[R]\f[CB], socklen_t *restrict\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_recvmsg(int\f[R] \f[I]sockfd\f[R]\f[CB], struct msghdr *\f[R]\f[I]msg\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_write(int\f[R] \f[I]fd\f[R]\f[CB], const void *\f[R]\f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]count\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_writev(int\f[R] \f[I]fd\f[R]\f[CB], const struct iovec *\f[R]\f[I]iov\f[R]\f[CB], int\f[R] \f[I]iovcnt\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_send(int\f[R] \f[I]sockfd\f[R]\f[CB], const void *\f[R]\f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]len\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_sendto(int\f[R] \f[I]sockfd\f[R]\f[CB], const void *\f[R]\f[I]buf\f[R]\f[CB], size_t\f[R] \f[I]len\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB], const struct sockaddr *\f[R]\f[I]dest_addr\f[R]\f[CB], socklen_t\f[R] \f[I]addrlen\f[R]\f[CB]);\f[R] .PP \f[CB]ssize_t ioth_sendmsg(int\f[R] \f[I]sockfd\f[R]\f[CB], const struct msghdr *\f[R]\f[I]msg\f[R]\f[CB], int\f[R] \f[I]flags\f[R]\f[CB]);\f[R] .IP \[bu] 2 nlinline+ API .PP \f[CB]int ioth_if_nametoindex(const char *\f[R]\f[I]ifname\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_linksetupdown(unsigned int\f[R] \f[I]ifindex\f[R]\f[CB], int\f[R] \f[I]updown\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_ipaddr_add(int\f[R] \f[I]family\f[R]\f[CB], void *\f[R]\f[I]addr\f[R]\f[CB], int\f[R] \f[I]prefixlen\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_ipaddr_del(int\f[R] \f[I]family\f[R]\f[CB], void *\f[R]\f[I]addr\f[R]\f[CB], int\f[R] \f[I]prefixlen\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_iproute_add(int\f[R] \f[I]family\f[R]\f[CB], void *\f[R]\f[I]dst_addr\f[R]\f[CB], int\f[R] \f[I]dst_prefixlen\f[R]\f[CB], void *\f[R]\f[I]gw_addr\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_iproute_del(int\f[R] \f[I]family\f[R]\f[CB], void *\f[R]\f[I]dst_addr\f[R]\f[CB], int\f[R] \f[I]dst_prefixlen\f[R]\f[CB], void *\f[R]\f[I]gw_addr\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_iplink_add(const char *\f[R]\f[I]ifname\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\f[CB], const char *\f[R]\f[I]type\f[R]\f[CB], const char *\f[R]\f[I]data\f[R]\f[CB]);\f[R] .PP \f[CB]int ioth_iplink_del(const char *\f[R]\f[I]ifname\f[R]\f[CB], unsigned int\f[R] \f[I]ifindex\f[R]\[ga]); .PP \f[CB]int ioth_linksetaddr(unsigned int\f[R] \f[I]ifindex\f[R]\f[CB], void *\f[R]\f[I]macaddr\f[R]\[ga]); .PP \f[CB]int ioth_linkgetaddr(unsigned int\f[R] \f[I]ifindex\f[R]\f[CB], void *\f[R]\f[I]macaddr\f[R]\[ga]); .SH DESCRIPTION \f[CB]libioth\f[R] is the API for the Internet of Threads. TCP\-IP networking stacks can be loaded as dynamic libraries at run time. .IP \[bu] 2 the API is minimal: Berkeley Sockets + msocket + newstack/delstack. .IP \[bu] 2 the stack implementation can be chosen as a plugin at run time. .IP \[bu] 2 netlink based stack/interface/ip configuration via nlinline. .IP \[bu] 2 ioth sockets are real file descriptors, poll/select/ppoll/pselect/epoll friendly .IP \[bu] 2 plug\-ins can be loaded in private address namespaces: libioth supports several stacks of the same type (same plugin) even if the stack implementation library was designed to provide just one stack. .PP \f[CB]libioth\f[R] provides the following functions: .TP \f[CB]ioth_newstack\f[R] \f[CB]ioth_newstack\f[R] creates a new stack without any interface if \f[CB]vnl\f[R] is NULL, otherwise the new stack has a virtual interface connected to the vde network identified by the VNL (Virtual Network Locator, see vde_open(3) ). .TP \f[CB]ioth_newstackl\f[R], \f[CB]ioth_newstackv\f[R] ioth_newstackl\f[CB]and\f[R]ioth_newstackv\[ga] (l = list, v = vector) support the creation of a new stack with several interfaces. It is possible to provide the VNLs as a sequence of arguments (as in execl(3)) or as a NULL terminated array of VNLs (as the arguments in execv(3)). .TP \f[CB]ioth_delstack\f[R] This function terminates/deletes a stack. .TP \f[CB]ioth_msocket\f[R] This is the multi\-stack supporting extension of socket(2). It behaves exactly as socket except for the added heading argument that allows the choice of the stack among those currently available (previously created by a \f[CB]ioth_newstack*\f[R]). .TP \f[CB]ioth_set_defstack\f[R], \f[CB]ioth_get_defstack\f[R] These functions define and retrieve the default stack, respectively. The default stack is implicitly used by ioth_msocket when its first argument iothstack is NULL. The default stack is initially defined as the native stack provided by the kernel. Use ioth_set_defstack(mystack) to define mystack as the current default stack. ioth_set_defstack(NULL) to revert the default stack to the native stack. .TP \f[CB]ioth_socket\f[R] \f[CB]ioth_socket\f[R] opens a socket using the default stack: \f[CB]ioth_socket(d, t, p)\f[R] is an alias for \f[CB]ioth_msocket(NULL, d, t, p)\f[R] .TP \f[CB]ioth_close\f[R], \f[CB]ioth_bind\f[R], \f[CB]ioth_connect\f[R], \f[CB]ioth_listen\f[R], \f[CB]ioth_accept\f[R], \f[CB]ioth_getsockname\f[R], \f[CB]ioth_getpeername\f[R], \f[CB]ioth_setsockopt\f[R], \f[CB]ioth_getsockopt\f[R], \f[CB]ioth_shutdown\f[R], \f[CB]ioth_ioctl\f[R], \f[CB]ioth_fcntl\f[R], \f[CB]ioth_read\f[R], \f[CB]ioth_readv\f[R], \f[CB]ioth_recv\f[R], \f[CB]ioth_recvfrom\f[R], \f[CB]ioth_recvmsg\f[R], \f[CB]ioth_write\f[R], \f[CB]ioth_writev\f[R], \f[CB]ioth_send\f[R], \f[CB]ioth_sendto\f[R], \f[CB]ioth_sendmsg\f[R] these functions have the same signature and functionalities of their counterpart in (2) and (3) without the \f[CB]ioth_\f[R] prefix. .TP \f[CB]ioth_if_nametoindex\f[R], \f[CB]ioth_linksetupdown\f[R], \f[CB]ioth_ipaddr_add\f[R], \f[CB]ioth_ipaddr_del\f[R], \f[CB]ioth_iproute_add\f[R], \f[CB]ioth_iproute_del\f[R], \f[CB]ioth_iplink_add\f[R], \f[CB]ioth_iplink_del\f[R], \f[CB]ioth_linksetaddr\f[R], \f[CB]ioth_linkgetaddr\f[R] these functions have the same signature and functionnalities described in \f[CB]nlinline\f[R](3). .SH RETURN VALUE \f[CB]ioth_newstack\f[R], \f[CB]ioth_newstackl\f[R], \f[CB]ioth_newstackv\f[R] return a \f[CB]struct stack\f[R] pointer, NULL in case of error. This address is used as a descriptor of the newly created stack and is later passed as parameter to \f[CB]ioth_msocket\f[R], \f[CB]ioth_set_defstack\f[R] or \f[CB]ioth_delstack\f[R]. .PP \f[CB]ioth_msocket\f[R] and \f[CB]ioth_socket\f[R] return the file descriptor of the new socket, \-1 in case of errore. .PP \f[CB]ioth_delstack\f[R] returns \-1 in case of error, 0 otherwise. If there are file descriptors already in use, this function fails and errno is EBUSY. .PP \f[CB]ioth_get_defstack\f[R] returns the stack descriptor of the default stack. .PP The return values of all the other functions are defined in the man pages of the corresponding functions provided by the GNU C library or nlinline(3) .SH SEE ALSO vde_plug(1), vdeplug_open(3), nlinline(3) .SH AUTHOR VirtualSquare. Project leader: Renzo Davoli libioth-0.1.2/man/ioth.3.md000066400000000000000000000215171454502410500153530ustar00rootroot00000000000000 # NAME ioth_newstack, ioth_newstackl, ioth_newstackv, ioth_delstack, ioth_msocket, ioth_set_defstack, ioth_get_defstack, ioth_socket, ioth_close, ioth_bind, ioth_connect, ioth_listen, ioth_accept, ioth_getsockname, ioth_getpeername, ioth_setsockopt, ioth_getsockopt, ioth_shutdown, ioth_ioctl, ioth_fcntl, ioth_read, ioth_readv, ioth_recv, ioth_recvfrom, ioth_recvmsg, ioth_write, ioth_writev, ioth_send, ioth_sendto ioth_sendmsg, ioth_if_nametoindex, ioth_linksetupdown, ioth_ipaddr_add, ioth_ipaddr_del, ioth_iproute_add, ioth_iproute_del, ioth_iplink_add, ioth_iplink_del, ioth_linksetaddr, ioth_linkgetaddr - Internet of Threads (IoTh) library # SYNOPSIS `#include ` `struct ioth *ioth_newstack(const char *`_stack_`, const char *`_vnl_`);` `struct ioth *ioth_newstackl(const char *`_stack_`, const char *`_vnl_`, ... );` `struct ioth *ioth_newstackv(const char *`_stack_`, const char *`_vnlv_`[]);` `int ioth_delstack(struct ioth *`_iothstack_`);` `int ioth_msocket(struct ioth *`_iothstack_`, int ` _domain_`, int ` _type_`, int ` _protocol_`);` `void ioth_set_defstack(struct ioth *`_iothstack_`);` `struct ioth *ioth_get_defstack(void);` `int ioth_socket(int ` _domain_`, int ` _type_`, int ` _protocol_`);` + Berkeley Sockets API `int ioth_close(int ` _fd_`);` `int ioth_bind(int ` _sockfd_`, const struct sockaddr *`_addr_`, socklen_t ` _addrlen_`);` `int ioth_connect(int ` _sockfd_`, const struct sockaddr *`_addr_`, socklen_t ` _addrlen_`);` `int ioth_listen(int ` _sockfd_`, int ` _backlog_`);` `int ioth_accept(int ` _sockfd_`, struct sockaddr *restrict ` _addr_`, socklen_t *restrict ` _addrlen_`);` `int ioth_getsockname(int ` _sockfd_`, struct sockaddr *restrict ` _addr_`, socklen_t *restrict ` _addrlen_`);` `int ioth_getpeername(int ` _sockfd_`, struct sockaddr *restrict ` _addr_`, socklen_t *restrict ` _addrlen_`);` `int ioth_getsockopt(int ` _sockfd_`, int ` _level_`, int ` _optname_`, void *restrict ` _optval_`, socklen_t *restrict ` _optlen_`);` `int ioth_setsockopt(int ` _sockfd_`, int ` _level_`, int ` _optname_`, const void *`_optval_`, socklen_t ` _optlen_`);` `int ioth_shutdown(int ` _sockfd_`, int ` _how_`);` `int ioth_ioctl(int ` _fd_`, unsigned long ` _request_`, ...);` `int ioth_fcntl(int ` _fd_`, int ` _cmd_`, ... /* arg */ );` `ssize_t ioth_read(int ` _fd_`, void *`_buf_`, size_t ` _count_`);` `ssize_t ioth_readv(int ` _fd_`, const struct iovec *`_iov_`, int ` _iovcnt_`);` `ssize_t ioth_recv(int ` _sockfd_`, void *`_buf_`, size_t ` _len_`, int ` _flags_`);` `ssize_t ioth_recvfrom(int ` _sockfd_`, void *restrict ` _buf_`, size_t ` _len_`, int ` _flags_`, struct sockaddr *restrict ` _src_addr_`, socklen_t *restrict ` _addrlen_`);` `ssize_t ioth_recvmsg(int ` _sockfd_`, struct msghdr *`_msg_`, int ` _flags_`);` `ssize_t ioth_write(int ` _fd_`, const void *`_buf_`, size_t ` _count_`);` `ssize_t ioth_writev(int ` _fd_`, const struct iovec *`_iov_`, int ` _iovcnt_`);` `ssize_t ioth_send(int ` _sockfd_`, const void *`_buf_`, size_t ` _len_`, int ` _flags_`);` `ssize_t ioth_sendto(int ` _sockfd_`, const void *`_buf_`, size_t ` _len_`, int ` _flags_`, const struct sockaddr *`_dest_addr_`, socklen_t ` _addrlen_`);` `ssize_t ioth_sendmsg(int ` _sockfd_`, const struct msghdr *`_msg_`, int ` _flags_`);` + nlinline+ API `int ioth_if_nametoindex(const char *`_ifname_`);` `int ioth_linksetupdown(unsigned int ` _ifindex_`, int ` _updown_`);` `int ioth_ipaddr_add(int ` _family_`, void *`_addr_`, int ` _prefixlen_`, unsigned int ` _ifindex_`);` `int ioth_ipaddr_del(int ` _family_`, void *`_addr_`, int ` _prefixlen_`, unsigned int ` _ifindex_`);` `int ioth_iproute_add(int ` _family_`, void *`_dst_addr_`, int ` _dst_prefixlen_`, void *`_gw_addr_`, unsigned int ` _ifindex_`);` `int ioth_iproute_del(int ` _family_`, void *`_dst_addr_`, int ` _dst_prefixlen_`, void *`_gw_addr_`, unsigned int ` _ifindex_`);` `int ioth_iplink_add(const char *`_ifname_`, unsigned int ` _ifindex_`, const char *`_type_`, const char *`_data_`);` `int ioth_iplink_del(const char *`_ifname_`, unsigned int ` _ifindex_`); `int ioth_linksetaddr(unsigned int ` _ifindex_`, void *`_macaddr_`); `int ioth_linkgetaddr(unsigned int ` _ifindex_`, void *`_macaddr_`); # DESCRIPTION `libioth` is the API for the Internet of Threads. TCP-IP networking stacks can be loaded as dynamic libraries at run time. * the API is minimal: Berkeley Sockets + msocket + newstack/delstack. * the stack implementation can be chosen as a plugin at run time. * netlink based stack/interface/ip configuration via nlinline. * ioth sockets are real file descriptors, poll/select/ppoll/pselect/epoll friendly * plug-ins can be loaded in private address namespaces: libioth supports several stacks of the same type (same plugin) even if the stack implementation library was designed to provide just one stack. `libioth` provides the following functions: `ioth_newstack` : `ioth_newstack` creates a new stack without any interface if `vnl` is NULL, otherwise the new stack has a virtual interface connected to the vde network identified by the VNL (Virtual Network Locator, see vde_open(3) ). `ioth_newstackl`, `ioth_newstackv` : ioth_newstackl` and `ioth_newstackv` (l = list, v = vector) support the creation of a new stack with several interfaces. It is possible to provide the VNLs as a sequence of arguments (as in execl(3)) or as a NULL terminated array of VNLs (as the arguments in execv(3)). `ioth_delstack` : This function terminates/deletes a stack. `ioth_msocket` : This is the multi-stack supporting extension of socket(2). It behaves exactly as socket except for the added heading argument that allows the choice of the stack among those currently available (previously created by a `ioth_newstack*`). `ioth_set_defstack`, `ioth_get_defstack` : These functions define and retrieve the default stack, respectively. : The default stack is implicitly used by ioth_msocket when its first argument iothstack is NULL. : The default stack is initially defined as the native stack provided by the kernel. Use ioth_set_defstack(mystack) to define mystack as the current default stack. ioth_set_defstack(NULL) to revert the default stack to the native stack. `ioth_socket` : `ioth_socket` opens a socket using the default stack: `ioth_socket(d, t, p)` is an alias for `ioth_msocket(NULL, d, t, p)` `ioth_close`, `ioth_bind`, `ioth_connect`, `ioth_listen`, `ioth_accept`, `ioth_getsockname`, `ioth_getpeername`, `ioth_setsockopt`, `ioth_getsockopt`, `ioth_shutdown`, `ioth_ioctl`, `ioth_fcntl`, `ioth_read`, `ioth_readv`, `ioth_recv`, `ioth_recvfrom`, `ioth_recvmsg`, `ioth_write`, `ioth_writev`, `ioth_send`, `ioth_sendto`, `ioth_sendmsg` : these functions have the same signature and functionalities of their counterpart in (2) and (3) without the `ioth_` prefix. `ioth_if_nametoindex`, `ioth_linksetupdown`, `ioth_ipaddr_add`, ` ioth_ipaddr_del`, `ioth_iproute_add`, `ioth_iproute_del`, ` ioth_iplink_add`, `ioth_iplink_del`, `ioth_linksetaddr`, `ioth_linkgetaddr` : these functions have the same signature and functionnalities described in `nlinline`(3). # RETURN VALUE `ioth_newstack`, `ioth_newstackl`, `ioth_newstackv` return a `struct stack` pointer, NULL in case of error. This address is used as a descriptor of the newly created stack and is later passed as parameter to `ioth_msocket`, `ioth_set_defstack` or `ioth_delstack`. `ioth_msocket` and `ioth_socket` return the file descriptor of the new socket, -1 in case of errore. `ioth_delstack` returns -1 in case of error, 0 otherwise. If there are file descriptors already in use, this function fails and errno is EBUSY. `ioth_get_defstack` returns the stack descriptor of the default stack. The return values of all the other functions are defined in the man pages of the corresponding functions provided by the GNU C library or nlinline(3) # SEE ALSO vde_plug(1), vdeplug_open(3), nlinline(3) # AUTHOR VirtualSquare. Project leader: Renzo Davoli libioth-0.1.2/man/ioth_accept.3000077700000000000000000000000001454502410500173072ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_bind.3000077700000000000000000000000001454502410500167642ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_close.3000077700000000000000000000000001454502410500171552ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_connect.3000077700000000000000000000000001454502410500175012ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_delstack.3000077700000000000000000000000001454502410500176422ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_fcntl.3000077700000000000000000000000001454502410500171562ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_get_defstack.3000077700000000000000000000000001454502410500204732ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_getpeername.3000077700000000000000000000000001454502410500203442ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_getsockname.3000077700000000000000000000000001454502410500203502ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_getsockopt.3000077700000000000000000000000001454502410500202322ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_if_nametoindex.3000077700000000000000000000000001454502410500210412ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_ioctl.3000077700000000000000000000000001454502410500171622ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_ipaddr_add.3000077700000000000000000000000001454502410500201232ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_ipaddr_del.3000077700000000000000000000000001454502410500201372ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_iplink_add.3000077700000000000000000000000001454502410500201462ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_iplink_del.3000077700000000000000000000000001454502410500201622ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_iproute_add.3000077700000000000000000000000001454502410500203472ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_iproute_del.3000077700000000000000000000000001454502410500203632ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_linkgetaddr.3000077700000000000000000000000001454502410500203402ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_linksetaddr.3000077700000000000000000000000001454502410500203542ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_linksetupdown.3000077700000000000000000000000001454502410500207562ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_listen.3000077700000000000000000000000001454502410500173462ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_msocket.3000077700000000000000000000000001454502410500175152ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_newstack.3000077700000000000000000000000001454502410500176672ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_newstackl.3000077700000000000000000000000001454502410500200432ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_newstackv.3000077700000000000000000000000001454502410500200552ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_read.3000077700000000000000000000000001454502410500167632ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_readv.3000077700000000000000000000000001454502410500171512ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_recv.3000077700000000000000000000000001454502410500170072ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_recvfrom.3000077700000000000000000000000001454502410500176732ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_recvmsg.3000077700000000000000000000000001454502410500175162ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_send.3000077700000000000000000000000001454502410500170012ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_sendmsg.3000077700000000000000000000000001454502410500175102ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_sendto.3000077700000000000000000000000001454502410500173442ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_set_defstack.3000077700000000000000000000000001454502410500205072ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_setsockopt.3000077700000000000000000000000001454502410500202462ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_shutdown.3000077700000000000000000000000001454502410500177232ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_socket.3000077700000000000000000000000001454502410500173402ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_write.3000077700000000000000000000000001454502410500172022ioth.3ustar00rootroot00000000000000libioth-0.1.2/man/ioth_writev.3000077700000000000000000000000001454502410500173702ioth.3ustar00rootroot00000000000000libioth-0.1.2/modules/000077500000000000000000000000001454502410500146145ustar00rootroot00000000000000libioth-0.1.2/modules/CMakeLists.txt000066400000000000000000000015571454502410500173640ustar00rootroot00000000000000add_library(ioth_kernel-r SHARED ioth_kernel.c) set_target_properties(ioth_kernel-r PROPERTIES PREFIX "") install(TARGETS ioth_kernel-r DESTINATION ${SYSTEM_IOTH_PATH}) ADD_CUSTOM_TARGET(ioth_kernel_n.so ALL DEPENDS ioth_kernel-r COMMAND ${CMAKE_COMMAND} -E create_symlink ioth_kernel-r.so ioth_kernel_n.so) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ioth_kernel_n.so DESTINATION ${SYSTEM_IOTH_PATH}) add_library(ioth_vdestack-r SHARED ioth_vdestack.c) set_target_properties(ioth_vdestack-r PROPERTIES PREFIX "") target_link_libraries(ioth_vdestack-r vdeplug -lpthread) install(TARGETS ioth_vdestack-r DESTINATION ${SYSTEM_IOTH_PATH}) ADD_CUSTOM_TARGET(ioth_vdestack_n.so ALL DEPENDS ioth_vdestack-r COMMAND ${CMAKE_COMMAND} -E create_symlink ioth_vdestack-r.so ioth_vdestack_n.so) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/ioth_vdestack_n.so DESTINATION ${SYSTEM_IOTH_PATH}) libioth-0.1.2/modules/ioth_kernel.c000066400000000000000000000032441454502410500172660ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * plugin for the kernel stack * * Copyright (C) 2020 Renzo Davoli VirtualSquare team. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include const char *ioth_kernel_license = "SPDX-License-Identifier: LGPL-2.1-or-later"; void *ioth_kernel_newstack(const char *vnlv[], const char *options, struct ioth_functions *ioth_f) { (void) vnlv; (void) options; ioth_f->socket = socket; ioth_f->close = close; ioth_f->bind = bind; ioth_f->connect = connect; ioth_f->listen = listen; ioth_f->accept = accept; ioth_f->getsockname = getsockname; ioth_f->getpeername = getpeername; ioth_f->setsockopt = setsockopt; ioth_f->getsockopt = getsockopt; ioth_f->shutdown = shutdown; ioth_f->ioctl = ioctl; ioth_f->fcntl = fcntl; ioth_f->read = read; ioth_f->readv = readv; ioth_f->recv = recv; ioth_f->recvfrom = recvfrom; ioth_f->recvmsg = recvmsg; ioth_f->write = write; ioth_f->writev = writev; ioth_f->send = send; ioth_f->sendto = sendto; ioth_f->sendmsg = sendmsg; return (void *) 42; // useless, but retval == NULL means error! } void *ioth_kernel_n_newstack(const char *vnlv[], const char *options, struct ioth_functions *ioth_f) __attribute__ ((alias ("ioth_kernel_newstack"))); libioth-0.1.2/modules/ioth_vdestack.c000066400000000000000000000175001454502410500176120ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * plugin for vdestack (vdestack borrows the kernel stack using a namespace) * * Copyright (C) 2020 Renzo Davoli VirtualSquare team. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or (at * your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define APPSIDE 0 #define DAEMONSIDE 1 #define DEFAULT_IF_NAME "vde0" #define POLLING_TIMEOUT 10000 #define CHILD_STACK_SIZE (256 * 1024) const char *ioth_vdestack_license = "SPDX-License-Identifier: LGPL-2.1-or-later"; struct vdestack { pid_t pid; pid_t parentpid; int noif; pthread_mutex_t mutex; int cmdpipe[2]; // socketpair for commands; char *child_stack; struct { VDECONN *vdeconn; char ifname[IFNAMSIZ]; } iface[]; }; struct vdecmd { int domain; int type; int protocol; }; struct vdereply { int rval; int err; }; static int open_tap(char *name) { struct ifreq ifr; int fd=-1; if((fd = open("/dev/net/tun", O_RDWR | O_CLOEXEC)) < 0) return -1; memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1); if(ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) { perror(name); close(fd); return -1; } return fd; } static int childFunc(void *arg) { struct vdestack *stack = arg; int noif = stack->noif; struct pollfd pfd[noif * 2 + 1]; int i; ssize_t unused; for (i = 0; i < noif; i++) { pfd[i].fd = vde_datafd(stack->iface[i].vdeconn); pfd[i + noif].fd = open_tap(stack->iface[i].ifname); pfd[i].events = pfd[i + noif].events = POLLIN; pfd[i].revents = pfd[i + noif].revents = 0; } pfd[noif * 2].fd = stack->cmdpipe[DAEMONSIDE]; pfd[noif * 2].events = POLLIN; pfd[noif * 2].revents = 0; while (poll(pfd, noif * 2 + 1, POLLING_TIMEOUT) >= 0) { char buf[VDE_ETHBUFSIZE]; size_t n; // printf("poll in %d %d %d\n",pfd[0].revents,pfd[1].revents,pfd[2].revents); if (kill(stack->parentpid, 0) < 0) break; if (pfd[noif * 2].revents & POLLIN) { struct vdecmd cmd; struct vdereply reply; if ((n = read(stack->cmdpipe[DAEMONSIDE], &cmd, sizeof(cmd))) > 0) { reply.rval = socket(cmd.domain, cmd.type, cmd.protocol); reply.err = errno; unused = write(stack->cmdpipe[DAEMONSIDE], &reply, sizeof(reply)); } else break; } for (i = 0; i < noif; i++) { if (pfd[i + noif].revents & POLLIN) { n = read(pfd[i + noif].fd, buf, VDE_ETHBUFSIZE); if (n <= 0) break; vde_send(stack->iface[i].vdeconn, buf, n, 0); } if (pfd[i].revents & POLLIN) { n = vde_recv(stack->iface[i].vdeconn, buf, VDE_ETHBUFSIZE, 0); if (n <= 0) break; unused = write(pfd[i + noif].fd, buf, n); } } (void) unused; //printf("poll out\n"); } for (i = 0; i < noif; i++) { if (pfd[i + noif].fd >= 0) close(pfd[i + noif].fd); } close(stack->cmdpipe[DAEMONSIDE]); _exit(EXIT_SUCCESS); } static int countif(const char **v) { int count; if (v == NULL) return 0; for (count = 0; v[count]; count++) ; return count; } struct vdestack *vde_addstack(const char *vnlv[], const char *options) { (void) options; int i; int noif = countif(vnlv); struct vdestack *stack = malloc(sizeof(*stack) + sizeof(stack->iface[0]) * noif); if (stack) { //printf("noif %d\n",noif); stack->noif = noif; if (pthread_mutex_init(&stack->mutex, NULL) != 0) goto err_mutex; stack->child_stack = mmap(0, CHILD_STACK_SIZE, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (stack->child_stack == NULL) goto err_child_stack; if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, stack->cmdpipe) < 0) goto err_cmdpipe; for (i = 0; i < noif; i++) stack->iface[i].vdeconn = NULL; for (i = 0; i < noif; i++) { const char *ifvnl = vnlv[i]; char *delim = strstr(ifvnl, "://"); // position of "://" char *colonmark = strchr(ifvnl, ':'); // position of ':' if (colonmark && (!delim || (delim && colonmark < delim))) { /* spit ifname from vnl */ int ifnamelen = colonmark - ifvnl; snprintf(stack->iface[i].ifname, IFNAMSIZ, "%.*s", ifnamelen, ifvnl); ifvnl = colonmark + 1; } else snprintf(stack->iface[i].ifname, IFNAMSIZ, "vde%d", i); //printf("open %s %s\n", stack->iface[i].ifname, ifvnl); if ((stack->iface[i].vdeconn = vde_open((char *) ifvnl, "ioth_vdestack", NULL)) == NULL) goto err_vdenet; } stack->parentpid = getpid(); stack->pid = clone(childFunc, stack->child_stack + CHILD_STACK_SIZE, CLONE_FILES | CLONE_NEWUSER | CLONE_NEWNET | SIGCHLD, stack); if (stack->pid == -1) goto err_child; } return stack; err_child: err_vdenet: for (i = 0; i < noif; i++) { if (stack->iface[i].vdeconn) vde_close(stack->iface[i].vdeconn); } close(stack->cmdpipe[APPSIDE]); close(stack->cmdpipe[DAEMONSIDE]); err_cmdpipe: munmap(stack->child_stack, CHILD_STACK_SIZE); err_child_stack: pthread_mutex_destroy(&stack->mutex); err_mutex: free(stack); return NULL; } void vde_delstack(struct vdestack *stack) { int i; int noif = stack->noif; for (i = 0; i < noif; i++) { if (stack->iface[i].vdeconn) vde_close(stack->iface[i].vdeconn); } close(stack->cmdpipe[APPSIDE]); waitpid(stack->pid, NULL, 0); munmap(stack->child_stack, CHILD_STACK_SIZE); pthread_mutex_destroy(&stack->mutex); free(stack); } int vde_msocket(struct vdestack *stack, int domain, int type, int protocol) { struct vdecmd cmd = {domain, type, protocol}; struct vdereply reply; pthread_mutex_lock(&stack->mutex); if (write(stack->cmdpipe[APPSIDE], &cmd, sizeof(cmd)) < 0 || read(stack->cmdpipe[APPSIDE], &reply, sizeof(reply)) < 0) goto err; pthread_mutex_unlock(&stack->mutex); if (reply.rval < 0) errno = reply.err; return reply.rval; err: pthread_mutex_unlock(&stack->mutex); return -1; } static typeof(getstackdata_prototype) *getstackdata; void *ioth_vdestack_newstack(const char *vnlv[], const char *options, struct ioth_functions *ioth_f) { struct vdestack *stackdata = vde_addstack(vnlv, options); getstackdata = ioth_f->getstackdata; ioth_f->close = close; ioth_f->bind = bind; ioth_f->connect = connect; ioth_f->listen = listen; ioth_f->accept = accept; ioth_f->getsockname = getsockname; ioth_f->getpeername = getpeername; ioth_f->setsockopt = setsockopt; ioth_f->getsockopt = getsockopt; ioth_f->shutdown = shutdown; ioth_f->ioctl = ioctl; ioth_f->fcntl = fcntl; ioth_f->read = read; ioth_f->readv = readv; ioth_f->recv = recv; ioth_f->recvfrom = recvfrom; ioth_f->recvmsg = recvmsg; ioth_f->write = write; ioth_f->writev = writev; ioth_f->send = send; ioth_f->sendto = sendto; ioth_f->sendmsg = sendmsg; return stackdata; } int ioth_vdestack_delstack(void *stackdata) { vde_delstack((struct vdestack *) stackdata); return 0; } int ioth_vdestack_socket(int domain, int type, int protocol) { struct vdestack *stackdata = getstackdata(); return vde_msocket(stackdata, domain, type, protocol); } void *ioth_vdestack_n_newstack(const char *vnlv[], const char *options, struct ioth_functions *ioth_f) __attribute__ ((alias ("ioth_vdestack_newstack"))); int ioth_vdestack_n_delstack(void *stackdata) __attribute__ ((alias ("ioth_vdestack_delstack"))); int ioth_vdestack_n_socket(int domain, int type, int protocol) __attribute__ ((alias ("ioth_vdestack_socket"))); libioth-0.1.2/test/000077500000000000000000000000001454502410500141235ustar00rootroot00000000000000libioth-0.1.2/test/CMakeLists.txt000066400000000000000000000003151454502410500166620ustar00rootroot00000000000000add_executable(iothtest_server iothtest_server.c) target_link_libraries(iothtest_server ioth pthread) add_executable(iothtest_client iothtest_client.c) target_link_libraries(iothtest_client ioth pthread) libioth-0.1.2/test/iothtest_client.c000066400000000000000000000065101454502410500174720ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * test program: client * * Copyright (C) 2020-2022 Renzo Davoli * VirtualSquare team. * * this test program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . * */ #define SPDX_LICENSE "SPDX-License-Identifier: GPL-2.0-or-later" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include void *handle (void *arg) { int connfd = (uintptr_t) arg; int n; char buf[BUFSIZ]; printf("new conn %d tid %d\n", connfd, gettid()); for(;;) { if ((n = ioth_recv(connfd, buf, BUFSIZ, 0)) <= 0) break; printf("tid %d GOT: %*.*s",gettid(),n,n,buf); ioth_send(connfd, buf, n, 0); } printf("close conn %d tid %d\n", connfd, gettid()); ioth_close(connfd); return NULL; } void client(struct ioth *mystack) { struct sockaddr_in servaddr; int fd; size_t n; char buf[BUFSIZ]; fd = ioth_msocket(mystack, AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5000); inet_pton(AF_INET, "192.168.250.50", &servaddr.sin_addr); if (ioth_connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) >= 0) { struct pollfd pfd[]={ {STDIN_FILENO, POLLIN, 0}, {fd, POLLIN, 0} }; for (;;) { poll(pfd, 2, -1); if (pfd[0].revents) { n = read(STDIN_FILENO, buf, 1024); if (n==0) break; ioth_write(fd, buf,n); } if (pfd[1].revents) { n = ioth_read(fd, buf, 1024); if (n==0) break; n = write(STDOUT_FILENO, buf, n); } } } ioth_close(fd); sleep(1); } struct ioth *net_setup(const char **args) { struct ioth *mystack; uint8_t ipv4addr[] = {192,168,250,51}; uint8_t ipv4gw[] = {192,168,250,1}; int ifindex; mystack = ioth_newstackv(args[0], args+1); if (mystack != NULL) { ifindex = ioth_if_nametoindex(mystack, "vde0"); if (ifindex < 0) perror("nametoindex"); else { if (ioth_linksetupdown(mystack, ifindex, 1) < 0) perror("link up"); if (ioth_ipaddr_add(mystack, AF_INET, ipv4addr, 24, ifindex) < 0) perror("addr ipv4"); if (ioth_iproute_add(mystack, AF_INET, NULL, 0, ipv4gw, 0) < 0) perror("route ipv4"); } } return mystack; } int main(int argc, const char *argv[]) { ioth_set_license(SPDX_LICENSE); if (argc < 2) { fprintf(stderr, "Usage:\n\n\t%s stack [ vnl vnl ]\n\n", basename(argv[0])); exit(1); } else { struct ioth *mystack = net_setup(argv+1); // printf("%p\n", mystack); if (mystack) { client(mystack); ioth_delstack(mystack); } else perror("net_setup"); } } libioth-0.1.2/test/iothtest_server.c000066400000000000000000000061601454502410500175230ustar00rootroot00000000000000/* * libioth: choose your networking library as a plugin at run time. * test program: server * * Copyright (C) 2020-2022 Renzo Davoli * VirtualSquare team. * * this test program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; If not, see . */ #define SPDX_LICENSE "SPDX-License-Identifier: GPL-2.0-or-later" #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include void *handle (void *arg) { int connfd = (uintptr_t) arg; int n; char buf[BUFSIZ]; printf("new conn %d tid %d\n", connfd, gettid()); for(;;) { if ((n = ioth_recv(connfd, buf, BUFSIZ, 0)) <= 0) break; printf("tid %d GOT: %*.*s",gettid(),n,n,buf); ioth_send(connfd, buf, n, 0); } printf("close conn %d tid %d\n", connfd, gettid()); ioth_close(connfd); return NULL; } void server(struct ioth *mystack) { struct sockaddr_in servaddr; int fd, connfd; fd = ioth_msocket(mystack, AF_INET, SOCK_STREAM, 0); memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5000); servaddr.sin_addr.s_addr = 0; if (ioth_bind(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) exit(1); ioth_listen (fd, 5); for ( ; ; ) { pthread_t pt; connfd = ioth_accept (fd, NULL, NULL); if (connfd < 0) break; pthread_create(&pt, NULL, handle, (void *) (uintptr_t)connfd); pthread_detach(pt); } ioth_close(fd); } struct ioth *net_setup(const char **args) { struct ioth *mystack; uint8_t ipv4addr[] = {192,168,250,50}; uint8_t ipv4gw[] = {192,168,250,1}; int ifindex; mystack = ioth_newstackv(args[0], args+1); if (mystack != NULL) { ifindex = ioth_if_nametoindex(mystack, "vde0"); if (ifindex < 0) perror("nametoindex"); else { if (ioth_linksetupdown(mystack, ifindex, 1) < 0) perror("link up"); if (ioth_ipaddr_add(mystack, AF_INET, ipv4addr, 24, ifindex) < 0) perror("addr ipv4"); if (ioth_iproute_add(mystack, AF_INET, NULL, 0, ipv4gw, 0) < 0) perror("route ipv4"); } } return mystack; } int main(int argc, const char *argv[]) { ioth_set_license(SPDX_LICENSE); if (argc < 2) { fprintf(stderr, "Usage:\n\n\t%s stack [ vnl vnl ]\n\n", basename(argv[0])); exit(1); } else { struct ioth *mystack = net_setup(argv+1); // printf("%p\n", mystack); if (mystack) { server(mystack); ioth_delstack(mystack); } else perror("net_setup"); } }