From ee47737b635f381d94e51f04e6f367c8bb5fd2ff Mon Sep 17 00:00:00 2001 From: Tomas Abrahamsson Date: Mon, 21 Apr 2014 13:49:01 +0200 Subject: [PATCH] The py_interface has moved to github The py_interface has moved to https://github.com/tomas-abrahamsson/py_interface --- .gitignore | 18 - COPYING.LIB | 481 ---------------- ChangeLog | 99 ---- Makefile.in | 138 ----- PKG-INFO.src | 10 - README | 73 +-- TODO | 5 - configure.in | 11 - examples/run_remote_exec_wrapper.sh | 57 -- examples/run_test_erl_node_pingpong.sh | 26 - examples/run_test_erl_node_pingpong_qc.sh | 77 --- examples/test_erl_epmd.py | 105 ---- examples/test_erl_node.py | 56 -- examples/test_erl_node_conn.py | 88 --- examples/test_erl_node_pingpong.erl | 86 --- examples/test_erl_node_pingpong.py | 91 --- examples/test_erl_node_pingpong_qc.erl | 228 -------- examples/test_erl_node_tk_1.py | 196 ------- examples/test_remote_exec.py | 144 ----- howto-make-a-new-version | 24 - install-sh | 238 -------- mkinstalldirs | 32 -- py_interface/__init__.py.src | 14 - py_interface/erl_async_conn.py | 190 ------- py_interface/erl_common.py | 419 -------------- py_interface/erl_epmd.py | 607 -------------------- py_interface/erl_eventhandler.py | 492 ---------------- py_interface/erl_node.py | 899 ------------------------------ py_interface/erl_node_conn.py | 768 ------------------------- py_interface/erl_opts.py | 79 --- py_interface/erl_term.py | 683 ----------------------- setup.py.src | 15 - vsn | 1 - 33 files changed, 2 insertions(+), 6448 deletions(-) delete mode 100644 .gitignore delete mode 100644 COPYING.LIB delete mode 100644 ChangeLog delete mode 100644 Makefile.in delete mode 100644 PKG-INFO.src rewrite README (100%) delete mode 100644 TODO delete mode 100644 configure.in delete mode 100755 examples/run_remote_exec_wrapper.sh delete mode 100755 examples/run_test_erl_node_pingpong.sh delete mode 100755 examples/run_test_erl_node_pingpong_qc.sh delete mode 100644 examples/test_erl_epmd.py delete mode 100644 examples/test_erl_node.py delete mode 100644 examples/test_erl_node_conn.py delete mode 100644 examples/test_erl_node_pingpong.erl delete mode 100755 examples/test_erl_node_pingpong.py delete mode 100644 examples/test_erl_node_pingpong_qc.erl delete mode 100644 examples/test_erl_node_tk_1.py delete mode 100755 examples/test_remote_exec.py delete mode 100755 howto-make-a-new-version delete mode 100755 install-sh delete mode 100755 mkinstalldirs delete mode 100644 py_interface/__init__.py.src delete mode 100644 py_interface/erl_async_conn.py delete mode 100644 py_interface/erl_common.py delete mode 100644 py_interface/erl_epmd.py delete mode 100644 py_interface/erl_eventhandler.py delete mode 100644 py_interface/erl_node.py delete mode 100644 py_interface/erl_node_conn.py delete mode 100644 py_interface/erl_opts.py delete mode 100644 py_interface/erl_term.py delete mode 100755 setup.py.src delete mode 100644 vsn diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 974ff52..0000000 --- a/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -test_erl_node_pingpong.log-py -*.beam -*.pyc -autom4te.cache -config.cache -config.status -configure -Makefile -__init__.py -*~ -setup.py -PKG-INFO -config.log -py_interface-*.tar.gz -py_interface-*.tgz -examples/test_erl_node_pingpong.log-py -examples/test_erl_node_pingpong_qc.log-py -/build diff --git a/COPYING.LIB b/COPYING.LIB deleted file mode 100644 index 92b8903..0000000 --- a/COPYING.LIB +++ /dev/null @@ -1,481 +0,0 @@ - GNU LIBRARY GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the library GPL. It is - numbered 2 because it goes with version 2 of the ordinary GPL.] - - 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 Library General Public License, applies to some -specially designated Free Software Foundation software, and to any -other libraries whose authors decide to use it. You can use it for -your libraries, 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 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 a program 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. - - Our method of protecting your rights has two steps: (1) copyright -the library, and (2) offer you this license which gives you legal -permission to copy, distribute and/or modify the library. - - Also, for each distributor's protection, we want to make certain -that everyone understands that there is no warranty for this free -library. If the library is modified by someone else and passed on, we -want its recipients to know that what they have is not the original -version, 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 companies distributing free -software will individually obtain patent licenses, thus in effect -transforming the program into proprietary software. To prevent this, -we have made it clear that any patent must be licensed for everyone's -free use or not licensed at all. - - Most GNU software, including some libraries, is covered by the ordinary -GNU General Public License, which was designed for utility programs. This -license, the GNU Library General Public License, applies to certain -designated libraries. This license is quite different from the ordinary -one; be sure to read it in full, and don't assume that anything in it is -the same as in the ordinary license. - - The reason we have a separate public license for some libraries is that -they blur the distinction we usually make between modifying or adding to a -program and simply using it. Linking a program with a library, without -changing the library, is in some sense simply using the library, and is -analogous to running a utility program or application program. However, in -a textual and legal sense, the linked executable is a combined work, a -derivative of the original library, and the ordinary General Public License -treats it as such. - - Because of this blurred distinction, using the ordinary General -Public License for libraries did not effectively promote software -sharing, because most developers did not use the libraries. We -concluded that weaker conditions might promote sharing better. - - However, unrestricted linking of non-free programs would deprive the -users of those programs of all benefit from the free status of the -libraries themselves. This Library General Public License is intended to -permit developers of non-free programs to use free libraries, while -preserving your freedom as a user of such programs to change the free -libraries that are incorporated in them. (We have not seen how to achieve -this as regards changes in header files, but we have achieved it as regards -changes in the actual functions of the Library.) The hope is that this -will lead to faster development of free libraries. - - 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, while the latter only -works together with the library. - - Note that it is possible for a library to be covered by the ordinary -General Public License rather than by this special one. - - GNU LIBRARY GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library which -contains a notice placed by the copyright holder or other authorized -party saying it may be distributed under the terms of this Library -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 compile 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) 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. - - c) 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. - - d) 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 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. - - 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 to -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 Library 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 Library General Public - License as published by the Free Software Foundation; either - version 2 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with this library; if not, write to the Free - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -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! diff --git a/ChangeLog b/ChangeLog deleted file mode 100644 index a9ca16e..0000000 --- a/ChangeLog +++ /dev/null @@ -1,99 +0,0 @@ -version 1.1.1, 2010-Mar-15 - - * examples/run_remote_exec_wrapper.sh, - examples/test_remote_exec.py: Really do include the files that - were expected to be new as of version 1.1. - - * examples/run_test_erl_node_pingpong_qc.sh, - examples/test_erl_node_pingpong_qc.erl: Really do include the - files that were expected to be new as of version 1.1. - - * ChangeLog: include this file in the tar ball - -version 1.1, 2010-Feb-22 - - * py_interface/erl_node_conn.py: Bugfix: now handles incoming - packets larger than 64kbytes. - * examples/run_test_erl_node_pingpong_qc.sh, - examples/test_erl_node_pingpong_qc.erl: QuickCheck test of - pingpong sending of data. - * examples/run_test_erl_node_pingpong.sh: possibility to - parameterize what erl command to use for easier testing of - different version. - - * examples/run_remote_exec_wrapper.sh, - examples/test_remote_exec.py: Implemented after a discussion - with HP Wei. - -version 1.0, 2010-Apr-13 - * py_interface/erl_epmd.py: Erlang/OTP epmd R13B04 compatibility - patch by Paul "TBBle" Hampson applied: R13B04 fixed a bug in the - epmd's handling of the `extra' field. This patch makes - py_interface work with the bug-fixed epmd. - -version 0.99, 2010-Mar-13 - * py_interface/erl_common.py: Bugfix of call to _HexDumpFormat in - DebugHex. Reported by Paul "TBBle" Hampson. - -version 0.98, 2009-Nov-18 - * py_interface/erl_term.py: Bugfixes for handling of negative - integers. Reported by bird devdoer . - -version 0.97, 2009-Jul-27 - * py_interface/erl_eventhandler.py: handles interrupted system - call exceptions also in the timeout case. - * py_interface/erl_node.py: doc string fix for methods - ErlMBox.Send and ErlNode.SendMsgFromMBox: the order of the process - name and node name had gotten mixed up. Noted by Paul TBBle - Hampson. - * py_interface/erl_node_conn.py: Python 2.6 compatibility patch by - David Reiss applied: uses md5 from hashlib - if that one is available. - -version 0.96, 2008-Dec-17 - Applied two patches from Anton Krasovsky: - * The first fixes a crash when the connection from python to - erlang node is terminated, because the erlang node has gone down - or stopped replying to pings - * The second fixes a crash when a connection between python node - and the erlang node has been broken due to lack of ping - responses from the erlang node (erlang process was suspended), - and then when erlang process is resumed and terminated, - exception was thrown. - - Fixed a few cases of the version number not getting properly - inserted into all files, and one bug related to buildning: now all - files needed to build gets properly included in the distribution - tar file. - -version 0.95, 2008-Jul-15 - Applied patch from David King: - * The socket connections now also checks for EWOULDBLOCK, not only - EAGAIN. - -version 0.94, 2008-Jul-13 - Applied patches from David King: - * The code now resides in its own namespace: py_interface - * Now supports packaging as an easy_install egg - * Bugfix: Queued writes attempted to access an undefined variable. - -version 0.93, 2006-Jul-25 - * Updated to work with Erlang R10 and R11 (15-->28 bits in pids - and ports). - * Now also works with threaded Tcl (as with Debian) as well. - * Also fixed a deprecation issue: integer vs floating-point - timeout values in erl_event_handler.py. - * Also added an installation support (the __init__.py file), based - on information by Ed Blake. - -version 0.92, 2004-Jul-13 - * Several bugfixes in packing/unpacking of erlang terms. A lot of - thanks to Jimmy Olgeni and Nigel Head for patches. See the file - erl_term.py, in the tar file, for details. - -version 0.91, 2002-Jul-21 - * Added autoconf stuff. - * This version is/was also on the Erlang User contribution page - -version 0.9, 2002-May-29 - * First version diff --git a/Makefile.in b/Makefile.in deleted file mode 100644 index 6f36743..0000000 --- a/Makefile.in +++ /dev/null @@ -1,138 +0,0 @@ -## This is a -*- makefile -*- - -# What the Python binary is called on your system -PYTHON = @PYTHON@ - - -# Prefix for constructing installation directory paths -prefix = @prefix@ -exec_prefix = $(prefix) - -# Installation command -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ - -# Various auxiliary programs -cat=cat -tar=tar -sed=sed -rm=rm -ln=ln -mkdir=mkdir -tar=tar -chmod=chmod - -srcdir = @srcdir@ -VPATH = @srcdir@ -ERLC = @ERLC@ - -SOURCES = py_interface/erl_node.py \ - py_interface/erl_node_conn.py \ - py_interface/erl_async_conn.py \ - py_interface/erl_opts.py \ - py_interface/erl_common.py \ - py_interface/erl_epmd.py \ - py_interface/erl_eventhandler.py \ - py_interface/erl_term.py - -TESTPROGRAMS = examples/test_erl_epmd.py \ - examples/test_erl_node.py \ - examples/test_erl_node_conn.py \ - examples/test_erl_node_tk_1.py \ - examples/test_erl_node_pingpong.py \ - examples/test_erl_node_pingpong.erl \ - examples/run_test_erl_node_pingpong.sh \ - examples/run_remote_exec_wrapper.sh \ - examples/test_remote_exec.py \ - examples/run_test_erl_node_pingpong_qc.sh \ - examples/test_erl_node_pingpong_qc.erl - - -OBJECTS = examples/test_erl_node_pingpong.beam - - -DISTFILES = $(SOURCES) $(TESTPROGRAMS) COPYING.LIB README \ - py_interface/__init__.py py_interface/__init__.py.src \ - vsn \ - PKG-INFO PKG-INFO.src setup.py setup.py.src \ - Makefile.in configure configure.in \ - mkinstalldirs install-sh ChangeLog - - -SHELL = /bin/sh -#.PHONY: all clean dist distclean install \ -# installdirs ps uninstall -.SUFFIXES: .beam .erl .py - -examples/%.beam: examples/%.erl - $(ERLC) -o examples examples/$*.erl - -all: $(OBJECTS) py_interface/__init__.py setup.py PKG-INFO - -py_interface/__init__.py: py_interface/__init__.py.src - version=`$(cat) vsn`; \ - $(sed) -e "s/@VSN@/$$version/g" \ - < py_interface/__init__.py.src \ - > py_interface/__init__.py - -setup.py: setup.py.src - version=`$(cat) vsn`; \ - $(sed) -e "s/@VSN@/$$version/g" > setup.py < setup.py.src && \ - $(chmod) +x setup.py - -PKG-INFO: PKG-INFO.src - version=`$(cat) vsn`; \ - $(sed) -e "s/@VSN@/$$version/g" > PKG-INFO < PKG-INFO.src - - -install: all installdirs - -# Make sure all installation directories actually exist -# by making them if necessary. -installdirs: mkinstalldirs - -# $(srcdir)/mkinstalldirs $(pythondir) - -uninstall: - -# -cd $(pythondir) && rm -f $(SOURCES) $(OBJECTS) - -TAGS: $(SOURCES) - cd $(srcdir) && etags $(SOURCES) - -clean: - rm -f $(OBJECTS) - -rm -f *.aux *.cp *.cps *.fn *.ky *.log *.pg *.toc *.tp *.vr - -rm -f *.html - rm -f TAGS - rm -f erl_crash.dump - rm -f *.beam - rm -f py_interface/__init__.py setup.py PKG-INFO - -distclean: clean - -rm -f *~ *.tar.gz - rm -f Makefile config.status config.cache config.log - -${srcdir}/configure: configure.in - cd ${srcdir} && autoconf - -Makefile: Makefile.in config.status - ./config.status - -config.status: ${srcdir}/configure - ./config.status --recheck - - -dist: $(DISTFILES) - version=`$(cat) vsn`; \ - distname=py_interface-$$version; \ - $(rm) -rf $$distname; \ - $(mkdir) $$distname; \ - for file in $(DISTFILES); do \ - d="`dirname $$file`"; \ - [ -d "$$distname/$$d" ] || mkdir -p "$$distname/$$d"; \ - $(ln) $$file $$distname/$$file; \ - done; \ - $(tar) -chz -f $$distname.tar.gz $$distname; \ - /bin/rm -f $$distname.tgz; ln $$distname.tar.gz $$distname.tgz; \ - $(rm) -rf $$distname diff --git a/PKG-INFO.src b/PKG-INFO.src deleted file mode 100644 index e336760..0000000 --- a/PKG-INFO.src +++ /dev/null @@ -1,10 +0,0 @@ -Metadata-Version: 1.0 -Name: py_interface -Version: @VSN@ -Summary: A python-implementation of an Erlang node -Home-page: http://www.lysator.liu.se/~tab/erlang/py_interface/ -Author: Tomas Abrahamsson -Author-email: tab@lysator.liu.se -License: GNU Library General Public License -Description: UNKNOWN -Platform: UNKNOWN diff --git a/README b/README dissimilarity index 100% index 98f0f80..75817fc 100644 --- a/README +++ b/README @@ -1,71 +1,2 @@ -README for the py_interface ---------------------------- -$Id$ - - -What is py_interface --------------------- - -The py_interface is a python-implementation of an Erlang node. For -information on the Erlang programming language, visit the web site -http://www.erlang.org/. - -The py_interface provides the possibility to create a node that may be -used for communication with other Erlang nodes. - -Some characteristics: -* The Python nodes are hidden, like the Java nodes -* The Python node supports - - registering the Python node in the epmd - - sending and receiving message - - executing remote procedure calls (the rpc:call(M,F,A) mechanism) -* The Python node does currently _not_ do: - - linking - - tracing -* The Python node translates Erlang types to Python types as far as - there is a reasonable Python counterpart. If there is not, then - a class is used. -* The Python node is a single threaded callback-driven process. -* The Python node is released under LGPL, see the file COPYING.LIB. -* The Python node runs on Python 1.5 -- Python 2.3. It - can talk to Erlang R7 -- R9 nodes, as far as I know. -* The source of information for this Python node has been the files - `distribution_handshake.txt' and `erl_ext_dist.txt' together with - the Java node source files, the `net_kernel.erl' and the - `dist_util.erl' files in the Erlang source code distribution. - - -General programming model -------------------------- - -When using the py_interface, the general principle is to register a -callback for different purposes, such as incoming messages to the pid, -an return from an rpc-call, or a timeout. The callback will get called -whenever the message or return value arrives or when the timer times -out. - -The easiest way to get acquainted with the Python node, check out the -test programs: - -* run_test_erl_node_pingping.sh - This tests communication, packing and unpacking of terms, - and show how to start the nodes. - -* test_erl_node_tk_1.py - This brings up a window in which you can select - to send a message or to make an rpc-call. - -* test_erl_node.py - This starts a Python node and registers a process called p. - You can then start an Erlang node and send messages to this - process. - -* test_erl_node_conn.py - This tests lowlevel inter-node communication. - - -Contacting the author ---------------------- -To contact the author, Tomas Abrahamsson: send a mail to: -tab@lysator.liu.se - +The py_interface has moved to +https://github.com/tomas-abrahamsson/py_interface diff --git a/TODO b/TODO deleted file mode 100644 index f66edb4..0000000 --- a/TODO +++ /dev/null @@ -1,5 +0,0 @@ -Cookies: Make it read the first line of ~/.erlang.cookie, trim whitespace - -Nodename: Check whether we should use long or short node name - e.g. @host.domain.com or just @host -Nodename: must not exceed 255 characters! diff --git a/configure.in b/configure.in deleted file mode 100644 index 41dbe38..0000000 --- a/configure.in +++ /dev/null @@ -1,11 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. -AC_INIT() - -AC_PROG_INSTALL() - -AC_CHECK_PROGS(PYTHON, python) - -AC_CHECK_PROGS(ERL, erl) -AC_CHECK_PROGS(ERLC, erlc) - -AC_OUTPUT(Makefile) diff --git a/examples/run_remote_exec_wrapper.sh b/examples/run_remote_exec_wrapper.sh deleted file mode 100755 index 6cf5b4a..0000000 --- a/examples/run_remote_exec_wrapper.sh +++ /dev/null @@ -1,57 +0,0 @@ -#! /bin/sh - -# A simple demo to show remote execution -if [ x"$1" = x"-d" ] -then - debug="-d" - shift -fi - -if [ ! -f ./test_remote_exec.py ] -then - echo "Run me in the examples directory!" - echo "Expected test_remote_exec.py to be in the current working directory" - echo "in order to get python path setup correct. Exiting." - exit 1 -fi - - -erl=${ERL:-erl} -epmd=${EPMD:-epmd} - -echo "Starting a backgrounded erlang node..." -$erl -setcookie more-cookies -sname enode@localhost -noinput \ - -eval 'timer:sleep(15000), erlang:halt().' & -erlnode=$! -echo "Starting a backgrounded erlang node...$erlnode" -printf "Waiting the backgrounded node to register to the epmd..." -registered=false -num_tries=0 -while [ $registered = false -a $num_tries -lt 10 ] -do - if ($epmd -names | egrep '^name enode at port' >/dev/null) - then - registered=true - fi - sleep 1 - printf "." - num_tries=`expr $num_tries + 1` -done -echo -echo "Waiting the backgrounded node to register to the epmd...$registered" - -trap "/bin/kill $erlnode 2>/dev/null; exit" 0 - -echo -echo "Will now ask the remote erlang-node to print something." -echo "-------------------------------------------------------" -# Now start the pythonnode -PYTHONPATH=..:$PYTHONPATH ./test_remote_exec.py \ - $debug -n pynode1@localhost -c more-cookies -t 5 \ - enode@localhost io format '"Erlang side printing: ~p~n"' "['xyz']" -echo -echo "Will now halt the remote erlang-node." -echo "-------------------------------------" -PYTHONPATH=..:$PYTHONPATH ./test_remote_exec.py \ - $debug -n pynode2@localhost -c more-cookies -t 5 \ - enode@localhost erlang halt diff --git a/examples/run_test_erl_node_pingpong.sh b/examples/run_test_erl_node_pingpong.sh deleted file mode 100755 index 95d2872..0000000 --- a/examples/run_test_erl_node_pingpong.sh +++ /dev/null @@ -1,26 +0,0 @@ -#! /bin/sh - -# A test case for testing packing/unpacking of erlang-terms: -# -# A message is sent from an erlang node to a python node. -# That message is echoed back to the erlang node, which checks -# if the received message matches the original message. -# - -erl=${ERL:-erl} - -# First make sure epmd is up and running. (needed by the python-node) -$erl -noinput -detach -sname ensure_epmd_started@localhost -s erlang halt - -# Now start the pythonnode -PYTHONPATH=..:$PYTHONPATH ./test_erl_node_pingpong.py \ - -n py_interface_test@localhost -c cookie \ - > test_erl_node_pingpong.log-py 2>&1 & -pynode=$! - -$erl -noinput -sname enode1@localhost \ - -setcookie cookie \ - -s test_erl_node_pingpong start \ - -s erlang halt - -kill $pynode diff --git a/examples/run_test_erl_node_pingpong_qc.sh b/examples/run_test_erl_node_pingpong_qc.sh deleted file mode 100755 index 6fbde43..0000000 --- a/examples/run_test_erl_node_pingpong_qc.sh +++ /dev/null @@ -1,77 +0,0 @@ -#! /bin/bash - -# script debugging -#set -xv - -# A test case for testing packing/unpacking of erlang-terms: -# -# A message is sent from an erlang node to a python node. -# That message is echoed back to the erlang node, which checks -# if the received message matches the original message. -# - -erl=${ERL:-erl} -eqc_path=${EQC_EBIN_PATH:-} - -if [ x"$eqc_path" != x ] -then - eqc_opt="-pa '$eqc_path'" -fi - -# Verify that we have quickcheck(mini) -have_eqc="$(erl +B -boot start_clean -noinput -noshell $eqc_opt -eval \ - 'case code:which(eqc) of - non_existing -> io:format("no~n"); - P when is_list(P) -> io:format("yes~n") - end.' -s erlang halt)" - -if [ x"$have_eqc" != xyes ] -then - echo "ERROR: QuickCheck (mini) needed but not found! Aborting." >&2 - echo "Download it from http://www.quviq.com/downloads/eqcmini.zip" - echo "and set the ERL_LIBS environment variable to include it," - echo "or set the EQC_EBIN_PATH environment variable." - echo - echo "Example (zsh/bash/...):" - echo " export ERL_LIBS=/usr/local/eqcmini/eqc-1.0.1" - echo " export EQC_EBIN_PATH=/usr/local/eqcmini/eqc-1.0.1/ebin" - echo - echo "Example (csh/tcsh):" - echo " setenv ERL_LIBS /usr/local/eqcmini/eqc-1.0.1" - echo " setenv EQC_EBIN_PATH /usr/local/eqcmini/eqc-1.0.1/ebin" - exit 1 -fi - -die () { echo "$@"; exit 1; } - -if [ ! -f test_erl_node_pingpong_qc.beam -o \ - test_erl_node_pingpong_qc.erl -nt test_erl_node_pingpong_qc.beam ] -then - echo "Compiling test_erl_node_pingpong_qc.erl..." - erlc -Wall $eqc_opt test_erl_node_pingpong_qc.erl \ - || die "Failed" -fi - -echo "Making sure we have epmd up and running..." -$erl +B -noinput -sname ensure_epmd_started@localhost -s erlang halt - -echo "Starting the py_interface python node..." -pynodename=py_interface_test_qc@localhost -log=test_erl_node_pingpong_qc.log-py -/bin/rm -f "$log" -touch "$log" -env PYTHONPATH=..:"$PYTHONPATH" PYTHONUNBUFFERED=x \ - ./test_erl_node_pingpong.py -q -n "$pynodename" -c cookie > "$log" 2>&1 & -echo $! > pynode_pid -#tail -f test_erl_node_pingpong_qc.log-py & -#dedicated_follower=$! - -echo "Starting the erlang qc node..." -$erl -noinput -sname qcnode1@localhost \ - -setcookie cookie \ - -s test_erl_node_pingpong_qc start "$pynodename" "PYTHONPATH=..:'$PYTHONPATH' PYTHONUNBUFFERED=x ./test_erl_node_pingpong.py -q -n '$pynodename' -c cookie >> '$log' 2>&1" \ - -s erlang halt - -[ -f pynode_pid ] && kill `cat pynode_pid` -/bin/rm -f pynode_pid -#kill $dedicated_follower diff --git a/examples/test_erl_epmd.py b/examples/test_erl_epmd.py deleted file mode 100644 index 9bb392a..0000000 --- a/examples/test_erl_epmd.py +++ /dev/null @@ -1,105 +0,0 @@ -#! /usr/bin/env python - -import sys -import types -import string -import socket -import getopt - -from py_interface import erl_epmd -from py_interface import erl_common -from py_interface import erl_async_conn -from py_interface import erl_eventhandler - -e = None - -def TestAliveOkResp(creation): - print "AliveOkResp creation=%d" % creation - -def TestAliveNotOkResp(self): - print "AliveNotOkResp" - -def TestAlive2Resp(result, creation): - print "Alive2Resp, result=%d, creation=%d" % (result, creation) - -def TestAlive2RespConnected(creation): - print "Alive2RespConnected, creation=%d" % creation - nodeToCheckFor = "flerp" - print "Checking for node named \"%s\"." % nodeToCheckFor - e.PortPlease2Req(nodeToCheckFor, TestPort2Resp) - -def TestAlive2RespConnectFailed(result): - print "Alive2RespConnectFailed, result=%d" % result - -def TestPortOkResp(portNum): - print "PortOkResp, portNum=%d" % portNum - -def TestPortNotOkResp(self): - print "PortNotOkResp" - -def TestPort2Resp(result, portNum, nodeType, proto, distr, nodeName, extra): - if result == 0: - # found - print ("Port2Resp, result=ok, portNum=%d, nodeType=%d, protocol=%d," + - " distrVSNRange=%s, nodeName=\"%s\", extra=\"%s\"") % \ - (portNum, nodeType, proto, `distr`, nodeName, extra) - else: - # not found - print "Port2Resp, result=%d" % result - - -def TestNamesResp(epmdPortNum, nodeInfo): - print "NamesResp, epmdPortNum=%d nodeInfo:\n%s" % \ - (epmdPortNum, nodeInfo) - -def TestDumpResp(epmdPortNum, nodeInfo): - print "DumpResp, epmdPortNum=%d nodeInfo:\n%s" % \ - (epmdPortNum, nodeInfo) - -def TestKillResp(resp): - print "KillResp, resp=%s" % resp - -def TestStopResp(resp): - print "StopResp, resp=%s" % resp - -def TestConnectionClosed(): - print "Connection to epmd has been closed." - -def main(argv): - global e - - try: - opts, args = getopt.getopt(argv[1:], "?p:n:") - except getopt.error, info: - print info - - hostName = "localhost" - portNum = 4369 - ownPortNum = 1234 - ownNodeName = "py_interface_test" - - for (optchar, optarg) in opts: - if optchar == "-?": - print "Usage: %s host [port]" % argv[0] - sys.exit(1) - elif optchar == "-p": - ownPortNum = string.atoi(optarg) - elif optchar == "-n": - ownNodeName = optarg - - if len(args) >= 2: - hostName = args[0] - portNum = string.atoi(args[1]) - elif len(args) == 1: - hostName = args[0] - - e = erl_epmd.ErlEpmd(hostName, portNum) - e.SetOwnPortNum(ownPortNum) - e.SetOwnNodeName(ownNodeName) - e.Connect(TestAlive2RespConnected, TestAlive2RespConnectFailed) - evhandler = erl_eventhandler.GetEventHandler() - evhandler.Loop() - - -main(sys.argv) - diff --git a/examples/test_erl_node.py b/examples/test_erl_node.py deleted file mode 100644 index df2932f..0000000 --- a/examples/test_erl_node.py +++ /dev/null @@ -1,56 +0,0 @@ -#! /usr/bin/env python - -import sys -import getopt - -from py_interface import erl_node -from py_interface import erl_opts -from py_interface import erl_eventhandler - -### -### -### -### TEST CODE -### -### - -def __TestMBoxCallback(msg): - print "msg=%s" % `msg` - -n=None -m=None -def main(argv): - try: - opts, args = getopt.getopt(argv[1:], "?n:c:") - except getopt.error, info: - print info - sys.exit(1) - - hostName = "localhost" - ownNodeName = "py_interface_test" - cookie = "cookie" - - for (optchar, optarg) in opts: - if optchar == "-?": - print "Usage: %s erlnode" % argv[0] - sys.exit(1) - elif optchar == "-c": - cookie = optarg - elif optchar == "-n": - ownNodeName = optarg - - print "Creating node..." - n = erl_node.ErlNode(ownNodeName, erl_opts.ErlNodeOpts(cookie=cookie)) - print "Publishing node..." - n.Publish() - print "Creating mbox..." - m = n.CreateMBox(__TestMBoxCallback) - print "Registering mbox as p..." - m.RegisterName("p") - - print "Looping..." - evhand = erl_eventhandler.GetEventHandler() - evhand.Loop() - - -main(sys.argv) diff --git a/examples/test_erl_node_conn.py b/examples/test_erl_node_conn.py deleted file mode 100644 index 4db38b5..0000000 --- a/examples/test_erl_node_conn.py +++ /dev/null @@ -1,88 +0,0 @@ -#! /usr/bin/env python - -### -### -### Test code -### -### -import sys -import string -import getopt - -from py_interface import erl_opts -from py_interface import erl_common -from py_interface import erl_node_conn -from py_interface import erl_eventhandler - - -def __TestConnectOk(): - print "ConnectOk" - -def __TestConnectFailed(): - print "ConnectFailed" - -def __TestConnectionBroken(connection, nodeName): - print "ConnectionBroken for %s" % nodeName - -def __TestPassThroughMsg(controlMsg, msg=None): - print "passThrough:" - print " controlMsg=%s" % `controlMsg` - print " msg=%s" % `msg` - -def main(argv): - global e - - try: - opts, args = getopt.getopt(argv[1:], "?n:c:d:f:") - except getopt.error, info: - print info - sys.exit(1) - - hostName = "localhost" - ownNodeName = "py_interface_test" - cookie = "cookie" - ownDistrVersion = 5 - ownFlags = 4 - - for (optchar, optarg) in opts: - if optchar == "-?": - print "Usage: %s [host] port" % argv[0] - sys.exit(1) - elif optchar == "-c": - cookie = optarg - elif optchar == "-n": - ownNodeName = optarg - elif optchar == "-d": - ownDistrVersion = string.atoi(optarg) - elif optchar == "-f": - ownFlags = string.atoi(optarg) - - if len(args) >= 2: - hostName = args[0] - portNum = string.atoi(args[1]) - elif len(args) >= 1: - portNum = string.atoi(args[0]) - else: - sys.exit(1) - - ownNodeName = erl_common.AlignNodeName(ownNodeName, 1) - - print "Connecting to %s:%d" - print " ownNodeName=\"%s\"" % ownNodeName - print " cookie=\"%s\"" % cookie - print " ownDistrVersion=%d" % ownDistrVersion - print " ownFlags=%d" % ownFlags - - opts = erl_opts.ErlNodeOpts(cookie=cookie) - c = erl_node_conn.ErlNodeOutConnection(ownNodeName, opts) - c.InitiateConnection(hostName, portNum, - __TestConnectOk, - __TestConnectFailed, - __TestConnectionBroken, - __TestPassThroughMsg) - evhandler = erl_eventhandler.GetEventHandler() - evhandler.Loop() - - -main(sys.argv) - diff --git a/examples/test_erl_node_pingpong.erl b/examples/test_erl_node_pingpong.erl deleted file mode 100644 index 9d9fd0b..0000000 --- a/examples/test_erl_node_pingpong.erl +++ /dev/null @@ -1,86 +0,0 @@ -%% A test case for testing packing/unpacking of erlang-terms: -%% -%% See run_test_erl_node_pingpong.sh for how to run it. -%% -%% A message is sent from an erlang node to a python node. -%% That message is echoed back to the erlang node, which checks -%% if the received message matches the original message. -%% --module(test_erl_node_pingpong). - --export([start/0, start/1]). - - -start() -> - start(['py_interface_test@localhost']). - -start([OtherNode]) -> - Term = {self(), [1, % small_integer_ext - 255, % small_integer_ext - 256, % integer_ext - 16#7fffffff, % integer_ext - -1, % negative integer_ext - -256, % negative integer_ext - -16#7fffffff,% negative integer_ext - -16#80000000,% negative integer_ext - 1.1, % float_ext - atom_ext, % atom_ext - '', % atom_ext - make_ref(),% new_reference_ext (reference_ext) - fixme, % port_ext - self(), % pid_ext - {}, % small_tuple_ext (up to 255 elements) - {1}, % small_tuple_ext (up to 255 elements) - {1,2,3,4}, % small_tuple_ext (up to 255 elements) - [], % nil_ext - "abc", % string_ext (up to 65k chars) - [1,2,3], % list_ext - % fixme: make test for improper lists - <<>>, % binary_ext - <<"abc">>, % binary_ext - 2 bsl 33, % small_big_ext - -16#80000001,% negative small_big_ext - fixme, % fixme: flag stuff needed to get funs to work - ' $end$ ' - ] - }, - LargeTerm = {self(), - [%% large_tuple_ext (>255 elements) - list_to_tuple(lists:seq(0,257)), - %% large_big_ext (needs > 255 bytes), positive and negative - 2 bsl (256*8), - -(2 bsl (256*8)), - %% string_ext - lists:duplicate(3000, $a), - ' $endlarge$ ' - ]}, - - - io:format("Sending message...~n"), - {p, OtherNode} ! Term, - io:format("Sending message...done~n"), - io:format("Waiting for answer...~n"), - receive - Term -> - io:format("Ok, got term ~p~n",[Term]), - io:format("Sending larger message...~n"), - {p, OtherNode} ! LargeTerm, - io:format("Sending larger message...done~n"), - io:format("Waiting for answer again...~n"), - receive - LargeTerm -> io:format("Ok, got term ~p~n",[LargeTerm]), - io:format("Test succeeded!~n"); - Y -> io:format("Oops, got ~p~n",[Y]), - io:format("Test failed.~n") - after 10000 -> - io:format("Timeout2~n"), - io:format("Test failed.~n") - end; - X -> - io:format("Oops, expected:~n ~p~n"++ - "got:~n ~p~n", [Term, X]), - io:format("Test failed.~n") - after 10000 -> - io:format("Timeout~n"), - io:format("Test failed.~n") - end. diff --git a/examples/test_erl_node_pingpong.py b/examples/test_erl_node_pingpong.py deleted file mode 100755 index 8cc62bd..0000000 --- a/examples/test_erl_node_pingpong.py +++ /dev/null @@ -1,91 +0,0 @@ -#! /usr/bin/env python - -## A test case for testing packing/unpacking of erlang-terms: -## -## See run_test_erl_node_pingpong.sh for how to run it. -## -## A message is sent from an erlang node to a python node. -## That message is echoed back to the erlang node, which checks -## if the received message matches the original message. -## - -import sys -import types -import string -import socket -import getopt - - -from py_interface import erl_term -from py_interface import erl_node -from py_interface import erl_opts -from py_interface import erl_common -from py_interface import erl_eventhandler - -mb = None -quiet = False - -def __TestMBoxCallback(msg, *k, **kw): - global mb, quiet - if not quiet: - print "Incoming msg=%s (k=%s, kw=%s)" % (`msg`, `k`, `kw`) - if type(msg) == types.TupleType: - if len(msg) == 2: - if erl_term.IsErlPid(msg[0]): - dest = msg[0] - if not quiet: - print "Sending it back to %s" % (dest,) - mb.Send(dest, msg) - - - -def main(argv): - global mb, quiet - - try: - opts, args = getopt.getopt(argv[1:], "?dn:c:q") - except getopt.error, info: - print info - sys.exit(1) - - hostName = "localhost" - ownNodeName = "py_interface_test" - cookie = "cookie" - doDebug = 0 - - for (optchar, optarg) in opts: - if optchar == "-?": - print "Usage: %s erlnode" % argv[0] - sys.exit(1) - elif optchar == "-c": - cookie = optarg - elif optchar == "-d": - doDebug = 1 - elif optchar == "-q": - quiet = 1 - elif optchar == "-n": - ownNodeName = optarg - - - if doDebug: - erl_common.DebugOnAll() - - print "Creating node..." - n = erl_node.ErlNode(ownNodeName, erl_opts.ErlNodeOpts(cookie=cookie)) - print "Publishing node..." - n.Publish() - print "Creating mbox..." - mb = n.CreateMBox(None) - m = n.CreateMBox(__TestMBoxCallback) - print "Registering mbox as p..." - m.RegisterName("p") - - print "Looping..." - evhand = erl_eventhandler.GetEventHandler() - evhand.Loop() - -try: - main(sys.argv) -except KeyboardInterrupt: - print "Interrupted. Exiting." - sys.exit(1) diff --git a/examples/test_erl_node_pingpong_qc.erl b/examples/test_erl_node_pingpong_qc.erl deleted file mode 100644 index f4182bc..0000000 --- a/examples/test_erl_node_pingpong_qc.erl +++ /dev/null @@ -1,228 +0,0 @@ -%% A test case for testing packing/unpacking of erlang-terms: -%% -%% See run_test_erl_node_pingpong_qc.sh for how to run it. -%% -%% Use quickcheck (eqcmini) to generate a lot of various values -%% to send to the python node and then receive back again. -%% -%% The eqcmini is a free (as in free of charge) version of quickcheck: -%% http://www.quviq.com/downloads/eqcmini.zip -%% More info here: http://www.quviq.com/news100621.html -%% -%% This might also work with PropEr, https://github.com/manopapad/proper -%% --module(test_erl_node_pingpong_qc). - --export([start/0, start/1]). - --export([prop_same_term_returns_after_roundtrip/0]). --export([prop_same_term_returns_after_roundtrip/1]). - --define(PYNODENAME_HOLDER, list_to_atom(atom_to_list(?MODULE)++"_holder")). --define(PYNODENAME_HOLDER_T, list_to_atom(atom_to_list(?MODULE)++"_holder_t")). --define(MAX_WAIT_PYNODE_UP, 20). % seconds - --include_lib("eqc/include/eqc.hrl"). - -start() -> - start(['py_interface_test_qc@localhost']). - -start([PyNodeName, PyCmdA]) -> - ensure_pynodename_holder_started(PyNodeName, atom_to_list(PyCmdA)), - io:format("Checking for Python node (~p) liveness...~n", [PyNodeName]), - case wait_until_node_available(PyNodeName, ?MAX_WAIT_PYNODE_UP) of - ok -> - io:format("Running tests...~n"), - eqc:module(?MODULE); - {error, Reason} -> - io:format("Failed to find the python node ~p~n ~p~n", - [PyNodeName, Reason]), - false - end. - -prop_same_term_returns_after_roundtrip() -> - eqc:numtests(500, - prop_same_term_returns_after_roundtrip(get_pynodename())). - -prop_same_term_returns_after_roundtrip(PyNodeName) -> - ?FORALL(Term, term(), - begin - ensure_py_node_running(), - ensure_node_monitored(PyNodeName), - Me = self(), - {p, PyNodeName} ! {Me, Term}, - Received = - receive - {Me, Term2} -> - {got,Term2}; - {nodedown, PyNodeName, _} -> - case flush_mbox() of - [] -> nodedown; - Ms -> {nodedown,{but_got_msgs,Ms}} - end - end, - ?WHENFAIL(if is_tuple(Term) -> - io:format("TupleTerm (~p elems)=~p~nGot=~p~n", [tuple_size(Term), Term, Received]); - true -> - io:format("Term=~p~nGot=~p~n", [Term, Received]) - end, - case Received of - nodedown -> false; - {nodedown,_} -> false; - {got,X} -> X =:= Term - end) - end). - -term() -> - oneof([term2(), - list(term2()), - t_tuple(n_uint(14), term2())]). - -term2() -> - oneof([int(), n_uint(32), n_sint(32), largeint(), - real(), - t_atom(), - t_ref(), - t_pid(), - t_string(), - binary(), - %% bitstring(), not supported yet - %% some-function... - %% improper list - %% m:f/a export - t_port()]). - -n_sint(Base) -> - oneof([n_uint(Base), ?LET(X, n_uint(Base), -X)]). - -n_uint(Base) -> - oneof([choose(0, pow2(B)-1) || B <- lists:seq(1, Base)]). - -pow2(0) -> 1; -pow2(N) when N > 0 -> 2*pow2(N-1); -pow2(N) when N < 0 -> 1/pow2(-N). - -t_tuple(SizeG, G) -> - ?LET(NumElems, SizeG, - ?LET(L, vector(NumElems, G), list_to_tuple(L))). - -t_atom() -> - oneof([a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, - a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, - a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, - x]). - -t_ref() -> - ?LET(_, int(), make_ref()). - -t_pid() -> - ?LET(_, int(), self()). - -t_port() -> - elements(erlang:ports()). - - -t_string() -> - list(n_uint(8)). - - -%% auxiliaries -------------------------------------------------------- - -ensure_py_node_running() -> - PyNodeName = get_pynodename(), - case wait_until_node_available(PyNodeName, 0.1) of - ok -> - ok; - {error,_} -> - Cmd = get_pynodecmd() ++ " &", - spawn(fun() -> Cmd2 = Cmd++ "\necho $! > pynode_pid", - case os:cmd(Cmd2) of - "" -> ok; - X -> io:format("Cmd ~p~n==> ~p~n", [Cmd2, X]) - end - end), - case wait_until_node_available(PyNodeName, ?MAX_WAIT_PYNODE_UP) of - ok -> - flush_any_nodeup(), - timer:sleep(300), %% Give it some time to start properly - ok; - {error, Reason} -> - exit({e2,Reason}) - end - end. - -ensure_node_monitored(_PyNodeName) -> - case get(has_monitored) of - undefined -> - net_kernel:monitor_nodes(true, [{node_type, hidden}]), - put(has_monitored, true); - true -> - ok - end. - -ensure_pynodename_holder_started(PyNodeName, PyNodeCmd) -> - case whereis(?PYNODENAME_HOLDER) of - undefined -> - Master = self(), - {P, MRef} = erlang:spawn_monitor( - fun() -> - T = ets:new(?PYNODENAME_HOLDER_T, - [set,named_table]), - ets:insert(T, {pynodename,PyNodeName}), - ets:insert(T, {pynodecmd,PyNodeCmd}), - Master ! {self(), started}, - timer:sleep(infinity) - end), - receive - {'DOWN',MRef,_,_,Reason} -> - exit(Reason); - {P, started} -> - erlang:demonitor(MRef,[flush]), - ok - end; - P when is_pid(P) -> - ok - end. - -get_pynodename() -> - [{pynodename,PyNodeName}] = ets:lookup(?PYNODENAME_HOLDER_T, pynodename), - PyNodeName. - -get_pynodecmd() -> - [{pynodecmd,PyNodeCmd}] = ets:lookup(?PYNODENAME_HOLDER_T, pynodecmd), - PyNodeCmd. - -wait_until_node_available(NodeName, MaxT) -> - wait_until_node_available(NodeName, MaxT, _T0=now()). - -wait_until_node_available(NodeName, MaxT, T0) -> - NStr = atom_to_list(NodeName), - {ok,NamePorts} = erl_epmd:names(), - case [Name || {Name,_P} <- NamePorts, lists:prefix(Name, NStr)] of - [] -> - SecondsSinceT0 = timer:now_diff(now(), T0) / 1000000, - if SecondsSinceT0 > MaxT -> - {error, {timeout_waiting_for_presence_in_epmd, - {NodeName, NamePorts}}}; - true -> - timer:sleep(100), - wait_until_node_available(NodeName, MaxT, T0) - end; - [_NodeNameInEpmd] -> - ok - end. - -flush_mbox() -> - receive - X -> [X | flush_mbox()] - after 0 -> - [] - end. - -flush_any_nodeup() -> - N = get_pynodename(), - receive - {nodeup,N,_} -> flush_any_nodeup() - after 0 -> - ok - end. diff --git a/examples/test_erl_node_tk_1.py b/examples/test_erl_node_tk_1.py deleted file mode 100644 index 06eda89..0000000 --- a/examples/test_erl_node_tk_1.py +++ /dev/null @@ -1,196 +0,0 @@ -#! /usr/bin/env python - -import sys -import types -import string -import socket -import getopt -from Tkinter import * - - -from py_interface import erl_term -from py_interface import erl_node -from py_interface import erl_opts -from py_interface import erl_common -from py_interface import erl_eventhandler - -class TkTest: - def __init__(self, top, node, mbox): - self.node = node - self.mbox = mbox - - self.evhand = erl_eventhandler.GetEventHandler() - if sys.stdin.isatty(): - # only useful if stdin might generate KeyboardInterrupt - self.__CheckKbdInterrupt() - - f1 = Frame(top) - self.destVar = StringVar() - self.msgVar = StringVar() - self.destVar.set("(\"xxsh\",\"address@%s\")" % socket.gethostname()) - self.msgVar.set("\"hej\"") - b = Button(f1, text="Send", borderwidth=1, - command=self.Send) - b.pack(side=LEFT) - dg = Label(f1, text="Dest:") - de = Entry(f1, borderwidth=1, textvariable=self.destVar) - mg = Label(f1, text="Msg:") - me = Entry(f1, borderwidth=1, textvariable=self.msgVar) - dg.pack(side=LEFT) - de.pack(side=LEFT) - mg.pack(side=LEFT) - me.pack(side=LEFT) - f1.pack() - - f2 = Frame(top) - b2 = Button(f2, text="SendRPC", borderwidth=1, command=self.SendRPC) - b2.pack(side=LEFT) - self.remoteNodeVar = StringVar() - self.modVar = StringVar() - self.funVar = StringVar() - self.argsVar = StringVar() - self.remoteNodeVar.set("\"'address@%s'\"" % socket.gethostname()) - self.modVar.set("\"'io'\"") - self.funVar.set("\"'format'\"") - self.argsVar.set("[\"hej!~nhopp!~n\", []]") - rnl = Label(f2, text="remotenode:") - rne = Entry(f2, borderwidth=1, textvariable=self.remoteNodeVar) - modl = Label(f2, text="mod:") - mode = Entry(f2, borderwidth=1, width=10, textvariable=self.modVar) - funl = Label(f2, text="fun:") - fune = Entry(f2, borderwidth=1, width=10, textvariable=self.funVar) - argsl = Label(f2, text="args:") - argse = Entry(f2, borderwidth=1, textvariable=self.argsVar) - rnl.pack(side=LEFT) - rne.pack(side=LEFT) - modl.pack(side=LEFT) - mode.pack(side=LEFT) - funl.pack(side=LEFT) - fune.pack(side=LEFT) - argsl.pack(side=LEFT) - argse.pack(side=LEFT) - f2.pack() - - f3 = Frame(top) - b3 = Button(f3, text="Dump node connections", - borderwidth=1, command=self.NDump) - b3.pack(side=LEFT) - f3.pack() - - def __CheckKbdInterrupt(self): - # Exercise the Python interpreter regularly so keyboard - # interrupts get through - self.evhand.AddTimerEvent(0.25, self.__CheckKbdInterrupt) - - def Send(self, event=None): - dest = eval(self.destVar.get()) - msg = ExprRebuildAtoms(eval(self.msgVar.get())) - msgCooked = ExprRebuildAtoms(msg) - print "Sending:" - print " dest=%s" % `dest` - print " msg =%s" % `msg` - self.mbox.Send(dest, msg) - - def SendRPC(self, event=None): - n = ExprRebuildAtoms(eval(self.remoteNodeVar.get())) - m = ExprRebuildAtoms(eval(self.modVar.get())) - f = ExprRebuildAtoms(eval(self.funVar.get())) - a = ExprRebuildAtoms(eval(self.argsVar.get())) - print "Sending:" - print " n=%s" % `n` - print " m=%s" % `m` - print " f=%s" % `f` - print " a=%s" % `a` - self.mbox.SendRPC(n, m, f, a, self._TestMBoxRPCResponse) - - - def _TestMBoxCallback(self, msg, *x, **kw): - print "Incoming msg=%s" % `msg` - - def _TestMBoxRPCResponse(self, msg): - print "RPC answer: %s" % `msg` - - def NDump(self, event=None): - self.node.DumpConnections() - - - -def ExprRebuildAtoms(expr): - if type(expr) == types.StringType: - if len(expr) >= 2 and expr[0] == expr[-1] == "'": - atomText = expr[1:-1] - return erl_term.ErlAtom(atomText) - else: - return expr - elif type(expr) == types.ListType: - rebuiltList = [] - for elem in expr: - rebuiltElem = ExprRebuildAtoms(elem) - rebuiltList.append(rebuiltElem) - return rebuiltList - elif type(expr) == types.TupleType: - rebuiltList = [] - for elem in list(expr): - rebuiltElem = ExprRebuildAtoms(elem) - rebuiltList.append(rebuiltElem) - return tuple(rebuiltList) - else: - return expr - - - - -def __TestMBoxCallback(msg): - print "Incoming msg=%s" % `msg` - - -def main(argv): - try: - opts, args = getopt.getopt(argv[1:], "?dn:c:") - except getopt.error, info: - print info - sys.exit(1) - - hostName = "localhost" - ownNodeName = "py_interface_test" - cookie = "cookie" - doDebug = 0 - - for (optchar, optarg) in opts: - if optchar == "-?": - print "Usage: %s erlnode" % argv[0] - sys.exit(1) - elif optchar == "-c": - cookie = optarg - elif optchar == "-d": - doDebug = 1 - elif optchar == "-n": - ownNodeName = optarg - - top = Tk() - erl_eventhandler.SetEventHandlerStateTk(top) - - - if doDebug: - erl_common.DebugOnAll() - - print "Creating node..." - n = erl_node.ErlNode(ownNodeName, erl_opts.ErlNodeOpts(cookie=cookie)) - print "Publishing node..." - n.Publish() - print "Creating mbox..." - m = n.CreateMBox(__TestMBoxCallback) - print "Registering mbox as p..." - m.RegisterName("p") - - TkTest(top, n, m) - - print "Looping..." - evhand = erl_eventhandler.GetEventHandler() - evhand.Loop() - -try: - main(sys.argv) -except KeyboardInterrupt: - print "Interrupted. Exiting." - sys.exit(1) diff --git a/examples/test_remote_exec.py b/examples/test_remote_exec.py deleted file mode 100755 index b30ddeb..0000000 --- a/examples/test_remote_exec.py +++ /dev/null @@ -1,144 +0,0 @@ -#! /usr/bin/env python - -import sys -import types -import string -import socket -import getopt - - -from py_interface import erl_term -from py_interface import erl_node -from py_interface import erl_opts -from py_interface import erl_common -from py_interface import erl_eventhandler - -eh = None - - -def print_usage(): - print "Usage: %s [opts] remote-node mod fn arg ..." % sys.argv[0] - print "Opts:" - print "-? print usage" - print "-d enable debugging info" - print "-t timeout: exit after this many seconds" - print "-n set the python node's name" - print "-c set cookie" - -def _TestMBoxCallback(msg, *x, **kw): - print "Incoming msg=%s" % `msg` - -def _TestMBoxRPCResponse(msg): - global eh - print "RPC answer: %s" % `msg` - eh.StopLooping() - - -def __TestMBoxCallback(msg): - print "Incoming msg=%s" % `msg` - -def SendTheRPC(mbox, remoteNode, m, f, a): - print "Sending:" - print " remoteNode=%s" % `remoteNode` - print " m=%s" % `m` - print " f=%s" % `f` - print " a=%s" % `a` - mbox.SendRPC(remoteNode, m, f, a, _TestMBoxRPCResponse) - -def DoTimeout(): - global eh - print "Timeout!" - eh.StopLooping() - -def ExprRebuildAtoms(expr): - if type(expr) == types.StringType: - if len(expr) >= 2 and expr[0] == expr[-1] == "'": - atomText = expr[1:-1] - return erl_term.ErlAtom(atomText) - else: - return expr - elif type(expr) == types.ListType: - rebuiltList = [] - for elem in expr: - rebuiltElem = ExprRebuildAtoms(elem) - rebuiltList.append(rebuiltElem) - return rebuiltList - elif type(expr) == types.TupleType: - rebuiltList = [] - for elem in list(expr): - rebuiltElem = ExprRebuildAtoms(elem) - rebuiltList.append(rebuiltElem) - return tuple(rebuiltList) - else: - return expr - -def main(argv): - global eh - - try: - opts, args = getopt.getopt(argv[1:], "?dn:c:t:", ['help']) - except getopt.error, info: - print info - sys.exit(1) - - hostName = "localhost" - ownNodeName = "py_interface_test" - cookie = "cookie" - doDebug = 0 - timeout = 10 - - for (optchar, optarg) in opts: - if optchar == "-?" or optchar == "--help": - print_usage() - sys.exit(0) - elif optchar == "-c": - cookie = optarg - elif optchar == "-d": - doDebug = 1 - elif optchar == "-n": - ownNodeName = optarg - elif optchar == "-t": - timeout = eval(optarg) - - if doDebug: - erl_common.DebugOnAll() - - if len(args) < 3: - print_usage() - sys.exit(1) - - [remoteNode, module, function] = args[0:3] - fargs = args[3:] - - print "Creating node..." - n = erl_node.ErlNode(ownNodeName, erl_opts.ErlNodeOpts(cookie=cookie)) - print "Publishing node..." - n.Publish() - print "Creating mbox..." - m = n.CreateMBox(__TestMBoxCallback) - print "Registering mbox as p..." - m.RegisterName("p") - - evhand = erl_eventhandler.GetEventHandler() - eh = evhand - - evhand.AddTimerEvent(timeout, DoTimeout) - - - # Schedule to run the RPC after we've started looping - evhand.AddTimerEvent(0.001, - erl_common.Callback( - SendTheRPC, m, remoteNode, - module, function, - map(lambda x: ExprRebuildAtoms(eval(x)), - fargs))) - - print "Looping..." - evhand.Loop() - sys.exit(0) - -try: - main(sys.argv) -except KeyboardInterrupt: - print "Interrupted. Exiting." - sys.exit(1) diff --git a/howto-make-a-new-version b/howto-make-a-new-version deleted file mode 100755 index f28c884..0000000 --- a/howto-make-a-new-version +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/sh -xv -# 1. Edit -# 2. Edit the file vsn -# 3. Edit the file ChangeLog -# 4. Test: - autoconf && \ - ./configure && \ - make clean && \ - make && \ - ./setup.py build && \ - make dist && - ( export vsn=`cat vsn` && \ - /bin/rm -rf tt && \ - mkdir tt && cd tt && \ - tar xfvpz ../py_interface-$vsn.tgz && \ - cd py_interface-$vsn && \ - ./configure && \ - make && \ - ./setup.py build ) && \ - /bin/rm -rf tt && - echo "Success!" -# 5. Commit -# 6. Tag -# 7. Push diff --git a/install-sh b/install-sh deleted file mode 100755 index 89fc9b0..0000000 --- a/install-sh +++ /dev/null @@ -1,238 +0,0 @@ -#! /bin/sh -# -# install - install a program, script, or datafile -# This comes from X11R5. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. -# - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" -mkdirprog="${MKDIRPROG-mkdir}" - -tranformbasename="" -transform_arg="" -instcmd="$mvprog" -chmodcmd="$chmodprog 0755" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" -dir_arg="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -d) dir_arg=true - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - -t=*) transformarg=`echo $1 | sed 's/-t=//'` - shift - continue;; - - -b=*) transformbasename=`echo $1 | sed 's/-b=//'` - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - # this colon is to work around a 386BSD /bin/sh bug - : - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -else - true -fi - -if [ x"$dir_arg" != x ]; then - dst=$src - src="" - - if [ -d $dst ]; then - instcmd=: - else - instcmd=mkdir - fi -else - -# Waiting for this to be detected by the "$instcmd $src $dsttmp" command -# might cause directories to be created, which would be especially bad -# if $src (and thus $dsttmp) contains '*'. - - if [ -f $src -o -d $src ] - then - true - else - echo "install: $src does not exist" - exit 1 - fi - - if [ x"$dst" = x ] - then - echo "install: no destination specified" - exit 1 - else - true - fi - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - - if [ -d $dst ] - then - dst="$dst"/`basename $src` - else - true - fi -fi - -## this sed command emulates the dirname command -dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` - -# Make sure that the destination directory exists. -# this part is taken from Noah Friedman's mkinstalldirs script - -# Skip lots of stat calls in the usual case. -if [ ! -d "$dstdir" ]; then -defaultIFS=' -' -IFS="${IFS-${defaultIFS}}" - -oIFS="${IFS}" -# Some sh's can't handle IFS=/ for some reason. -IFS='%' -set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` -IFS="${oIFS}" - -pathcomp='' - -while [ $# -ne 0 ] ; do - pathcomp="${pathcomp}${1}" - shift - - if [ ! -d "${pathcomp}" ] ; - then - $mkdirprog "${pathcomp}" - else - true - fi - - pathcomp="${pathcomp}/" -done -fi - -if [ x"$dir_arg" != x ] -then - $doit $instcmd $dst && - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi -else - -# If we're going to rename the final executable, determine the name now. - - if [ x"$transformarg" = x ] - then - dstfile=`basename $dst` - else - dstfile=`basename $dst $transformbasename | - sed $transformarg`$transformbasename - fi - -# don't allow the sed command to completely eliminate the filename - - if [ x"$dstfile" = x ] - then - dstfile=`basename $dst` - else - true - fi - -# Make a temp file name in the proper directory. - - dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - - $doit $instcmd $src $dsttmp && - - trap "rm -f ${dsttmp}" 0 && - -# and set any options; do chmod last to preserve setuid bits - -# If any of these fail, we abort the whole thing. If we want to -# ignore errors from any of these, just make sure not to ignore -# errors from the above "$doit $instcmd $src $dsttmp" command. - - if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && - if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && - if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && - if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && - -# Now rename the file to the real destination. - - $doit $rmcmd -f $dstdir/$dstfile && - $doit $mvcmd $dsttmp $dstdir/$dstfile - -fi && - - -exit 0 diff --git a/mkinstalldirs b/mkinstalldirs deleted file mode 100755 index 0801ec2..0000000 --- a/mkinstalldirs +++ /dev/null @@ -1,32 +0,0 @@ -#! /bin/sh -# mkinstalldirs --- make directory hierarchy -# Author: Noah Friedman -# Created: 1993-05-16 -# Last modified: 1994-03-25 -# Public domain - -errstatus=0 - -for file in ${1+"$@"} ; do - set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` - shift - - pathcomp= - for d in ${1+"$@"} ; do - pathcomp="$pathcomp$d" - case "$pathcomp" in - -* ) pathcomp=./$pathcomp ;; - esac - - if test ! -d "$pathcomp"; then - echo "mkdir $pathcomp" 1>&2 - mkdir "$pathcomp" || errstatus=$? - fi - - pathcomp="$pathcomp/" - done -done - -exit $errstatus - -# mkinstalldirs ends here diff --git a/py_interface/__init__.py.src b/py_interface/__init__.py.src deleted file mode 100644 index f568a23..0000000 --- a/py_interface/__init__.py.src +++ /dev/null @@ -1,14 +0,0 @@ -"""This file lets the py_interface files function as a package.""" -__version__ = "@VSN@" -__author__ = "Tomas Abrahamsson" -__license__ = "GNU Library General Public License" -__all__ = [ - "erl_async_conn", - "erl_common", - "erl_epmd", - "erl_eventhandler", - "erl_node", - "erl_node_conn", - "erl_opts", - "erl_term" - ] diff --git a/py_interface/erl_async_conn.py b/py_interface/erl_async_conn.py deleted file mode 100644 index 0a9c16d..0000000 --- a/py_interface/erl_async_conn.py +++ /dev/null @@ -1,190 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_async_conn.py -- general async communication over tcp/ip - -import socket -try: - import SOCKET -except ImportError: - SOCKET = socket -import errno - -from py_interface import erl_common -from py_interface import erl_eventhandler - - -class ErlAsyncPeerConnection: - def __init__(self, openSocket=None): - self.evhandler = erl_eventhandler.GetEventHandler() - if openSocket == None: - self._Init() - else: - self._Init() - self._SetConnectionOpen(openSocket) - - - def Close(self): - if not self._isConnected: - return - self._SetConnectionClosed() - - - def Send(self, data): - self._SendOrQueue(data) - - - def GetConnection(self): - if not self._isConnected: - return None - else: - return self._connection - - - ## - ## Internal routines - ## - - def _Init(self): - self._isConnected = 0 - self._pendingOutput = "" - - def _SetConnectionClosed(self): - if self._isConnected: - self.evhandler.PopReadEvent(self._connection) - self._connection.close() - self._connection = None - self._isConnected = 0 - self._Init() - - def _SetConnectionOpen(self, sock): - if not self._isConnected: - self._connection = sock - self._isConnected = 1 - self.evhandler.PushReadEvent(self._connection, self._In) - - def _SendOrQueue(self, data): - numBytesToSend = len(data) - try: - numBytesSent = self._connection.send(data) - if numBytesSent < numBytesToSend: - remaining = data[numBytesSent:] - self._Queue(remaining) - except socket.error, (errNum, errText): - if errNum == errno.EAGAIN or errNum == errno.EWOULDBLOCK: - self._Queue(data) - else: - raise - - def _Queue(self, strToQueue): - if self._pendingOutput == "": - self.evhandler.PushWriteEvent(self._connection, self._QueuedWrite) - self._pendingOutput = self._pendingOutput + strToQueue - - def _QueuedWrite(self): - numBytesToSend = len(self._pendingOutput) - try: - numBytesSent = self._connection.send(self._pendingOutput) - if numBytesSent == numBytesToSend: - self._pendingOutput = "" - self.evhandler.PopWriteEvent(self._connection) - else: - self._pendingOutput = self._pendingOutput[numBytesSent:] - except socket.error, (errNum, errText): - if errNum == errno.EAGAIN or errNum == errno.EWOULDBLOCK: - # still not possible to send... - # wait a bit more - pass - - def _In(self): - print "erl_sync_conn: please override me!" - newData = self._connection.recv(10000) - - def ReadInt1(self, s): - return erl_common.ReadInt1(s) - - def ReadInt2(self, s): - return erl_common.ReadInt2(s) - - def ReadInt4(self, s): - return erl_common.ReadInt4(s) - - def PackInt1(self, i): - return erl_common.PackInt1(i) - - def PackInt2(self, i): - return erl_common.PackInt2(i) - - def PackInt4(self, i): - return erl_common.PackInt4(i) - - -class ErlAsyncClientConnection(ErlAsyncPeerConnection): - def __init__(self): - ErlAsyncPeerConnection.__init__(self) - - - def Connect(self, hostname, portNum): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.connect((hostname, portNum)) - s.setblocking(0) - self.hostname = hostname - self.portNum = portNum - self._SetConnectionOpen(s) - return 1 - except socket.error, errInfo: - print "socket error:", errInfo - self._SetConnectionClosed() - return 0 - - -class ErlAsyncServer(ErlAsyncPeerConnection): - def __init__(self): - ErlAsyncPeerConnection.__init__(self) - - def Start(self, portNum=0, iface=""): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - try: - s.setsockopt(SOCKET.SOL_SOCKET, SOCKET.SO_REUSEADDR, 1) - s.bind((iface, portNum)) - (ipNum, resultPortNum) = s.getsockname() - s.listen(5) - s.setblocking(0) - self.hostname = iface - self.portNum = resultPortNum - self._SetConnectionOpen(s) - return resultPortNum - except socket.error, errInfo: - print "socket error:", errInfo - return None - - def _In(self): - s = self.GetConnection() - (s2, (remoteHost, remotePort)) = s.accept() - self._NewConnection(s2, (remoteHost, remotePort)) - - def _NewConnection(self, sockConn, remoteAddr): - asyncConnection = ErlAsyncPeerConnection(s2) - pass diff --git a/py_interface/erl_common.py b/py_interface/erl_common.py deleted file mode 100644 index 48dfbaf..0000000 --- a/py_interface/erl_common.py +++ /dev/null @@ -1,419 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_common.py -- common utility functions - -import os -import string -import socket - -def ReadInt1(s): - """Convert first byte from a string to an unsigned 8-bit integer.""" - return ord(s[0]) - -def ReadInt2(s): - """Convert first two bytes from a string to an unsigned 16-bit integer.""" - return (ord(s[0]) << 8) + \ - (ord(s[1]) << 0) - -def ReadInt4(s): - """Convert first four bytes from a string to an unsigned 32-bit integer. - - Returns integer | long - - In Python on a 32-bit machine, integers are signed and within - the range -2^31 .. (2^31 - 1). If the 32-bit integer fits within this - range, an integer is returned, otherwise a long is returned.""" - l4 = (long(ord(s[0])) << 24) + \ - (ord(s[1]) << 16) + \ - (ord(s[2]) << 8) + \ - (ord(s[3]) << 0) - try: - i4 = int(l4) - return i4 - except OverflowError: - return l4 - - -def PackInt1(i): - """Converts an unsigned 8-bit integer/long into a string, 1 byte long.""" - return chr(i & 255) - -def PackInt2(i): - """Converts an unsigned 16-bit integer/long into a string, 2 byte long.""" - return chr((i >> 8) & 255) + \ - chr((i >> 0) & 255) - -def PackInt4(i): - """Converts an unsigned 32-bit integer/long into a string, 4 byte long.""" - return chr((i >> 24) & 255) + \ - chr((i >> 16) & 255) + \ - chr((i >> 8) & 255) + \ - chr((i >> 0) & 255) - - -def AlignNodeName(nodeName, useShortNodeNames=1): - """Make sure the node name is a valid node name. - - NODE-NAME = string - A node name, possibly containing an "@" - USE-SHORT-NODE-NAMES = bool - Whether to align using short node names - or not. If not, then long node names are - assumed. - - Returns: string - Throws: nothing - - The returned node name: - - 1. If the NODE-NAME contains an `@', then NODE-NAME is returned unchanged - 2. If the NODE-NAME does not contain an `@', then the returned node name - is constructed as NODE-NAME + "@" + host-name, where - host-name is either on short or long form, depending on - USE-SHORT-NODE-NAMES. - """ - if useShortNodeNames: - return AlignShortNodeName(nodeName) - else: - return AlignLongNodeName(nodeName) - -def AlignShortNodeName(nodeName): - """Align a node, use short hostname if needed. See doc for AlignNodeName""" - if "@" in nodeName: - return nodeName - fqdn = GetFullyQualifiedHostName() - shortHostName = string.split(fqdn, ".")[0] - return nodeName + "@" + shortHostName - -def AlignLongNodeName(nodeName): - """Align a node, use long hostname if needed. See doc for AlignNodeName""" - if "@" in nodeName: - return nodeName - fqdn = GetFullyQualifiedHostName() - return nodeName + "@" + fqdn - -def GetFullyQualifiedHostName(name=""): - """Get fully qualified domain name from name. - - An empty argument is interpreted as meaning the local host. - - First the hostname returned by gethostbyaddr() is checked, then - possibly existing aliases. In case no FQDN is available, hostname - is returned. - """ - try: - # Try the builtin version if it exists. - # It does in Python 2.0 - return socket.getfqdn(name) - except AttributeError, info: - # This fallback code is provided for Python 1.5.2 and earlier - # It is stolen with pride from Python 2.0 - name = string.strip(name) - if not name or name == '0.0.0.0': - name = socket.gethostname() - try: - hostname, aliases, ipaddrs = socket.gethostbyaddr(name) - except error: - pass - else: - aliases.insert(0, hostname) - for name in aliases: - if '.' in name: - break - else: - name = hostname - return name - -def getenv(envName): - """Read an environment variable. - ENV-NAME = string - The name of the environment variable - Returns: "" | string - The env-value, or "" if the env-name isn't defined - Throws: nothing - """ - if os.environ.has_key(envName): - return os.environ[envName] - else: - return "" - - - -def IndexSeq(seq): - """Given a sequence, return a list of tuples (i, elem[i]). -Example: IndexSeq(["a", "b", "c"]) ==> [(0, "a"), (1, "b"), (2, "c")].""" - return map(None, range(len(seq)), seq) - - -_logfilename = None -def SetLogFile(fileName): - """Setup a file name to log to - FILE-NAME = string - The name of a file to log to - Returns: void - - Sets up a log file. - """ - global _logfilename - -def Log(str): - """Log a string to the log file - STR = string - The string to log (without trailing new-line) - Returns: void - Throws: nothing - - Logs a string to the file set up by logfilename. - The file is opened only during the logging. It is kept closed between - calls to this function. - """ - global _logfilename - if _logfilename != None: - try: - f = open(_logfilename, "w") - f.write(str) - f.write("\n") - f.flush() - f.close() - except IOError, info: - # Silently ignore - pass - - -_modulesToDebug = [] -_debugAllModules = 0 -_debugFileName = None - -def DebugToFile(fileName): - """Setup a file name to print debugging messages to - FILE-NAME = string - The name of a file to log to - Returns: void - Throws: nothing - - Sets up a file to print debugging messages to. - """ - global _debugFileName - _debugFileName = fileName - -def DebugOnAll(): - """Turn on debugging for all modules - No arguments - Returns: void - Throws: nothing - - Turns on debugging flag for all modules - """ - global _modulesToDebug, _debugAllModules - _debugAllModules = 1 - - -def DebugOn(moduleList): - """Turn on debugging for selected modules - MODULE-LIST = list(string) - - Returns: void - Throws: nothing - - Turns on debugging flag for selected modules - """ - global _modulesToDebug, _debugAllModules - _debugAllModules = 0 - _modulesToDebug = moduleList - -def Debug(module, txt): - """Print a debug text - MODULE = string - Name of the module that is printing the debug text - TXT = string - The text to print as debugging message - Returns: void - Throws: nothing - - Prints a debugging text. The text is printed if debugging for the - module is turned on, see DebugOnAll and DebugOn. - - The debug message is printed to stdout, except if debugging has - been set to go to a file, see DebugToFile. - """ - global _modulesToDebug, _debugAllModules - if _debugAllModules or module in _modulesToDebug: - _DebugEmitText("%s: %s" % (module, txt)) - -def DebugHex(module, txt, msg): - """Print a debug text and a hexdump of a message - MODULE = string - Name of the module that is printing the debug text - TXT = string - The text to print as debugging message - MSG = string - The message to hexdump - Returns: void - Throws: nothing - - Prints a debugging text. The text is printed if debugging for the - module is turned on, see DebugOnAll and DebugOn. - - The debug message is printed to stdout, except if debugging has - been set to go to a file, see DebugToFile. - """ - hexMsg = _HexDumpFormat(msg) - _DebugEmitText("%s: %s\n%s" % (module, txt, hexMsg)) - -def _DebugEmitText(txt): - global _debugFileName - if _debugFileName == None: - print txt - else: - try: - f = open(_debugFileName, "w") - f.write(txt) - f.flush() - f.close() - except IOError, info: - # Silently ignore - pass - - -def _HexDumpFormat(string): - def dump_chars(addr, s): - hexString = "" - ascString = "" - for i, c in map(None, range(len(s)), s): - if i > 0: - hexString = hexString + " " - hexString = hexString + ("%02x" % ord(c)) - if (c < " ") or ((ord(c) >= 128) and (ord(c) < 160)): - ascString = ascString + "." - else: - ascString = ascString + c - numFill = 16 - len(s) - hexString = hexString + " " * numFill - addrString = "%04x" % addr - return addrString + ": " + hexString + " " + ascString + "\n" - - remaining_chars = string; - addr = 0 - result = "" - while len(remaining_chars) > 0: - if len(remaining_chars) < 16: - result = result + dump_chars(addr, remaining_chars) - remaining_chars = "" - else: - result = result + dump_chars(addr, remaining_chars[:16]) - remaining_chars = remaining_chars[16:] - addr = addr + 16 - return result - -class Callback: - """This class provides a callback object. - Here's how to use it: - - def MyFunction1(...): - pass - def MyFunction2(..., arg1, arg2, arg3): - pass - def MyFunction3(..., arg1, arg2, arg3, kw1=None, kw2=None): - pass - - cb1 = Callback(MyFunction1) - cb2 = Callback(MyFunction2, 1, 2, 3) - cb3 = Callback(MyFunction3, 1, 2, 3, kw1=4, kw2=5) - - RegisterCallback(cb1) - RegisterCallback(cb2) - RegisterCallback(cb3) - - Any arguments that the invoker uses are tacked on before the first - callback-argument, hence the `...' in the function definitions above. - This example might clarify: - - def MyFunction(s1, s2, arg1, arg2): - print "s1=%s, s2=%s, arg1=%s, arg2=%s" % (`s1`, `s2`, `arg1`, `arg2`) - mycb = Callback(MyFunction, 3, 4) - RegisterCallback(mycb) - ... - #someone calls: - cb(1, 2) - # This will cause MyFunction to be invoked as MyFuntion(1,2,3,4), - # the arguments 1 and 2 tacked on to the front, - # coming from the callback invoker, and arguments 3 and 4 - # come from the creation of the callback object - # Thus, the following will be printed: - s1=1, s2=2, arg1=3, arg2=4 - """ - def __init__(self, callback, *optArgs, **namedArgs): - self.callback = callback - self.optArgs = optArgs - self.namedArgs = namedArgs - - def __call__(self, *extraArgs): - try: - return apply(self.callback, extraArgs+self.optArgs, self.namedArgs) - except KeyboardInterrupt: - raise - except: - print "Error in VCallback %s" % self.__repr__() - raise - - def __repr__(self): - return "" % `self.callback` - -class VCallback: - """This class provides a callback object. - It is similar to the Callback (see the doc for this class), - but is intended to be used in a situation where you have - already collected the optional args and the keyword args. - - Here's an example of when to use this class instead of the Callback class: - - def DefineRegisterCallback(cbfn, *optArgs, *namedArgs): - cb = VCallback(cbfn, optArgs namedArgs) - RegisterCallback(cb) - - ... - - DefineRegisterCallback(MyFunction, 1, 2) - """ - def __init__(self, callback, optArgs, namedArgs): - self.callback = callback - self.optArgs = optArgs - self.namedArgs = namedArgs - - def __call__(self, *extraArgs): - try: - return apply(self.callback, extraArgs+self.optArgs, self.namedArgs) - except KeyboardInterrupt: - raise - except: - print "Error in VCallback %s" % self.__repr__() - print " extraArgs=%s" % `extraArgs` - print " self.optArgs=%s" % `self.optArgs` - print " self.namedArgs=%s" % `self.namedArgs` - raise - - def __repr__(self): - return "" % `self.callback` - diff --git a/py_interface/erl_epmd.py b/py_interface/erl_epmd.py deleted file mode 100644 index bb08140..0000000 --- a/py_interface/erl_epmd.py +++ /dev/null @@ -1,607 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_epmd.py -- handle the communication with the epmd -### (the Erlang portmapper daemon) - -import sys -import types -import string -import socket -import getopt - -from py_interface import erl_common -from py_interface import erl_async_conn -from py_interface import erl_eventhandler - -NODETYPE_NORMAL = 77 -NODETYPE_HIDDEN = 72 - -M = "erl_epmd" - -class ErlEpmd: - """This class provides a connection to the Erlang Portmapper Daemon, EPMD. - """ - def __init__(self, hostName="localhost", portNum=4369): - """Constructor. - - HOST-NAME = string - Default is "localhost" - PORT-NUM = integer - Default is 4369 - - Creates an instance for communicating with the EPMD on HOST-NAME - on PORT-NUM. - Use the Connect method to establish the actual connection to the EPMD. - """ - self._hostName = hostName - self._portNum = portNum - self.connection = None - - def SetOwnPortNum(self, ownPortNum): - """Specify the port number for the node - - OWN-PORT-NUM = integer - - Specify the port number for the socket that serves incoming - connections to the node. This is the portnumber to be published - to the EPMD. Other nodes looks up the nodes portnumber in the - EPMD, then establishes connections to that port. - """ - self._ownPortNum = ownPortNum - - def SetOwnNodeName(self, nodeName): - """Specify the node name for the node - - NODE-NAME = string - Must be on the form alivename@hostname - - Sets the nodes name. This is the node name that is published in - the EPMD. - """ - ## XXX Ought to change the scheme: get the host from the node-name - ## instead of from an argument to the constructor? - self._ownNodeName = nodeName - - def Connect(self, connectedCb, connectFailedCb): - """Connect to the EPMD and issue an Alive2 request. - - CONNECTED-CB = - CREATION = integer - CONNECT-FAILED-CB = - RESULT = integer - - Connects to the EPMD specified in the constructor, then publishes - the own node name and port by issuing an Alive2 request. - - The SetOwnPortNum and SetOwnNodeName methods must have been called - prior to calling this method. - """ - self._connectedCb = connectedCb - self._connectFailedCb = connectFailedCb - self._epmdConn = ErlEPMDStdConnection() - if not self._epmdConn.Connect(self._hostName, self._portNum): - raise "Connection to EPMD failed" - self.Alive2Req(self._ownPortNum, NODETYPE_HIDDEN, - (5, 5), self._ownNodeName, "", self._Alive2RespCb) - - def Close(self): - """Close the connection to the EPMD.""" - self.AliveCloseReq(self._AliveCloseSink) - - ## Requests - ## - - def AliveReq(self, portNum, nodeName, cb): - """Issue an Alive request. - PORT-NUM = integer - The port number of the socket that serves incoming - connections to the node. - NODE-NAME = string - the name of the node (on the form alive@host) - - This request has no callback. - """ - self._epmdConn.AliveReq(portNum, nodeName, cb) - - def Alive2Req(self, portNum, nodeType, distrVSNRange, nodeName, extra, cb): - """Issue an Alive2 request. - PORT-NUM = integer - The port number of the socket that serves incoming - connections to the node. - NODE-TYPE = integer - DISTR-VSN-RANGE = tuple(LO, HI) - LO = HI = integer - NODE-NAME = string - the name of the node (on the form alive@host) - EXTRA = string - CB = - CREATION = integer - - Calls the callback CB when the answer is available. - See the file distribution_handshake.txt in the erlang distribution - for more info on the NODE-TYPE, DISTR-VSN-RANGE and EXTRA arguments. - """ - self._epmdConn.Alive2Req(portNum, nodeType, distrVSNRange, - nodeName, extra, cb) - - def AliveCloseReq(self, cb): - """Issue an AliveClose request. - CB = - - This effectively closes the socket connection to the EPMD. - """ - self._epmdConn.AliveCloseReq(cb) - - def PortPleaseReq(self, nodeName, callback): - """Issue a PortPlease request. - NODE-NAME = string - CALLBACK = - PORT-NUMBER = integer - Calls the CALLBACK function with argument PORT-NUMBER when - the answer is available. - """ - e = ErlEPMDOneShotConnection(self._hostName, self._portNum) - e.PortPleaseReq(nodeName, callback) - - def PortPlease2Req(self, nodeName, callback): - """Issue a PortPlease2 request. - NODE-NAME = string - CALLBACK = - RESULT = 1 | 0 - NODE-TYPE = integer - PROTOCOL = integer - DISTR-VSN-RANGE = tuple(LO, HI) - LO = HI = integer - RNODE-NAME = string - EXTRA = string - Calls the CALLBACK function when the answer is available from the EPMD. - If the RESULT is 0, then the values of the rest of the arguments - are undefined. If the result is 1, then the rest of the arguments - have the values as reported from the EPMD. - - Calls the CALLBACK function with argument PORT-NUMBER when - the answer is available. - """ - e = ErlEPMDOneShotConnection(self._hostName, self._portNum) - e.PortPlease2Req(nodeName, callback) - - def NamesReq(self, callback): - """Issue a Names request - CALLBACK = - PORT-NUMBER = integer - Calls the CALLBACK function with argument PORT-NUMBER when - the answer is available. - """ - msg = self.PackInt1(self._PORT_PLEASE_REQ) + nodeName - unpackcb = erl_common.Callback(self._UnpackPortPleaseResp, callback) - self._SendOneShotReq(msg, unpackcb) - - def PortPlease2Req(self, nodeName, callback): - """Issue a PortPlease2 request. - NODE-NAME = string - CALLBACK = - RESULT = 1 | 0 - NODE-TYPE = integer - PROTOCOL = integer - DISTR-VSN-RANGE = tuple(LO, HI) - LO = HI = integer - RNODE-NAME = string - EXTRA = string - Calls the CALLBACK function when the answer is available from the EPMD. - If the RESULT is 0, then the values of the rest of the arguments - are undefined. If the result is 1, then the rest of the arguments - have the values as reported from the EPMD. - - Calls the CALLBACK function with argument PORT-NUMBER when - the answer is available. - """ - msg = self.PackInt1(self._PORT_PLEASE2_REQ) + nodeName - unpackcb = erl_common.Callback(self._UnpackPortPlease2Resp, callback) - self._SendOneShotReq(msg, unpackcb) - - def NamesReq(self, callback): - """Issue a Names request - CALLBACK = - CREATION = integer - - Calls the callback CB when the answer is available. - See the file distribution_handshake.txt in the erlang distribution - for more info on the NODE-TYPE, DISTR-VSN-RANGE and EXTRA arguments. - """ - aliveName = string.split(nodeName, "@")[0] - msg = (self.PackInt1(self._ALIVE2_REQ) + - self.PackInt2(portNum) + - self.PackInt1(nodeType) + - self.PackInt1(0) + # protocol: 0 = tcp/ip-v4 - self.PackInt2(distrVSNRange[0]) + - self.PackInt2(distrVSNRange[1]) + - self.PackInt2(len(aliveName)) + aliveName + - self.PackInt2(len(extra)) + extra) - self._SendReq(msg, cb) - - - def AliveReq(self, portNum, nodeName): - """Issue an Alive request. - PORT-NUM = integer - The port number of the socket that serves incoming - connections to the node. - NODE-NAME = string - the name of the node (on the form alive@host) - - This request has no callback. - """ - msg = (self.PackInt1(self._ALIVE_REQ) + - self.PackInt2(portNum) + - nodeName) - self._SendReq(msg, cb) - - def AliveCloseReq(self, cb): - """Issue an AliveClose request. - CB = - - This effectively closes the socket connection to the EPMD. - """ - self.Close() - cb() - - - ## - ## Internal routines - ## - - ## - ## Sending - ## - - def _SendReq(self, req, cb): - if not self._isConnected: - raise "not connected to epmd" - self._NewCurrReq(ord(req[0]), cb) - msg = self.PackInt2(len(req)) + req - self.Send(msg) - - - def _NewCurrReq(self, reqId, cb): - self._currentRequests.append((reqId, cb)) - - - def _GetCurrReqId(self): - if len(self._currentRequests) == 0: - return None - else: - return self._currentRequests[0][0] - - def _GetCurrReqCb(self): - if len(self._currentRequests) == 0: - return None - else: - return self._currentRequests[0][1] - - - def _CurrReqDone(self): - self._currentRequests = self._currentRequests[1:] - - - ## - ## Handling incoming data - ## - - def _In(self): - is_closed = 0 - data = self._connection.recv(100000) - if len(data) == 0: - # closed connection - is_closed = 1 - - newInput = self._pendingInput + data - - # split into chunks separated by newline sequence - # call the callback for each of these chunks - - newPendingInput = self._HandleMsgs(newInput) - self._pendingInput = newPendingInput - - if is_closed: - self._OtherEndClosedConnection() - - - def _OtherEndClosedConnection(self): - if self._GetCurrReqId() == self._ALIVE_REQ: # alive_req - self.AliveNotOkResp() - self._CurrReqDone() - else: - self.ConnectionClosed() - ## close our end - self.Close() - - - def _HandleMsgs(self, input): - toBeUnpacked = input - while 1: - (parsedOk, remainingInput) = self._HandleMsg(toBeUnpacked) - if not parsedOk: - return remainingInput - else: - self._CurrReqDone() - toBeUnpacked = remainingInput - - - def _HandleMsg(self, data): - dataLen = len(data) - if dataLen < 3: - return (0, data) - - data0 = ord(data[0]) - if data0 == self._ALIVE_OK_RESP and \ - self._GetCurrReqId() == self._ALIVE_REQ: - if dataLen < 3: - return (0, data) - creation = self.ReadInt2(data[1:3]) - cb = self._GetCurrReqCb() - cb(creation) - self._CurrReqDone() - return (1, data[3:]) - elif data0 == self._ALIVE2_RESP and \ - self._GetCurrReqId() == self._ALIVE2_REQ: - if dataLen < 4: - return (0, data) - result = self.ReadInt1(data[1]) - creation = self.ReadInt2(data[2:4]) - cb = self._GetCurrReqCb() - cb(result, creation) - self._CurrReqDone() - return (1, data[4:]) - - currReqTxt = "current request is %s" % `self._GetCurrReqId()` - erl_common.DebugHex(M, "unexpected msg, trown away, "+currReqTxt, data) - return (0, "") diff --git a/py_interface/erl_eventhandler.py b/py_interface/erl_eventhandler.py deleted file mode 100644 index b6fa26a..0000000 --- a/py_interface/erl_eventhandler.py +++ /dev/null @@ -1,492 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_eventhandler.py -- A general event handler. -### It provides the possibility to register -### callbacks to be called at certain events: -### * when there is data to read on a file descriptor -### * when it's posssible to write to a file descriptor -### * at file descriptor exceptions -### * after timeout - - - -import os -import sys -import string -import select -import time -try: - from Tkinter import tkinter - import Tkinter -except: pass - -from py_interface import erl_common - -_evhandler = None - -### --------------------------------------------------- -### API -### - -def GetEventHandler(): - """Retrieve the eventhandler. - No arguments. - Returns: - Throws: nothing - """ - global _evhandler - - if _evhandler == None: - ## This is the first call to the event handler. It has not been - ## created yet, so create it first. - _evhandler = _EventHandler() - return _evhandler - -def SetEventHandlerStateTk(top): - """Sets up the event handler to use Tkinter's mainloop. - - TOP = - - Returns: void - Throws: nothing - - Call this when you want to use the event handler in a program that uses - Tkinter. The argument is expected to be the object that's returned by - a call to Tkinter.Tk(). - """ - evhandler = GetEventHandler() - evhandler._SetStateTk(top) - -def SetEventHandlerStateStandalone(): - """Sets up the event handler to use its own mainloop. This is the default. - - No arguments - Returns: void - Throws: nothing - """ - evhandler = GetEventHandler() - evhandler._SetStateStandAlone() - -### -### End of API -### --------------------------------------------------- - -class EVCallback: - """This class is intended to be used by the _EventHandler class. - It differs from erl_common.VCallback in that it does not - tack on any extra arguments to the front. This is because tkinter - sends some extra arguments to the callback, so the arguments to - callbacks would have been depended on whether the event handler - is in tkinter-state or not. - """ - def __init__(self, callback, optArgs, namedArgs): - self.callback = callback - self.optArgs = optArgs - self.namedArgs = namedArgs - - def __call__(self, *extraArgs): - try: - return apply(self.callback, self.optArgs, self.namedArgs) - except KeyboardInterrupt: - raise - except: - print "Error in EVCallback %s" % self.__repr__() - raise - - def __repr__(self): - return "" % `self.callback` - -_tk = None -def _GetTk(): - global _tk - if _tk == None: - _tk = Tkinter.Frame().tk - return _tk - - -_nextTimerId = 0 -def GetNewTimerId(): - global _nextTimerId - - idToReturn = _nextTimerId - _nextTimerId = _nextTimerId + 1 - return idToReturn - -class _TimerEvent: - def __init__(self, timeLeft, cb): - self.addedWhen = time.time() - self.id = GetNewTimerId() - self.timeOutTime = self.addedWhen + timeLeft - self.cb = cb - - def __cmp__(self, other): - if self.timeOutTime == other.timeOutTime: - return 0 - elif self.timeOutTime < other.timeOutTime: - return -1 - else: - return 1 - -class _EventHandler: - STATE_STANDALONE = 1 - STATE_TK = 2 - - READ = 1 - WRITE = 2 - EXCEPT = 4 - - def __init__(self): - # mappings of connection --> callback - self.readEvents = {} - self.writeEvents = {} - self.exceptEvents = {} - - # A sorted list of timers: the timer with least time to run is first - self.timerEvents = [] - - # State: STATE_STANDALONE -- Tk is not involved - # STATE_TK -- use the eventhandler in Tkinter - self.state = self.STATE_STANDALONE - self.tkTopLevel = None - - def _SetStateTk(self, topLevel): - """State that we are using eventhandler in Tkinter. -Note: When using the Tkinter eventhandler, you cannot delete timer-events.""" - self.state = self.STATE_TK - self.tkTopLevel = topLevel - - def SetStateStandAlone(self): - """State that we are implementing our own eventhandler.""" - self.state = self.STATE_STANDALONE - - - def PushReadEvent(self, connection, cbfunction, *optArgs, **namedArgs): - """Register a callback to be called when there's data to read - on a connection. Or really, push the the callback onto the - stack of read-callbacks for the connection. Only the first callback - on the stack is called. - - CONNECTION = - CB-FUNCTION = - OPT-ARG ... = - NAMED-ARG ... = - - Returns: void - Throws: nothing - """ - cb = EVCallback(cbfunction, optArgs, namedArgs) - if self.readEvents.has_key(connection): - handlers = self.readEvents[connection] - else: - handlers = [] - newHandlers = self._PushHandler(cb, handlers) - self.readEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPushFileHandler(self.READ, connection) - - - def PopReadEvent(self, connection): - """Unregister a read callback for a connection. - Or really, pop it from the stack of callbacks. - - CONNECTION = - - Returns: void - Throws: nothing - """ - handlers = self.readEvents[connection] - newHandlers = self._PopHandler(handlers) - if len(newHandlers) == 0: - del self.readEvents[connection] - else: - self.readEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPopFileHandler(self.READ, connection) - - - def PushWriteEvent(self, connection, cbfunction, *optArgs, **namedArgs): - """Register a callback to be called when there's data to write - to a connection. Or really, push the the callback onto the - stack of write-callbacks for the connection. Only the first callback - on the stack is called. - - CONNECTION = - CB-FUNCTION = - OPT-ARG ... = - NAMED-ARG ... = - - Returns: void - Throws: nothing - """ - cb = EVCallback(cbfunction, optArgs, namedArgs) - if self.writeEvents.has_key(connection): - handlers = self.writeEvents[connection] - else: - handlers = [] - newHandlers = self._PushHandler(cb, handlers) - self.writeEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPushFileHandler(self.WRITE, connection) - - def PopWriteEvent(self, connection): - """Unregister a write callback for a connection. - Or really, pop it from the stack of callbacks. - - CONNECTION = - - Returns: void - Throws: nothing - """ - handlers = self.writeEvents[connection] - newHandlers = self._PopHandler(handlers) - if len(newHandlers) == 0: - del self.writeEvents[connection] - else: - self.writeEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPopFileHandler(self.WRITE, connection) - - - def PushExceptEvent(self, connection, cbfunction, *optArgs, **namedArgs): - """Register a callback to be called when there's an exception - on a connection. Or really, push the the callback onto the - stack of exception-callbacks for the connection. - Only the first callback on the stack is called. - - CONNECTION = - CB-FUNCTION = - OPT-ARG ... = - NAMED-ARG ... = - - Returns: void - Throws: nothing - """ - cb = EVCallback(cbfunction, optArgs, namedArgs) - if self.exceptEvents.has_key(connection): - handlers = self.exceptEvents[connection] - else: - handlers = [] - newHandlers = self._PushHandler(cb, handlers) - self.exceptEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPushFileHandler(self.EXCEPT, connection) - - def PopExceptEvent(self, connection): - """Unregister an exception callback for a connection. - Or really, pop it from the stack of callbacks. - - CONNECTION = - - Returns: void - Throws: nothing - """ - handlers = self.exceptEvents[connection] - newHandlers = self._PopHandler(handlers) - if len(newHandlers) == 0: - del self.exceptEvents[connection] - else: - self.exceptEvents[connection] = newHandlers - if self.state == self.STATE_TK: - self._TkPopFileHandler(self.EXCEPT, connection) - - - def AddTimerEvent(self, timeLeft, cbfunction, *optArgs, **namedArgs): - """Register a callback to be called after a certain amount of time. - - TIME-LEFT = integer | float - Timeout (in seconds) for the timer - CB-FUNCTION = - OPT-ARG ... = - NAMED-ARG ... = - - Returns: timer-id - Throws: nothing - """ - cb = EVCallback(cbfunction, optArgs, namedArgs) - if self.state == self.STATE_STANDALONE: - newTimerEvent = _TimerEvent(timeLeft, cb) - self.timerEvents.append(newTimerEvent) - self.timerEvents.sort() - return newTimerEvent.id - elif self.state == self.STATE_TK: - return _GetTk().createtimerhandler(int(round(timeLeft * 1000)), cb) - - def DelTimerEvent(self, id): - """Unregister a timer callback. - - TIMER-ID = timer-id - - Returns: nothing - Throws: "Cannot delete timer events when using tk" - - Note that it is not possible to unregister timer events when using Tk. - """ - if self.state == self.STATE_TK: - raise "Cannot delete timer events when using tk" - - indexForId = None - it = map(None, range(len(self.timerEvents)), self.timerEvents) - for i, ev in it: - if ev.id == id: - indexForId = i - break - if indexForId != None: - del self.timerEvents[indexForId] - - def Loop(self): - """Start the event handler. - - No arguments: - Returns: void - Throws: nothing - """ - if self.state == self.STATE_TK: - self.__LoopTk() - elif self.state == self.STATE_STANDALONE: - self.__LoopStandalone() - - - def __LoopTk(self): - self.tkTopLevel.mainloop() - - def __LoopStandalone(self): - self.continueLooping = 1 - while self.continueLooping: - rList = self.readEvents.keys() - wList = self.writeEvents.keys() - eList = self.exceptEvents.keys() - - timeout = None - if len(self.timerEvents) > 0: - firstTimerEv = self.timerEvents[0] - now = time.time() - timeout = firstTimerEv.timeOutTime - now - - if timeout == None: - # No timer to wait for - try: - reads, writes, excepts = select.select(rList, wList, eList) - except select.error, info: - (errno, errText) = info - if errno == 4: - # 'Interrupted system call' - # ignore this one. - # loop again in the while loop - continue - else: - # Other error: serious. Raise again. - raise - - elif timeout < 0: - # Signal timeout - (reads, writes, excepts) = ([], [], []) - else: - # Select and wait for timer - try: - reads, writes, excepts = select.select(rList, wList, eList, - timeout) - except select.error, info: - (errno, errText) = info - if errno == 4: - # 'Interrupted system call' - # ignore this one. - # loop again in the while loop - continue - else: - # Other error: serious. Raise again. - raise - - # Check for handles that are clear for reading - for readable in reads: - cb = self.readEvents[readable][0] - cb() - - # Check for handles that are clear for writing - for writable in writes: - cb = self.writeEvents[writable][0] - cb() - - # Check for handles that are in exception situation - for exceptable in excepts: - cb = self.exceptEvents[exceptable][0] - cb() - - # Check for timers that have timed out - while 1: - expiredTimers = filter(lambda ev, now=time.time(): - ev.timeOutTime <= now, - self.timerEvents) - if len(expiredTimers) == 0: - break # skip the while loop - - for expiredTimer in expiredTimers: - expiredTimer.cb() - self.DelTimerEvent(expiredTimer.id) - - - def StopLooping(self): - """Start the event handler. - - No arguments: - Returns: void - Throws: nothing - - This can use in e.g. callbacks to stop the event handler loop.""" - self.continueLooping = 0 - - def _PushHandler(self, cb, handlers): - return [cb] + handlers - - def _PopHandler(self, handlers): - return handlers[1:] - - def _TkPushFileHandler(self, eventType, connection): - fileNum = connection.fileno() - if eventType == self.READ: - cb = self.readEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.READABLE, cb) - elif eventType == self.WRITE: - cb = self.writeEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.WRITABLE, cb) - elif eventType == self.EXCEPT: - cb = self.exceptEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.EXCEPTION,cb) - - def _TkPopFileHandler(self, eventType, connection): - fileNum = connection.fileno() - ## In tkinter, all handlers (readable as well as writable/exception) - ## are deleted when we delete a handler. - ## The net result is that the code is all the same no matter - ## what type of handler we delete. - _GetTk().deletefilehandler(fileNum) - if self.readEvents.has_key(connection): - cb = self.readEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.READABLE, cb) - if self.writeEvents.has_key(connection): - cb = self.writeEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.WRITABLE, cb) - if self.exceptEvents.has_key(connection): - cb = self.exceptEvents[connection][0] - _GetTk().createfilehandler(fileNum, tkinter.EXCEPTION,cb) diff --git a/py_interface/erl_node.py b/py_interface/erl_node.py deleted file mode 100644 index 208126b..0000000 --- a/py_interface/erl_node.py +++ /dev/null @@ -1,899 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_node.py -- the node - -import sys -import types -import string - - -from py_interface import erl_epmd -from py_interface import erl_term -from py_interface import erl_opts -from py_interface import erl_common -from py_interface import erl_node_conn -from py_interface import erl_eventhandler - - - -M = "erl_node" - -py_interface_version = "0.9" - -_pidCount = 1 -_serial = 0 - -class ErlMBox: - """This class provides an mbox, which is equivalent to an - erlang-process. It is intenteded to be used in a single-threaded - application. You must provide a callback routine for incoming - messages.""" - - def __init__(self, node, pid, msgCallback): - """The recommended way to create mboxes is through the method - CreateMBox in the ErlNode class. - - NODE = - The node to which this mbox belongs. - PID = - The pid for this mbox - MSG-CALLBACK = - A callback to call for incoming messages - to this mbox. The callback should take one - argument: the message. Its return value is - ignored. - """ - self._node = node - if msgCallback == None: - msgCallback = self._Sink - self._msgCallback = msgCallback - self._pid = pid - self._pendingRPCs = {} - - def Self(self): - """Return the pid for this mbox. - - Returns: - Throws: nothing - """ - return self._pid - - def Send(self, dest, msg): - """Send, to DEST, the message MSG. - - DEST = | string | | - tuple(PROC-NAME, NODE) - PROC-NAME = NODE = string | - The destination to which the message is to be sent. - This can is either a pid for an mbox (on the same node or on a - different node), or a registered name (as string or atom) on - the same node, or a tuple specifying a node and a registered - name on that node. - - MSG = - The message to be sent. - - Returns: void - Throws: <> - - Send a message. There is no result indicating whether the delivery - of the message was successful or not. If the DEST is located on - another node, a connection to that node is automatically set up - and maintained, unless already connected. - - This method returns immediately. Any necessarry queuing, - possibly due to network traffic congestion, is handled - automatically by the node. - """ - self._node.SendMsgFromMBox(self, dest, msg) - - def RegisterName(self, name): - """Register a NAME for this mbox. - - NAME = string | - The name to register this mbox as. - - Returns: void - Throws: <> - - Only on name can be registered for each mbox. - """ - self._node.RegisterNameForMBox(self, name) - - def UnregisterName(self): - """Unregister the name that was registered for this mbox. - Returns: void - Throws: <> - """ - self._node.UnregisterNameForMBox(self) - - def Link(self, otherEnd): - """Link this mbox to another pid/mbox. - Currently, this is not implemented.""" - pass - - def Unlink(self, otherEnd): - """Unlink another pid/mbox. - Currently, this is not implemented.""" - pass - - def SendRPC(self, remoteNode, mod, fun, args, cb): - """Send an rpc to REMOTE-NODE, MOD, FUN, ARGS. Call CB for the answer. - - REMOTE-NODE = string | - The node to send the call to - MOD = string | - The module - FUN = string | - The name of the function to call - ARGS = list() - The argument list - CB = - REMOTE-NODE = string - RESULT = - A callback function to be called when the answer - to the rpc callback receives. The callback is called - with one arg: the result. Its return value is ignored. - If the remote node goes down during execution, the - callback is called with this value: - tuple(, - tuple(, - )>)) - - Returns: void - Throws: <> - - Send an request to execute a function in a module on a remote node. - As for the Send method, this method returns immediately. - """ - rexMBox = self._node.WhereisMBox("rex") - rexMBox.SendRPC(remoteNode, mod, fun, args, cb) - - ## - ## Routines to be called from the node only - ## - def Msg(self, sourceNodeName, msg): - """This routine is intended to be called only from mbox's node. - - SOURCE-NODE-NAME = string - MSG = - - Returns: void - Throws: nothing - - An incoming message - """ - self._msgCallback(msg) - - def _Sink(self, *a, **kw): - """Message sink.""" - pass - - -class _ErlRexMBox(ErlMBox): - """This class implements what's needed for the rpc (remote procedure call) - functionality. It is an mbox that registers itself as "rex". - """ - - def __init__(self, node, pid): - ErlMBox.__init__(self, node, pid, None) - self._nodeDownSubscriptions = {} - - def Start(self): - self.RegisterName("rex") - - - def SendRPC(self, remoteNode, mod, fun, args, cb): - """Send an rpc to REMOTE-NODE, MOD, FUN, ARGS. Call CB for the answer. - - REMOTE-NODE = string | - The node to send the call to - MOD = string | - The module - FUN = string | - The name of the function to call - ARGS = list() - The argument list - CB = - REMOTE-NODE = string - RESULT = - A callback function to be called when the answer - to the rpc callback receives. The callback is called - with one arg: the result. Its return value is ignored. - If the remote node goes down during execution, the - callback is called with this value: - tuple(, - tuple(, - )>)) - - Returns: void - Throws: <> - - Send an request to execute a function in a module on a remote node. - As for the Send method, this method returns immediately. - """ - if type(mod) == types.StringType: - mod = erl_term.ErlAtom(mod) - if type(fun) == types.StringType: - fun = erl_term.ErlAtom(fun) - - # Handle queue of pending callbacks for the remote node - if type(remoteNode) == types.StringType: - remoteNodeName = remoteNode - elif erl_term.IsErlAtom(remoteNode): - remoteNodeName = remoteNode.atomText - if self._pendingRPCs.has_key(remoteNodeName): - self._pendingRPCs[remoteNodeName].append(cb) - else: - self._pendingRPCs[remoteNodeName] = [cb] - - # Register a nodedown-callback for this node, so - # we can call any rpc callbacks in case the node goes down - if not self._nodeDownSubscriptions.has_key(remoteNodeName): - id = self._node.NodeDownSubscribe(self._NodeDown) - self._nodeDownSubscriptions[remoteNodeName] = id - - # Now send the rpc-message - self.Send(("rex", remoteNode), - (self.Self(), - (erl_term.ErlAtom("call"), - mod, fun, args, erl_term.ErlAtom("user")))) - - - ## - ## Routines to be called from the node only - ## - def Msg(self, sourceNodeName, msg): - """This routine is intended to be called only from mbox's node. - - SOURCE-NODE-NAME = string - MSG = - - Returns: void - Throws: nothing - - An incoming message - """ - if type(msg) == types.TupleType and \ - len(msg) == 2 and \ - erl_term.IsErlAtom(msg[0]) and \ - msg[0].atomText == "rex" and \ - len(self._pendingRPCs) > 0: - self._RPCAnswer(sourceNodeName, msg[1]) - else: - erl_common.Debug("REX: Unexpected msg: %s" % `msg`) - - def _RPCAnswer(self, sourceNodeName, answer): - # Does this assumption always hold: - # first answer is for first rpc-call? - # Maybe this holds for calls/answers for one single node. - # So the pendingRPCs is one queue per node. - if self._pendingRPCs.has_key(sourceNodeName): - pendingRPCs = self._pendingRPCs[sourceNodeName] - cb = pendingRPCs[0] - self._pendingRPCs[sourceNodeName] = pendingRPCs[1:] - cb(answer) - - def _NodeDown(self, nodeStatus, nodeName): - if self._pendingRPCs.has_key(nodeName): - callbacks = self._pendingRPCs[nodeName] - self._pendingRPCs[nodeName] = [] - for cb in callbacks: - cb((erl_term.ErlAtom("EXIT"), - (erl_term.ErlAtom("nodedown"), - erl_term.ErlAtom(nodeName)))) - - -class ErlNode: - """This class implements a node, which is equivaluent to an erlang node. - It is intended to be used in a single-threaded applucation. - - MBoxes, which corresponds to erlang processes, can be created for - communication. - """ - # Early operations - CTRLMSGOP_LINK = 1 - CTRLMSGOP_SEND = 2 - CTRLMSGOP_EXIT = 3 - CTRLMSGOP_UNLINK = 4 - CTRLMSGOP_NODE_LINK = 5 - CTRLMSGOP_REG_SEND = 6 - CTRLMSGOP_GROUP_LEADER = 7 - CTRLMSGOP_EXIT2 = 8 - # New operations in destrvsn = 1 (OTP R4) - CTRLMSGOP_SEND_TT = 12 - CTRLMSGOP_EXIT_TT = 13 - CTRLMSGOP_REG_SEND_TT = 16 - CTRLMSGOP_EXIT2_TT = 18 - # New operations in destrvsn = 4 (OTP R6) - CTRLMSGOP_MONITOR_P = 19 - CTRLMSGOP_DEMONITOR_P = 20 - CTRLMSGOP_MONITOR_P_EXIT = 21 - # end of operations - - def __init__(self, nodeName, opts=erl_opts.ErlNodeOpts()): - """Constructor. - - NODE-NAME = string - The name for this node. - - OPTS = - - Creates an ErlNode. The name of the node is determined by NODE-NAME - as described below. A node-name consists of two parts: an alive-name - and a host-name, separated by an `@'. The host-name can be short - (not including the domain) or long (including the domain). Short and - long node-names must not be mixed among the nodes in a system, see - the erlang documentation for further details. - 1. If the NODE-NAME contains an `@', then NODE-NAME is used - unchanged as name for the node. - 2. If the NODE-NAME does not contain an `@', then the node's name - is constructed as NODE-NAME + "@" + host-name, where - host-name is either on short or long form, depending on what is - specified in the OPTS. - """ - shortNodeNames = opts.GetShortNodeNames() - self._nodeName = erl_common.AlignNodeName(nodeName, shortNodeNames) - self._opts = opts - - self._creation = 0 - self._connections = {} - - self._epmd = erl_epmd.ErlEpmd() - self._ongoingPings = {} - - self._isServerPublished = 0 - self._pids = {} # mapping pid --> ErlMBox() - self._mboxes = {} # mapping ErlMBox --> pid - self._registeredNames = {} # mapping name --> pid - self._registeredPids = {} # mapping pid --> name - - self._nodeUpCb = [] # stores (id, callback) - self._nodeDownCb = [] # stores (id, callback) - self._cbId = 0 - - self._server = erl_node_conn.ErlNodeServerSocket(self._nodeName, - self._opts) - self._portNum = self._server.Start(self._NodeUp, self._NodeDown, - self._PassThroughMsg) - self._epmd.SetOwnPortNum(self._portNum) - self._epmd.SetOwnNodeName(self._nodeName) - self._CreateRex() - - def CreateMBox(self, msgCallback=None): - """Creates an mbox, which is equivalent to an erlang process. - - MSG-CALLBACK = - A callback function to call for incoming messages. - - Returns: - Throws: nothing - - This creates an mbox, which is equivalent to an erlang process. - Messages to the mbox are delivered as callbacks to the callback - function. - """ - mboxPid = self._CreatePid() - mbox = ErlMBox(self, mboxPid, msgCallback) - self._pids[mboxPid] = mbox - self._mboxes[mbox] = mboxPid - return mbox - - def Ping(self, remoteNodeName, pingCallback): - """Ping a remote node. - - REMOTE-NODE-NAME = string | - The node to ping - PING-CALLBACK = - A callback to call for deliverance of the - ping result. RESULT = "pong" | "pang". - - Returns: void - Throws: <> - - Try to ping a remote node. A connection to that node is established - unless already connected. Whether or not the remote node is up or - down is indicated as by the argument to the callback function: - "pong": the remote node is alive and there is a connection to it - "pang": the remote node is down. - """ - if not "@" in remoteNodeName: - raise "Bad node name for remote node \"%s\"" % remoteNodeName - if self._ongoingPings.has_key(remoteNodeName): - pingCallbacks = self._ongoingPings[remoteNodeName] - self._ongoingPings[remoteNodeName] = pingCallbacks + [pingCallback] - else: - self._ongoingPings[remoteNodeName] = [pingCallback] - [nodeName, hostName] = string.split(remoteNodeName, "@") - e = erl_epmd.ErlEpmd(hostName) - cb = erl_common.Callback(self._PingEpmdResponse, remoteNodeName) - e.PortPlease2Req(nodeName, cb) - - def Publish(self): - """Publish this node to the EPMD, the Erlang Portmapper Daemon. - Returns: void - Throws: nothing. - - Publishing must be done for mboxes/processes on other nodes - to be able to establish contact with mboxes on this node. - The node is published automatically when it tries to contact - another node, for example due to a message to send or an rpc call. - """ - if not self._isServerPublished: - self._epmd.Connect(self._EpmdConnectedOk, self._EpmdConnectFailed) - - def Unpublish(self): - """Removes the publication of this node to the EPMD. - Returns: void - Throws: nothing - """ - if self._isServerPublished: - self._epmd.Close() - self._isServerPublished = 0 - - def NodeUpSubscribe(self, cb): - """Subscribe to nodeup-information - - CB = - - Returns: ID = - Throws: nothing - - Subscribe to nodeup-information, that is, to connections to - new nodes. The new connections may initiated by, for example, - a messages begin sent from this node to another one (a new - connection is automatically set up), or by another node - connection to this. - - The ID returned can be used to unsubscribe the callback from further - nodeup-informations. - """ - id = self._cbId - self._cbId = self._cbId + 1 - self._nodeUpCb.append((id, cb)) - return id - - def NodeUpUnsubscribe(self, id): - """Unsubscribe to nodeup-information - - ID = - - Returns: void - Throws: nothing - - Unsubscribes to nodeup-information. - """ - cbs = self._nodeUpCb - for (index, (cbid, cb)) in map(None, range(len(cbs)), cbs): - if id == cbid: - del self._nodeUpCb[index] - return - - def NodeDownSubscribe(self, cb): - """Subscribe to nodedown-information for a certain node - - CB = - - Returns: ID = - Throws: nothing - - Subscribe to nodedown-information, that is, to broken connections to - other nodes. - - The ID returned can be used to unsubscribe the callback from further - nodedown-informations. - """ - id = self._cbId - self._cbId = self._cbId + 1 - self._nodeDownCb.append((id, cb)) - return id - - def NodeDownUnsubscribe(self, id): - """Unsubscribe to nodedown-information - - ID = - - Returns: void - Throws: nothing - - Unsubscribes to nodedown-information. - """ - cbs = self._nodeDownCb - for (index, (cbid, cb)) in map(None, range(len(cbs)), cbs): - if id == cbid: - del self._nodeDownCb[index] - return - - def DumpConnections(self): - """Dump connections. This method is intended for debugging purposes. - Returns: void - Throws: nothing - """ - print "Connections:" - for k in self._connections.keys(): - print " %s --> %s" % (`k`, `self._connections[k]`) - print "--" - - - ## - ## Routines to be called only by mboxes - ## - - def RegisterNameForMBox(self, mbox, name): - """This routine is intended to be called from an ErlMBox instance. - MBOX = - NAME = string - Returns: void - Throws: <> - """ - mboxPid = mbox.Self() - if self._registeredNames.has_key(name): - raise "IsRegistered" - if self._registeredPids.has_key(mboxPid): - raise "IsRegistered" - self._registeredNames[name] = mboxPid - self._registeredPids[mboxPid] = name - - def UnregisterNameForMBox(self, mbox): - """This routine is intended to be called from an ErlMBox instance - MBOX = - Returns: void - Throws: <> - """ - mboxPid = mbox.Self() - if not self._registeredPids.has_key(mboxPid): - raise "NotRegistered" - name = self._registeredPids[mboxPid] - del self._registeredPids[mboxPid] - del self._registeredNames[name] - - - def WhereisMBox(self, name): - """Lookup an mbox that is registered under a name. - NAME = string - Returns: - Throws: nothing - """ - mboxPid = self.WhereisPid(name) - if mboxPid == None: - return None - if not self._pids.has_key(mboxPid): - return None - return self._pids[mboxPid] - - def WhereisPid(self, name): - """Lookup an mbox that is registered under a name. - NAME = string - Returns: - Throws: nothing - """ - if not self._registeredNames.has_key(name): - return None - return self._registeredNames[name] - - - def SendMsgFromMBox(self, sourceMBox, dest, msg): - """This routine is intended to be called from an ErlMBox instance - SOURCE-MBOX = - DEST = | - string | - | - tuple(DEST-REGNAME, DEST-NODE) - DEST-REGNAME = DEST-NODE = string | - MSG = - Returns: void - THrows: <> - """ - ## Possible dest types: - ## - A tuple: (registered_name, node_name) - ## - An atom: registered_name - ## - A pid: (note: the pid contains the pid's node) - - sourcePid = self._mboxes[sourceMBox] - - ## First check for strings in the dest argument. - ## Convert any strings to to atoms. - if type(dest) == types.StringType: - dest = erl_term.ErlAtom(dest) - elif type(dest) == types.TupleType: - destPidName = dest[0] - destNode = dest[1] - if type(destPidName) == types.StringType: - destPidName = erl_term.ErlAtom(destPidName) - if type(destNode) == types.StringType: - destNode = erl_term.ErlAtom(destNode) - dest = (destPidName, destNode) - - ## Then split the dest into: - ## destPid/destPidName and destNode - ## depending on its type. - if type(dest) == types.TupleType: - destPid = dest[0] - destNode = dest[1] - elif erl_term.IsErlAtom(dest): - destNode = self - name = dest.atomText - if not self._registeredNames.has_key(name): - return - destPid = self._registeredNames[name] - elif erl_term.IsErlPid(dest): - destPid = dest - destNode = dest.node - else: - return - - ## Now do the sending... - if destNode == self: - if not self._registeredPids.has_key(destPid): - return - mbox = self._registredPids[destPid] - mbox.Msg(msg) - else: # dest node is remote - # First make sure we are online - # FIXME: Will this really work??? - # Publish might register callbacks, but - # this code continues after the Publish... - self.Publish() - destNodeName = destNode.atomText - if not self._connections.has_key(destNodeName): - # We don't have a connection to the destination - # We must open a connection. - # This is done by pinging with the ping-callback - # being a function that sends the message. - - cb = erl_common.Callback(self._SendMsgToRemoteNode, - sourcePid, destNode, destPid, msg) - destNodeName = destNode.atomText - self.Ping(destNodeName, cb) - else: - ## We have contact with the remote node. Send at once! - self._SendMsgToRemoteNode("pong", - sourcePid, destNode, destPid, msg) - - ## - ## Internal routines - ## - - def _CreateRex(self): - mboxPid = self._CreatePid() - mbox = _ErlRexMBox(self, mboxPid) - self._pids[mboxPid] = mbox - self._mboxes[mbox] = mboxPid - mbox.Start() - - def _CreatePid(self): - """Returns: """ - ## Code stolen from com/ericsson/otp/erlang/OtpLocalNode.java - global _serial, _pidCount - newPid = erl_term.ErlPid(erl_term.ErlAtom(self._nodeName), - _pidCount, _serial, self._creation) - _pidCount = _pidCount + 1 - if _pidCount > 0x7fff: - _pidCount = 0 - _serial = _serial + 1 - if _serial > 0x07: - _serial = 0 - return newPid - - def _EpmdConnectedOk(self, creation): - """This callback is called when the publish to EPMD has successfully - completed.""" - self._isServerPublished = 1 - self._creation = creation - - def _EpmdConnectFailed(self, errorResult): - raise "Failed to connect to epmd (%d)" % errorResult - - def _NodeUp(self, connection, nodeName): - """This callback is called from the in/out connection object - when a new connection has been established.""" - erl_common.Debug(M, "NODEUP: nodeName=%s connection=%s" % \ - (nodeName, connection)) - self._connections[nodeName] = connection - for (id, cb) in self._nodeUpCb: - cb("nodeup", nodeName) - - def _NodeDown(self, connection, nodeName): - """This callback is called from the in/out connection object when a - connection has been broken.""" - erl_common.Debug(M, "NODENOWN: nodeName=%s connection=%s" % \ - (nodeName, connection)) - if self._connections.has_key(nodeName): - del self._connections[nodeName] - for (id, cb) in self._nodeDownCb: - cb("nodedown", nodeName) - - def _PingEpmdResponse(self, result, portNum, nodeType, proto, - distVSNRange, nodeNameNoHost, extra, - remoteNodeName): - """This callback is called when the lookup for a nodename at a host - has returned, whether it was successful or not. - If it was successful, then RESULT != 0 and the other parameters - are valid. If it was not successful, then the other parameters have - undefined values.""" - if result != 0: - callbacks = self._ongoingPings[remoteNodeName] - del self._ongoingPings[remoteNodeName] - for cb in callbacks: - cb("pang") - else: - [otherNode, otherHost] = string.split(remoteNodeName, "@") - out = erl_node_conn.ErlNodeOutConnection(self._nodeName, - self._opts) - connectedOkCb = erl_common.Callback(self._PingSucceeded, - out, remoteNodeName) - connectFailedCb = erl_common.Callback(self._PingFailed, - out, remoteNodeName) - connectionBrokenCb = erl_common.Callback(self._NodeDown, - out, remoteNodeName) - passThroughMsgCb = erl_common.Callback(self._PassThroughMsg, - out, remoteNodeName) - out.InitiateConnection(otherHost, portNum, - connectedOkCb, - connectFailedCb, - connectionBrokenCb, - self._PassThroughMsg) - - def _PingSucceeded(self, connection, remoteNodeName): - """This internal routine signals that the ping of another node - was successul.""" - callbacks = self._ongoingPings[remoteNodeName] - del self._ongoingPings[remoteNodeName] - self._NodeUp(connection, remoteNodeName) - for cb in callbacks: - cb("pong") - - def _PingFailed(self, connection, remoteNodeName): - """This internal routine signals that the ping of another node - failed.""" - if self._ongoingPings.has_key(remoteNodeName): - callbacks = self._ongoingPings[remoteNodeName] - del self._ongoingPings[remoteNodeName] - for cb in callbacks: - cb("pang") - - - def _PassThroughMsg(self, connection, remoteNodeName, ctrlMsg, msg=None): - """This callback is called when a connection recevies a message of - type passthrough. Currently all messages are of type passthrough.""" - erl_common.Debug(M, "ctrlMsg=%s" % `ctrlMsg`) - - ctrlMsgOp = ctrlMsg[0] - if ctrlMsgOp == self.CTRLMSGOP_LINK: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - pass - elif ctrlMsgOp == self.CTRLMSGOP_SEND: - cookie = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - msg = msg - erl_common.Debug(M, "SEND: msg=%s" % `msg`) - if self._pids.has_key(toPid): - mbox = self._pids[toPid] - mbox.Msg(remoteNodeName, msg) - else: - erl_common.Debug(M, "Got SEND with no dest pid: %s" % toPid) - erl_common.Debug(M, "Pids:\n%s" % `self._pids`) - elif ctrlMsgOp == self.CTRLMSGOP_EXIT: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - reason = ctrlMsg[3] - pass - elif ctrlMsgOp == self.CTRLMSGOP_UNLINK: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - pass - elif ctrlMsgOp == self.CTRLMSGOP_NODE_LINK: - pass - elif ctrlMsgOp == self.CTRLMSGOP_REG_SEND: - fromPid = ctrlMsg[1] - cookie = ctrlMsg[2] - toNameAtom = ctrlMsg[3] - toName = toNameAtom.atomText - msg = msg - if self._registeredNames.has_key(toName): - mboxPid = self._registeredNames[toName] - mbox = self._pids[mboxPid] - mbox.Msg(remoteNodeName, msg) - else: - erl_common.Debug(M, - "Got REG_SEND with no dest mbox: \"%s\": %s" % - (toName, msg)) - elif ctrlMsgOp == self.CTRLMSGOP_GROUP_LEADER: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - pass - elif ctrlMsgOp == self.CTRLMSGOP_EXIT2: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - reason = ctrlMsg[3] - pass - elif ctrlMsgOp == self.CTRLMSGOP_SEND_TT: - cookie = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - traceToken = ctrlMsg[3] - msg = msg - pass - elif ctrlMsgOp == self.CTRLMSGOP_EXIT_TT: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - traceToken = ctrlMsg[3] - reason = ctrlMsg[4] - pass - elif ctrlMsgOp == self.CTRLMSGOP_REG_SEND_TT: - fromPid = ctrlMsg[1] - cookie = ctrlMsg[2] - toName = ctrlMsg[3] - traceToken = ctrlMsg[4] - msg = msg - pass - elif ctrlMsgOp == self.CTRLMSGOP_EXIT2_TT: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - traceToken = ctrlMsg[3] - reason = ctrlMsg[4] - pass - elif ctrlMsgOp == self.CTRLMSGOP_MONITOR_P: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - ref = ctrlMsg[3] - pass - elif ctrlMsgOp == self.CTRLMSGOP_DEMONITOR_P: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - ref = ctrlMsg[3] - pass - elif ctrlMsgOp == self.CTRLMSGOP_MONITOR_P_EXIT: - fromPid = ctrlMsg[1] - toPid = self._InternPid(ctrlMsg[2]) - ref = ctrlMsg[3] - pass - else: - erl_common.Debug(M, "Unknown controlmsg: %s" % `ctrlMsg`) - - def _SendMsgToRemoteNode(self, pingResult, srcPid, destNode, destPid, msg): - """This internal routine performs the actual sending.""" - if pingResult != "pong": - return - destNodeName = destNode.atomText - if not self._connections.has_key(destNodeName): - return - conn = self._connections[destNodeName] - cookie = erl_term.ErlAtom("") - if erl_term.IsErlAtom(destPid): - ctrlMsg = (self.CTRLMSGOP_REG_SEND, srcPid, cookie, destPid) - else: - ctrlMsg = (self.CTRLMSGOP_SEND, cookie, destPid) - conn.SendMsg(ctrlMsg, msg) - - def _InternPid(self, newPid): - """This is like intern() for strings, but for pids. - The purpose is so that we'll be able to lookup pids - in self._pids and self._registredPids. - """ - for existingPid in self._pids.keys(): - if existingPid.equals(newPid): - return existingPid - return newPid diff --git a/py_interface/erl_node_conn.py b/py_interface/erl_node_conn.py deleted file mode 100644 index 24bc065..0000000 --- a/py_interface/erl_node_conn.py +++ /dev/null @@ -1,768 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_node_conn.py -- Handle inter-node communication - -import sys -import time -import types -import string -import socket -import random -try: - from hashlib import md5 -except ImportError: - # Pre-Python2.5 library for md5 - from md5 import new as md5 - - -from py_interface import erl_opts -from py_interface import erl_term -from py_interface import erl_common -from py_interface import erl_async_conn -from py_interface import erl_eventhandler - -M = "erl_node_conn" - -def CheckDigest(digest, challenge, cookie): - """Checks that a digest is correct. - DIGEST = string - CHALLENGE = integer | longinteger - COOKIE = string - - Returns: 1 | 0 - Throws: nothing - """ - expectedDigest = GenDigest(challenge, cookie) - return expectedDigest == digest - -def GenDigest(challenge, cookie): - """Generates a digest from a CHALLENGE and a COOKIE. - CHALLENGE = integer | longinteger - COOKIE = string - - Returns: string - Throws: nothing - """ - challengeStr = str(challenge) - if challengeStr[-1] == 'L': - challengeStr = challengeStr[:-1] - return md5(cookie + challengeStr).digest() - -def GenChallenge(): - """Generates a challenge. - No arguments. - Returns: integer - Throws: nothing - """ - return int(random.random() * 0x7fffffff) - - -class Ticker: - """This class is used for keeping track of the net-ticks: - * when a remote node has been silent for too long - * when it's time to send a tick so the other part won't think - we've been silent for to long (to `tick'). - """ - - def __init__(self, netTickTime, timeToTickCb, noResponseCb): - """Constructor - NET-TICK-TIME = integer - the net-tick-time (in seconds). - TIME-TO-TICK-CB = - callback to call when it's time to tick. - NO-RESPONSE-CB = - callback to call when the other end has been - silent for too long. - - Throws: nothing - """ - self._netTickTime = netTickTime - self._evhandler = erl_eventhandler.GetEventHandler() - self._InitStartResponseTimer(netTickTime, noResponseCb) - self._InitStartTickTimer(netTickTime, timeToTickCb) - - def _InitStartResponseTimer(self, netTickTime, noResponseCb): - self._noResponseCb = noResponseCb - self._noResponseTimeout = netTickTime * 1.25 - self._responseCheckTimeout = netTickTime * 0.25 - self._responseDoCheck = 1 - self._timeForLastResponse = time.time() - self._StartResponseTimer() - - def _StartResponseTimer(self): - if self._responseDoCheck: - timeout = self._responseCheckTimeout - cb = self._CheckResponse - timerId = self._evhandler.AddTimerEvent(timeout, cb) - self._checkResponseTimerId = timerId - - def _StopResponseTimer(self): - self._responseDoCheck = 0 - - def GotResonse(self): - """To be called whenever data has been received from the other end. - No arguments. - Returns: void - Throws: nothing - """ - self._timeForLastResponse = time.time() - - def _CheckResponse(self): - if self._responseDoCheck: - now = time.time() - if now > self._timeForLastResponse + self._noResponseTimeout: - self._responseDoCheck = 0 - self._noResponseCb() - else: - self._StartResponseTimer() - - def _InitStartTickTimer(self, netTickTime, timeToTickCb): - self._timeToTickCb = timeToTickCb - self._tickTimeout = netTickTime * 0.25 - self._tickCheckTimeout = netTickTime * 0.125 - self._tickDoCheck = 1 - self._timeForLastTick = time.time() - self._StartTickTimer() - - def _StartTickTimer(self): - if self._tickDoCheck: - timeout = self._tickCheckTimeout - cb = self._Tick - timerId = self._evhandler.AddTimerEvent(timeout, cb) - self._tickTimerId = timerId - - def _StopTickTimer(self): - self._tickDoCheck = 0 - - def RestartTick(self): - """To be called whenever something has been sent to the other end. - No arguments. - Returns: void - Throws: nothing - """ - self._timeForLastTick = time.time() - - def _Tick(self): - if self._tickDoCheck: - self._StartTickTimer() - now = time.time() - if now > self._timeForLastTick + self._tickTimeout: - self._timeToTickCb() - self._timeForLastTick = time.time() - - def Stop(self): - """Stop the timers. - No arguments. - Returns: void - Throws: nothing - """ - self._StopResponseTimer() - self._StopTickTimer() - -class ErlNodeOutConnection(erl_async_conn.ErlAsyncClientConnection): - """This class handles a connection _to_ another node, - initiated by this node. - - Inheritance: erl_async_conn.ErlAsyncClientConnection - - This is intended to be used by the erl_node.ErlNode class. - """ - _STATE_DISCONNECTED = -1 - _STATE_HANDSHAKE_RECV_STATUS = 2 - _STATE_HANDSHAKE_RECV_CHALLENGE = 4 - _STATE_HANDSHAKE_RECV_CHALLENGE_ACK = 6 - _STATE_CONNECTED = 7 - - def __init__(self, nodeName, opts): - """Constructor. - NODE-NAME = string - OPTS = - - Throws: nothing - """ - erl_async_conn.ErlAsyncClientConnection.__init__(self) - self._recvdata = "" - self._hostName = None - self._portNum = None - self._nodeName = nodeName - self._opts = opts - self._peerName = None - self._state = self._STATE_DISCONNECTED - # 2 bytes for the packet length during the handshake, then 4 bytes - self._packetLenSize = 2 - # These are started once the connection is up - self._tickTimers = None - - def InitiateConnection(self, hostName, portNum, - connectOkCb, connectFailedCb, connectionBrokenCb, - passThroughMsgCb): - """Initiates a connection to another erlang-node. - HOST-NAME = string - The node to connect to. - PORT-NUM = integer - The port on that node. Use the EPMD to find - the port number, given a node name. - CONNECT-OK-CB = - To be called when a connection has been - successfully established. - CONNECT-FAILED-CB = - CONNECTION = ErlNodeOutConnection - PEER-NAME = string (the node name for the peer) - To be called when a connection establishment - failed. - CONNECTION-BROKEN-CB = - CONNECTION = ErlNodeOutConnection - PEER-NAME = string (the node name for the peer) - To be called when an established connection - has been broken. - - Returns: void - Throws: <> - """ - self._hostName = hostName - self._portNum = portNum - self._connectOkCb = connectOkCb - self._connectFailedCb = connectFailedCb - self._connectionBrokenCb = connectionBrokenCb - self._passThroughMsgCb = passThroughMsgCb - self._peerName = "(unknown)@%s" % hostName - if self.Connect(hostName, portNum): - self._SendName() - self._state = self._STATE_HANDSHAKE_RECV_STATUS - else: - return 0 - - def GetPeerNodeName(self): - """Retrieves the node name for the peer. - No arguments. - Returns: string | "" - Throws: nothing - """ - return self._peerName - - def SendMsg(self, ctrlMsg, msg=None): - """Sends a message to the other end. - CTRL-MSG = term - MSG (optional) = None | term - - Returns: void - Throws: nothing - - For information on the CTRL-MSG and the MSG, please refer to the file - erl_ext_dist.txt in the Erlang distribution. - """ - if msg == None: - packet = "p" + erl_term.TermToBinary(ctrlMsg) - else: - packet = "p" + (erl_term.TermToBinary(ctrlMsg) + \ - erl_term.TermToBinary(msg)) - self._SendPacket(packet) - - - ## - ## Internal routines - ## - - def _In(self): - """Callback routine, which is called when data is available - on the connection.""" - connection = self.GetConnection() - newData = connection.recv(100000) - if len(newData) == 0: - self.Close() - if self._state != self._STATE_CONNECTED: - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - else: - self._state = self._STATE_DISCONNECTED - if self._tickTimers != None: - self._tickTimers.Stop() - self._connectionBrokenCb() - return - - self._recvdata = self._recvdata + newData - remainingUnhandledData = self._HandleData(self._recvdata) - self._recvdata = remainingUnhandledData - - def _HandleData(self, data): - remainingInput = data - while 1: - if len(remainingInput) < self._packetLenSize: - return remainingInput - - if self._packetLenSize == 2: - packetLen = self.ReadInt2(remainingInput[0:2]) - packetOffset = 2 - else: - packetLen = self.ReadInt4(remainingInput[0:4]) - packetOffset = 4 - - if len(remainingInput) < self._packetLenSize + packetLen: - return remainingInput - - packetData = remainingInput[packetOffset:packetOffset+packetLen] - self._HandlePacket(packetData) - remainingInput = remainingInput[packetOffset+packetLen:] - - - def _HandlePacket(self, data): - if self._state == self._STATE_HANDSHAKE_RECV_STATUS: - # First check that the correct message came in - if data[0] != "s": - erl_common.DebugHex(M, "handshake:recv_status: got", data) - self.Close() - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - status = data[1:] - if status == "ok" or status == "ok_simultaneous": - self._state = self._STATE_HANDSHAKE_RECV_CHALLENGE - elif status == "nok" or status == "not_allowed": - self.Close() - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - elif status == "alive": - self._SendStatusAliveTrue() - self._state = self._STATE_HANDSHAKE_RECV_CHALLENGE - else: - erl_common.DebugHex(M, "handshake:recv_status", data) - elif self._state == self._STATE_HANDSHAKE_RECV_CHALLENGE: - # First check that the correct message came in - if data[0] != "n": - erl_common.DebugHex(M, "handshake:recv_cha", data) - self.Close() - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - self._peerVersion = self.ReadInt2(data[1:3]) - self._peerFlags = self.ReadInt4(data[3:7]) - challenge = self.ReadInt4(data[7:11]) - self._peerName = data[11:] - self._SendChallengeReply(challenge) - self._state = self._STATE_HANDSHAKE_RECV_CHALLENGE_ACK - elif self._state == self._STATE_HANDSHAKE_RECV_CHALLENGE_ACK: - # First check that the correct message came in - if data[0] != "a": - erl_common.DebugHex(M, "handshake:recv_cha_ack", data) - self.Close() - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - digest = data[1:] - ownCookie = self._opts.GetCookie() - if CheckDigest(digest, self._challengeToPeer, ownCookie): - self._packetLenSize = 4 - self._state = self._STATE_CONNECTED - t = self._opts.GetNetTickTime() - self._tickTimers = Ticker(t, self._Tick, self._NoResponse) - self._connectOkCb() - else: - erl_common.Debug(M, - "Connection attempt to disallowed node %s" % - self._peerName) - self.Close() - self._state = self._STATE_DISCONNECTED - self._connectFailedCb() - elif self._state == self._STATE_CONNECTED: - self._tickTimers.GotResonse() - if len(data) == 0: - # A tick - return - - msgType = data[0] - if msgType == "p": - terms = erl_term.BinariesToTerms(data[1:]) - if len(terms) == 2: - controlMsg = terms[0] - msg = terms[1] - self._passThroughMsgCb(self, self.GetPeerNodeName(), - controlMsg, msg) - elif len(terms) == 1: - controlMsg = terms[0] - self._passThroughMsgCb(self, self.GetPeerNodeName(), - controlMsg, msg) - else: - debugTxt = "PassThrough-msg: terms=%s" % `terms` - erl_common.DebugHex(M, debugTxt, data) - else: - erl_common.DebugHex(M, "msgType=%c" % msgType, data) - else: - erl_common.DebugHex(M, "state=%d" % self._state, data) - - - def _Tick(self): - """This callback is called by the Ticker class instance - when it is time to send a tick to the other end, to indicate that - we are still alive. - """ - self._SendPacket("") - - def _NoResponse(self): - """This callback is called by the Ticker class instance - when nothing has been received from the other end for too long. - """ - erl_common.Debug(M, "InConnection: Connection broken") - self._state = self._STATE_DISCONNECTED - self._tickTimers.Stop() - self._connectionBrokenCb() - - - def _SendName(self): - packet = "n" + \ - self.PackInt2(self._opts.GetDistrVersion()) + \ - self.PackInt4(self._opts.GetDistrFlags()) + \ - self._nodeName - self._SendHandshakeMsg(packet) - - def _SendStatusAliveTrue(self): - self._SendHandshakeMsg("true") - - def _SendChallengeReply(self, challenge): - digest = GenDigest(challenge, self._opts.GetCookie()) - challengeToPeer = GenChallenge() - self._challengeToPeer = challengeToPeer - packet = "r" + self.PackInt4(challengeToPeer) + digest - self._SendHandshakeMsg(packet) - - def _SendHandshakeMsg(self, packet): - msg = self.PackInt2(len(packet)) + packet - erl_common.Debug(M, "Sending handshake") - self.Send(msg) - - def _SendPacket(self, packet): - msg = self.PackInt4(len(packet)) + packet - erl_common.Debug(M, "Sending msg") - self._tickTimers.RestartTick() - self.Send(msg) - - -class ErlNodeServerSocket(erl_async_conn.ErlAsyncServer): - """This class opens a socket and for incoming connections from other - Erlang nodes. When a remote node connects, an new instance of - the ErlNodeInConnection is created for handling the new connection. - - This class is indended to be used by the erl_node.ErlNode. - """ - def __init__(self, nodeName, opts): - """Constructor - NODE-NAME = string - The name of this node - OPTS = - - Throws: nothing - """ - erl_async_conn.ErlAsyncServer.__init__(self) - self._nodeName = nodeName - self._opts = opts - self._passThroughMsgCb = self._Sink - self._nodeUpCb = self._Sink - self._nodeDownCb = self._Sink - - def Start(self, nodeUpCb, nodeDownCb, passThroughMsgCb): - """Setup and start to listen for incoming connections. - - NODE-UP-CB = - Callback to call when a new connection has been - established. - NODE-DOWN-CB = - Callback to call when an established connection - has been broken. - PASS-THROUGH-MSG-CB = - Callback to call for pass-through messages. - Currently, all messages incoming messages are - of this type. - (Sub)Types: - - CONNECTION = - The instance of the class that handles the connection - PEER-NAME = string - The node name for the peer node - CTRL-MSG = term - MSG = term - For information on CTRL-MSG and MSG, see the - file erl_ext_dist.txt, which is included in the - Erlang distribution. - - Returns: void - Throws: <> - """ - self._nodeUpCb = nodeUpCb - self._nodeDownCb = nodeDownCb - self._passThroughMsgCb = passThroughMsgCb - return erl_async_conn.ErlAsyncServer.Start(self) - - def _NewConnection(self, s, remoteAddr): - erl_common.Debug(M, "new connection from %s" % `remoteAddr`) - inConn = ErlNodeInConnection(s, - self._nodeName, self._opts, - self._nodeUpCb, self._nodeDownCb, - self._passThroughMsgCb) - - def _Sink(self, *a, **kw): - pass - -class ErlNodeInConnection(erl_async_conn.ErlAsyncPeerConnection): - """This class handles incoming connections from other Erlang nodes. - - This class is indended to be used by the ErlNodeSocketServer - (and thus indirectly by the erl_node.ErlNode). - """ - - ## XXX TODO: This node duplicates too much functionality - ## from ErlNodeOutConnection, still there are differences. - ## - ## The differences are in the setting up of the connection; - ## during the handshake sequence, the connecting side - ## (ErlNodeOutConnection) acts the client, while the connected - ## side (ErlNodeInConnection) acts as server. - ## - ## One idea is to maybe separate the state-machine - ## into its own class. - ## - ## Need to think about this one... - - _STATE_DISCONNECTED = -1 - _STATE_HANDSHAKE_RECV_NAME = 1 - _STATE_HANDSHAKE_RECV_STATUS = 3 - _STATE_HANDSHAKE_RECV_CHALLENGE_REPLY = 5 - _STATE_CONNECTED = 7 - - def __init__(self, sock, nodeName, opts, - newConnectionUpCb, connectionBrokenCb, - passThroughMsgCb): - """Constructor. - SOCK = - The socket for the incoming connection. - NODE-NAME = string - The node name of the node to which this - connection belongs. - OPTS = - Options for the node - NEW-CONNECTION-UP-CB = - Callback to call when a new connection has been - established. - CONNECTION-BROKEN-CB = - Callback to call when an established connection - has been broken. - PASS-THROUGH-MSG-CB = - Callback to call for pass-through messages. - Currently, all messages incoming messages are - of this type. - """ - erl_async_conn.ErlAsyncPeerConnection.__init__(self, sock) - self._recvdata = "" - self._hostName = None - self._portNum = None - self._nodeName = nodeName - self._opts = opts - self._newConnectionUpCb = newConnectionUpCb - self._connectionBrokenCb = connectionBrokenCb - self._passThroughMsgCb = passThroughMsgCb - self._state = self._STATE_HANDSHAKE_RECV_NAME - self._peerName = nodeName - # 2 bytes for the packet length during the handshake, then 4 bytes - self._packetLenSize = 2 - # These are started once the connection is up - self._tickTimers = None - - def GetPeerNodeName(self): - """Retrieves the node name for the peer. - No arguments. - Returns: string | "" - Throws: nothing - """ - return self._peerName - - def SendMsg(self, ctrlMsg, msg=None): - """Sends a message to the other end. - CTRL-MSG = term - MSG (optional) = None | term - - Returns: void - Throws: nothing - - For information on the CTRL-MSG and the MSG, please refer to the file - erl_ext_dist.txt in the Erlang distribution. - """ - if msg == None: - packet = "p" + erl_term.TermToBinary(ctrlMsg) - else: - packet = "p" + (erl_term.TermToBinary(ctrlMsg) + \ - erl_term.TermToBinary(msg)) - self._SendPacket(packet) - - - ## - ## Internal routines - ## - - def _In(self): - """Callback routine, which is called when data is available - on the connection.""" - connection = self.GetConnection() - newData = connection.recv(100000) - if len(newData) == 0: - self.Close() - if self._state != self._STATE_CONNECTED: - self._state = self._STATE_DISCONNECTED - else: - erl_common.Debug(M, "InConnection: Connection broken") - self._state = self._STATE_DISCONNECTED - if self._tickTimers != None: - self._tickTimers.Stop() - self._connectionBrokenCb(self, self.GetPeerNodeName()) - return - - self._recvdata = self._recvdata + newData - remainingUnhandledData = self._HandleData(self._recvdata) - self._recvdata = remainingUnhandledData - - def _HandleData(self, data): - remainingInput = data - while 1: - if len(remainingInput) < self._packetLenSize: - return remainingInput - - if self._packetLenSize == 2: - packetLen = self.ReadInt2(remainingInput[0:2]) - packetOffset = 2 - else: - packetLen = self.ReadInt4(remainingInput[0:4]) - packetOffset = 4 - - if len(remainingInput) < self._packetLenSize + packetLen: - return remainingInput - - packetData = remainingInput[packetOffset:packetOffset+packetLen] - self._HandlePacket(packetData) - remainingInput = remainingInput[packetOffset+packetLen:] - - def _HandlePacket(self, data): - if self._state == self._STATE_HANDSHAKE_RECV_NAME: - # First check that the correct message came in - if data[0] != "n": - erl_common.DebugHex(M, "handshake:recv_name", data) - self.Close() - self._state = self._STATE_DISCONNECTED - self._peerDistrVersion = self.ReadInt2(data[1:3]) - self._peerFlags = self.ReadInt4(data[3:7]) - self._peerName = data[7:] - # FIXME: check for connections _to_ this node: - # check whether nodeName > ownNodeName (or check < ?) - self._SendStatusOk() - self._SendChallenge() - self._state = self._STATE_HANDSHAKE_RECV_CHALLENGE_REPLY - elif self._state == self._STATE_HANDSHAKE_RECV_CHALLENGE_REPLY: - # First check that the correct message came in - if data[0] != "r": - erl_common.DebugHex(M, "handshake:recv_chreply", data) - self.Close() - self._state = self._STATE_DISCONNECTED - peersChallenge = self.ReadInt4(data[1:5]) - peersDigest = data[5:] - ownCookie = self._opts.GetCookie() - if CheckDigest(peersDigest, self._challengeToPeer, ownCookie): - self._SendChallengeAck(peersChallenge) - self._packetLenSize = 4 - self._state = self._STATE_CONNECTED - t = self._opts.GetNetTickTime() - self._tickTimers = Ticker(t, self._Tick, self._NoResponse) - self._newConnectionUpCb(self, self.GetPeerNodeName()) - else: - erl_common.Debug(M, - "Connection attempt from disallowed node %s" % - self._peerName) - self.Close() - self._state = self._STATE_DISCONNECTED - elif self._state == self._STATE_CONNECTED: - self._tickTimers.GotResonse() - if len(data) == 0: - # A tick - return - - msgType = data[0] - if msgType == "p": - terms = erl_term.BinariesToTerms(data[1:]) - if len(terms) == 2: - controlMsg = terms[0] - msg = terms[1] - peerName = self.GetPeerNodeName() - self._passThroughMsgCb(self, peerName, controlMsg, msg) - elif len(terms) == 1: - controlMsg = terms[0] - peerName = self.GetPeerNodeName() - self._passThroughMsgCb(self, peerName, controlMsg) - else: - debugTxt = "PassThrough-msg: terms=%s" % `terms` - erl_common.DebugHex(M, debugTxt, data) - else: - erl_common.DebugHex(M, "msgType=%c" % msgType, data) - else: - erl_common.DebugHex(M, "state=%d" % self._state, data) - - - def _Tick(self): - """This callback is called by the Ticker class instance - when it is time to send a tick to the other end, to indicate that - we are still alive. - """ - self._SendPacket("") - - def _NoResponse(self): - """This callback is called by the Ticker class instance - when nothing has been received from the other end for too long. - """ - erl_common.Debug(M, "InConnection: Connection broken") - self._state = self._STATE_DISCONNECTED - self._tickTimers.Stop() - self._connectionBrokenCb(self, self.GetPeerNodeName()) - - - def _SendStatusOk(self): - self._SendHandshakeMsg("sok") - - def _SendChallenge(self): - challenge = GenChallenge() - self._challengeToPeer = challenge - packet = "n" + \ - self.PackInt2(self._opts.GetDistrVersion()) + \ - self.PackInt4(self._opts.GetDistrFlags()) + \ - self.PackInt4(challenge) + \ - self._nodeName - self._SendHandshakeMsg(packet) - - def _SendChallengeAck(self, challenge): - packet = "a" + GenDigest(challenge, self._opts.GetCookie()) - self._SendHandshakeMsg(packet) - - def _SendHandshakeMsg(self, packet): - msg = self.PackInt2(len(packet)) + packet - erl_common.Debug(M, "Sending handshake") - self.Send(msg) - - def _SendPacket(self, packet): - msg = self.PackInt4(len(packet)) + packet - erl_common.Debug(M, "Sending msg") - self._tickTimers.RestartTick() - self.Send(msg) diff --git a/py_interface/erl_opts.py b/py_interface/erl_opts.py deleted file mode 100644 index 10bb350..0000000 --- a/py_interface/erl_opts.py +++ /dev/null @@ -1,79 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_opts.py -- holder class for options for the node - -### Added a patch from Luke Gorrie, to support Erlang/OTP R10B, see -### http://article.gmane.org/gmane.comp.lang.erlang.general/9751 - - -DISTR_FLAG_PUBLISHED = 1; -DISTR_FLAG_ATOMCACHE = 2; -DISTR_FLAG_EXTENDEDREFERENCES = 4; -DISTR_FLAG_DISTMONITOR = 8; -DISTR_FLAG_FUNTAGS = 16; -DISTR_FLAG_DISTMONITORNAME = 32; -DISTR_FLAG_HIDDENATOMCACHE = 64; -DISTR_FLAG_NEWFUNTAGS = 128; -DISTR_FLAG_EXTENDEDPIDSPORTS = 256; - -class ErlNodeOpts: - def __init__(self, - netTickTime=60, - shortNodeNames=1, - cookie="", - distrVersion=5, - distrFlags=(DISTR_FLAG_EXTENDEDREFERENCES| - DISTR_FLAG_EXTENDEDPIDSPORTS) - ): - self._netTickTime = netTickTime - self._shortNodeNames = shortNodeNames - self._cookie = cookie - self._distrVersion = distrVersion - self._distrFlags = distrFlags - - def GetNetTickTime(self): - return self._netTickTime - def SetNetTickTime(self, netTickTime): - self._netTickTime = netTickTime - - def GetShortNodeNames(self): - return self._shortNodeNames - def SetShortNodeNames(self, shortNodeNames): - self._shortNodeNames = shortNodeNames - - def GetCookie(self): - return self._cookie - def SetCookie(self, cookie): - self._cookie = cookie - - def GetDistrVersion(self): - return self._distrVersion - def SetDistrVersion(self, distrVersion): - self._distrVersion = distrVersion - - def GetDistrFlags(self): - return self._distrFlags - def SetDistrFlags(self, distrFlags): - self._distrFlags = distrFlags diff --git a/py_interface/erl_term.py b/py_interface/erl_term.py deleted file mode 100644 index c01fa48..0000000 --- a/py_interface/erl_term.py +++ /dev/null @@ -1,683 +0,0 @@ -### py_interface -- A Python-implementation of an Erlang node -### -### $Id$ -### -### Copyright (C) 2002 Tomas Abrahamsson -### -### Author: Tomas Abrahamsson -### -### This file is part of the Py-Interface library -### -### This library is free software; you can redistribute it and/or -### modify it under the terms of the GNU Library General Public -### License as published by the Free Software Foundation; either -### version 2 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 -### Library General Public License for more details. -### -### You should have received a copy of the GNU Library General Public -### License along with this library; if not, write to the Free -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -### erl_term.py -- python types/classes for all erlang types. -### Also: packing and unpacking all types to/from -### the erlang external binary format - -### Log of fixes: -### -### * integer unpacking by Jimmy Olgeni -### -### * string packing by Jimmy Olgeni -### -### * reference unpacking, independently by Nigel Head -### and Tomas Abrahamsson -### -### * bignum packing by Tomas Abrahamsson -### -### * error handling changed a bit: throws exceptions instead of silently -### hiding some nasties by Nigel Head -### -### * deals with received list tails better for non-proper lists -### by Nigel Head - -import os -import sys -import math -import types -import string - - -from py_interface import erl_common - -def ErlNumber(number): - return number - -_atom_cache = {} -class ErlAtom: - """An Erlang atom. The following attributes are defined: - atomText = string - """ - def __init__(self, atomText, cache=-1): - global _atom_cache - if atomText == None and cache != -1: - if _atom_cache.has_key(cache): - self.atomText = _atom_cache[cache] - else: - raise "No such cached atom: %s" % `cache` - elif atomText != None and cache != -1: - self.atomText = atomText - _atom_cache[cache] = atomText - else: - self.atomText = atomText - def __repr__(self): - return "" % `self.atomText` - def equals(self, other): - return self.atomText == other.atomText - def __str__(self): - return self.atomText - -def IsErlAtom(term): - """Checks whether a term is an Erlang atom or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlAtom) - - -class ErlRef: - """An Erlang reference. The following attributes are defined: - node = - id = integer | list(integer) - creation = integer - """ - def __init__(self, node, id, creation): - self.node = node - self.id = id # id is either an int or a list of ints - self.creation = creation - def __repr__(self): - return "" % \ - (`self.node`, `self.id`, self.creation) - def equals(self, other): - return self.node.equals(other.node) and \ - self.id == other.id and \ - self.creation == other.creation - -def IsErlRef(term): - """Checks whether a term is an Erlang reference or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlRef) - - -class ErlPort: - """An Erlang port. The following attributes are defined: - node = - id = integer - creation = integer - """ - def __init__(self, node, id, creation): - self.node = node - self.id = id - self.creation = creation - def __repr__(self): - return "" % \ - (`self.node`, self.id, self.creation) - def equals(self, other): - return self.node.equals(other.node) and \ - self.id == other.id and \ - self.creation == other.creation - -def IsErlPort(term): - """Checks whether a term is an Erlang reference or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlPort) - -class ErlPid: - """An Erlang process id. The following attributes are defined: - node = - id = integer - serial = integer - creation = integer - """ - def __init__(self, node, id, serial, creation): - self.node = node - self.id = id - self.serial = serial - self.creation = creation - def __repr__(self): - return "" % \ - (`self.node`, self.id, self.serial, self.creation) - def equals(self, other): - return self.node.equals(other.node) and \ - self.id == other.id and \ - self.serial == other.serial and \ - self.creation == other.creation - -def IsErlPid(term): - """Checks whether a term is an Erlang process id or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlPid) - -def ErlTuple(elementsAsList): - """An Erlang tuple. This maps to a python tuple.""" - return tuple(elementsAsList) - -def ErlList(elements): - """An Erlang list. This maps to a python list.""" - return elements - -class ErlImproperList: - """An improper erlang list (one where the tail is not []). - Can be iterated over to get the elements, by default will include - the tail as the last element.""" - def __init__(self,elements,tail,useTail=1): - self.elements = elements - self.tail = tail - # if true, we include tail element in iterations on this list - self.iterOnTail = useTail - def __repr__(self): - return "" % (`self.elements`,`self.tail`) - def equals(self,other): - return self.elements==other.elements and self.tail==other.tail - def __getitem__(self,key): - try: - return self.elements[key] - except IndexError: - if self.iterOnTail and key==len(self.elements): - return self.tail - raise IndexError - -def IsErlImproperList(term): - return type(term)== types.InstanceType and isinstance(term, ErlImproperList) - -class ErlBinary: - """An Erlang binary. The following attributes are defined: - contents = string - """ - def __init__(self, contents): - self.contents = contents # a string - def __repr__(self): - return "" % len(self.contents) - def equals(self, other): - return self.contents == other.contents - -def IsErlBinary(term): - """Checks whether a term is an Erlang binary or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlBinary) - -def ErlString(s): - """An Erlang list. This maps to a python string.""" - return s - -class ErlFun: - """An Erlang process id. The following attributes are defined: - pid = - module = - index = integer - uniq = integer - freeVars = list(term) - """ - def __init__(self, pid, module, index, uniq, freeVars): - self.pid = pid - self.module = module - self.index = index - self.uniq = uniq - self.freeVars = freeVars - def __repr__(self): - return ""%\ - (`self.pid`, `self.module`, self.index, self.uniq, - `self.freeVars`) - def equals(self, other): - return self.pid.equals(other.pid) and \ - self.module.equals(other.module) and \ - self.index == other.index and \ - self.uniq == other.uniq and \ - self.freeVars == other.freeVars - - -def IsErlFun(term): - """Checks whether a term is an Erlang function or not.""" - return type(term) == types.InstanceType and isinstance(term, ErlFun) - -### -### MAGIC tags used in packing/unpacking. See erl_ext_dist.txt -### -MAGIC_VERSION = 131 -MAGIC_STRING = 107 -MAGIC_NIL = 106 -MAGIC_LIST = 108 -MAGIC_SMALL_TUPLE = 104 -MAGIC_LARGE_TUPLE = 105 -MAGIC_LARGE_BIG = 111 -MAGIC_SMALL_BIG = 110 -MAGIC_FLOAT = 99 -MAGIC_SMALL_INTEGER = 97 -MAGIC_INTEGER = 98 -MAGIC_ATOM = 100 -MAGIC_NEW_REFERENCE = 114 -MAGIC_REFERENCE = 101 -MAGIC_PORT = 102 -MAGIC_PID = 103 -MAGIC_BINARY = 109 -MAGIC_FUN = 117 -MAGIC_NEW_CACHE = 78 -MAGIC_CACHED_ATOM = 67 - -### -### UNPACKING -### -def BinaryToTerm(binary): - """Unpack a binary to a term. - - BINARY = string - - Returns: term - Throws: "BinaryToTerm: Extraneous data in binary" - """ - try: - (term, remaining) = _UnpackOneTermTop(binary) - except: - raise "BinaryToTerm: Panic -- invalid binary received?" - if len(remaining) != 0: - raise "BinaryToTerm: Extraneous data in binary" - return term - -def BinariesToTerms(binary): - """Unpack a binary/binaries to term(s). - This is mainly for use by the erl_node_conn, where, in some cases, - two or more terms are packed together. - - BINARY = string - - Returns: list(term) - Throws: "BinaryToTerm: Extraneous data in binary" - """ - try: - (terms, remaining) = BufToTerm(binary) - except: - raise "BinariesToTerms: Panic -- invalid binary received?" - if len(remaining) != 0: - raise "BinariesToTerms: Extraneous data in binary" - return terms - -def BufToTerm(data): - unpackedTerms = [] - inputData = data - while 1: - (unpackedTerm, remainingData) = _UnpackOneTermTop(inputData) - if unpackedTerm == None: - return (unpackedTerms, remainingData) - unpackedTerms.append(unpackedTerm) - inputData = remainingData - -def _UnpackOneTermTop(data): - if len(data) == 0: - return (None, data) - if data[0] != chr(MAGIC_VERSION): - return (None, data) - return _UnpackOneTerm(data[1:]) - - -def _UnpackOneTerm(data): - dataLen = len(data) - - if len(data) == 0: - return (None, data) - - data0 = ord(data[0]) - - if data0 == MAGIC_SMALL_INTEGER: - n = _ReadInt1(data[1]) - return (ErlNumber(n), data[2:]) - - elif data0 == MAGIC_INTEGER: - n = _ReadSignedInt4(data[1:5]) - return (ErlNumber(n), data[5:]) - - elif data0 == MAGIC_FLOAT: - floatData = data[1:32] - try: - nullIndex = string.index(floatData, chr(0)) - floatStr = floatData[0:nullIndex] - except ValueError: - floatStr = floatData - f = string.atof(floatStr) - return (ErlNumber(f), data[32:]) - - elif data0 == MAGIC_ATOM: - atomLen = _ReadInt2(data[1:3]) - atomText = data[3:3 + atomLen] - return (ErlAtom(atomText), data[3 + atomLen:]) - - elif data0 == MAGIC_REFERENCE: - (node, remainingData) = _UnpackOneTerm(data[1:]) - id = _ReadId(remainingData[0:4]) - creation = _ReadCreation(remainingData[4]) - return (ErlRef(node, id, creation), remainingData[5:]) - - elif data0 == MAGIC_PORT: - (node, remainingData) = _UnpackOneTerm(data[1:]) - id = _ReadId(remainingData[0:4], 28) - creation = _ReadCreation(remainingData[4]) - return (ErlPort(node, id, creation), remainingData[5:]) - - elif data0 == MAGIC_PID: - (node, remainingData) = _UnpackOneTerm(data[1:]) - id = _ReadId(remainingData[0:4], 28) - serial = _ReadInt4(remainingData[4:8]) - creation = _ReadCreation(remainingData[8]) - return (ErlPid(node, id, serial, creation), remainingData[9:]) - - elif data0 == MAGIC_SMALL_TUPLE: - arity = _ReadInt1(data[1]) - (elements, remainingData) = _UnpackTermSeq(arity, data[2:]) - return (ErlTuple(elements), remainingData) - - elif data0 == MAGIC_LARGE_TUPLE: - arity = _ReadInt4(data[1:5]) - (elements, remainingData) = _UnpackTermSeq(arity, data[5:]) - return (ErlTuple(elements), remainingData) - - elif data0 == MAGIC_NIL: - return (ErlList([]), data[1:]) - - elif data0 == MAGIC_STRING: - strlen = _ReadInt2(data[1:3]) - s = data[3:3 + strlen] - return (ErlString(s), data[3 + strlen:]) - - elif data0 == MAGIC_LIST: - # get the list head - arity = _ReadInt4(data[1:5]) - (elements, remainingData) = _UnpackTermSeq(arity, data[5:]) - # now get the list tail (usually this is [] but - # for not well formed lists it may be any term). - (tail, newRemainingData) = _UnpackOneTerm(remainingData) - if tail <> []: - return (ErlImproperList(elements,tail), newRemainingData) - return (ErlList(elements), newRemainingData) - - elif data0 == MAGIC_BINARY: - binlen = _ReadInt4(data[1:5]) - s = data[5:5 + binlen] - return (ErlBinary(s), data[5 + binlen:]) - - elif data0 == MAGIC_SMALL_BIG: - n = _ReadInt1(data[1]) - sign = _ReadInt1(data[2]) - bignum = 0L - for i in range(n): - d = _ReadInt1(data[3 + n - i - 1]) - bignum = bignum * 256L + long(d) - if sign: - bignum = bignum * -1L - return (ErlNumber(bignum), data[3 + n:]) - - elif data0 == MAGIC_LARGE_BIG: - n = _ReadInt4(data[1:5]) - sign = _ReadInt1(data[5]) - bignum = 0L - for i in range(n): - d = _ReadInt1(data[6 + n - i - 1]) - bignum = bignum * 256L + long(d) - if sign: - bignum = bignum * -1L - return (ErlNumber(bignum), data[6 + n:]) - - elif data0 == MAGIC_NEW_CACHE: - index = _ReadInt1(data[1]) - atomLen = _ReadInt2(data[2:4]) - atomText = data[4:4 + atomLen] - return (ErlAtom(atomText, cache=index), data[4 + atomLen:]) - - elif data0 == MAGIC_CACHED_ATOM: - index = _ReadInt1(data[1]) - return (ErlAtom(None, cache=index), data[2:]) - - elif data0 == MAGIC_NEW_REFERENCE: - idLen = _ReadInt2(data[1:3]) - (node, remainingData) = _UnpackOneTerm(data[3:]) - nprim = 4 * idLen - creation = _ReadCreation(remainingData[0]) - remainingData = remainingData[1:] - id0 = _ReadId(remainingData[0:4]) - ids = [id0] - remainingData = remainingData[4:] - for i in range(idLen-1): - id = _ReadInt4(remainingData[0:4]) - remainingData = remainingData[4:] - ids.append(id) - return (ErlRef(node, ids, creation), remainingData) - - elif data0 == MAGIC_FUN: - freevarsLen = _ReadInt4(data[1:5]) - (pid, remainingData1) = _UnpackOneTerm(data[5:]) - (module, remainingData2) = _UnpackOneTerm(remainingData1) - (index, remainingData3) = _UnpackOneTerm(remainingData2) - (uniq, remainingData4) = _UnpackOneTerm(remainingData3) - (freeVars, remainingData5) = _UnpackTermSeq(freevarsLen,remainingData4) - print "MAGIC_FUN" - print pid - print module - print index - print uniq - print freeVars - return (ErlFun(pid, module, index, uniq, freeVars), - remainingData5) - - else: - print "Bad tag %s" % `data0` - - - return (None, data) - -def _UnpackTermSeq(numTerms, data): - seq = [] - remainingData = data - for i in range(numTerms): - (term, newRemainingData) = _UnpackOneTerm(remainingData) - seq.append(term) - remainingData = newRemainingData - return (seq, remainingData) - -def _ReadId(s, maxSignificantBits = 18): - return _ReadInt4(s) & ((1 << maxSignificantBits) - 1) - -def _ReadCreation(s): - return _ReadInt1(s) & ((1 << 2) - 1) - -def _ReadInt1(s): - return erl_common.ReadInt1(s) - -def _ReadInt2(s): - return erl_common.ReadInt2(s) - -def _ReadInt4(s): - return erl_common.ReadInt4(s) - -def _ReadSignedInt4(s): - n = erl_common.ReadInt4(s) - if n <= 0x7fffffff: - return n - else: - return -(0x100000000-n) - -### -### PACKING -### - -def TermToBinary(term): - """Pack a term to a binary. - - TERM = term - - Returns: string - Throws: \"Can't pack value of type ...\" - """ - return chr(MAGIC_VERSION) + _PackOneTerm(term) - -def _PackOneTerm(term): - if type(term) == types.StringType: - return _PackString(term) - elif type(term) == types.ListType: - return _PackList(term) - elif type(term) == types.TupleType: - return _PackTuple(term) - elif type(term) == types.LongType: - return _PackLong(term) - elif type(term) == types.FloatType: - return _PackFloat(term) - elif type(term) == types.IntType: - return _PackInt(term) - elif IsErlAtom(term): - return _PackAtom(term) - elif IsErlRef(term): - return _PackRef(term) - elif IsErlPort(term): - return _PackPort(term) - elif IsErlPid(term): - return _PackPid(term) - elif IsErlBinary(term): - return _PackBinary(term) - elif IsErlFun(term): - return _PackFun(term) - else: - print "Term=%s" % `term` - raise "Can't pack value of type %s" % `type(term)` - - -def _PackString(term): - if len(term) == 0: - return _PackList([]) - elif len(term) <= 65535: - return _PackInt1(MAGIC_STRING) + _PackInt2(len(term)) + term - else: - return _PackList(map(lambda c: ord(c), term)) - -def _PackList(term): - if len(term) == 0: - return _PackInt1(MAGIC_NIL) - else: - packedData = "" - for elem in term: - packedData = packedData + _PackOneTerm(elem) - return _PackInt1(MAGIC_LIST) + _PackInt4(len(term)) + packedData + \ - _PackList([]) - -def _PackTuple(term): - if len(term) < 256: - head = _PackInt1(MAGIC_SMALL_TUPLE) + _PackInt1(len(term)) - else: - head = _PackInt1(MAGIC_LARGE_TUPLE) + _PackInt4(len(term)) - packedData = head - for elem in term: - packedData = packedData + _PackOneTerm(elem) - return packedData - - -def _PackLong(term): - if -long(0x7fffffff) - 1 <= term <= long(0x7fffffff): - return _PackInt(term) - else: - numBytesNeeded = int(math.log(abs(term)) / math.log(256)) + 1 - if numBytesNeeded > 255: - return _PackInt1(MAGIC_LARGE_BIG) + \ - _PackInt4(numBytesNeeded) + \ - _PackLongBytes(term, numBytesNeeded) - else: - return _PackInt1(MAGIC_SMALL_BIG) + \ - _PackInt1(numBytesNeeded) + \ - _PackLongBytes(term, numBytesNeeded) - -def _PackLongBytes(term, numBytesNeeded): - if term < 0: - sign = _PackInt1(1) - else: - sign = _PackInt1(0) - bignum = abs(term) - bignumBytes = sign - for i in range(numBytesNeeded): - bignumBytes = bignumBytes + _PackInt1(bignum & 255) - bignum = bignum >> 8 - return bignumBytes - -def _PackFloat(term): - floatStr = "%.20e" % term - nullPadStr = _PackInt1(0) * (31 - len(floatStr)) - return _PackInt1(MAGIC_FLOAT) + floatStr + nullPadStr - -def _PackInt(term): - if 0 <= term < 256: - return _PackInt1(MAGIC_SMALL_INTEGER) + _PackInt1(term) - else: - return _PackInt1(MAGIC_INTEGER) + _PackInt4(term) - -def _PackAtom(term): - atomText = term.atomText - return _PackInt1(MAGIC_ATOM) + _PackInt2(len(atomText)) + atomText - -def _PackRef(term): - if type(term.id) == types.ListType: - return _PackNewReferenceExt(term) - else: - return _PackReferenceExt(term) - -def _PackNewReferenceExt(term): - node = _PackOneTerm(term.node) - creation = _PackCreation(term.creation) - id0 = _PackId(term.id[0]) - ids = id0 - for id in term.id[1:]: - ids = ids + _PackInt4(id) - return _PackInt1(MAGIC_NEW_REFERENCE) + \ - _PackInt2(len(term.id)) + \ - node + creation + ids - -def _PackReferenceExt(term): - node = _PackOneTerm(term.node) - id = _PackId(term.id) - creation = _PackCreation(term.creation) - return _PackInt1(MAGIC_REFERENCE) + node + id + creation - -def _PackPort(term): - node = _PackOneTerm(term.node) - id = _PackId(term.id, 28) - creation = _PackCreation(term.creation) - return _PackInt1(MAGIC_PORT) + node + id + creation - -def _PackPid(term): - node = _PackOneTerm(term.node) - id = _PackId(term.id, 28) - serial = _PackInt4(term.serial) - creation = _PackCreation(term.creation) - return _PackInt1(MAGIC_PID) + node + id + serial + creation - -def _PackBinary(term): - return _PackInt1(MAGIC_BINARY) + \ - _PackInt4(len(term.contents)) + \ - term.contents - -def _PackFun(term): - numFreeVars = _PackInt4(len(term.freeVars)) - pid = _PackPid(term.pid) - module = _PackAtom(term.module) - index = _PackInt(term.index) - uniq = _PackInt(term.uniq) - freeVars = "" - for freeVar in term.freeVars: - freeVars = freeVars + _PackOneTerm(freeVar) - return _PackInt4(MAGIC_FUN) + numFreeVars + \ - pid + module + index + uniq + freeVars - - -def _PackId(i, maxSignificantBits=18): - return _PackInt4(i & ((1 << maxSignificantBits) - 1)) - -def _PackCreation(i): - return _PackInt1(i & ((1 << 2) - 1)) - -def _PackInt1(i): - return erl_common.PackInt1(i) - -def _PackInt2(i): - return erl_common.PackInt2(i) - -def _PackInt4(i): - return erl_common.PackInt4(i) - diff --git a/setup.py.src b/setup.py.src deleted file mode 100755 index 237b64c..0000000 --- a/setup.py.src +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python - -from distutils.core import setup - -setup( - name='py_interface', - version='@VSN@', - description='A python-implementation of an Erlang node', - author='Tomas Abrahamsson', - author_email='tab@lysator.liu.se', - url='http://www.lysator.liu.se/~tab/erlang/py_interface/', - packages=['py_interface'], - license='GNU Library General Public License') - - diff --git a/vsn b/vsn deleted file mode 100644 index 524cb55..0000000 --- a/vsn +++ /dev/null @@ -1 +0,0 @@ -1.1.1 -- 2.11.4.GIT