├── CREDITS ├── EXPERIMENTAL ├── tests ├── pong.erl └── ping.php ├── INSTALL ├── LICENSE ├── README.md ├── config.m4 ├── manual ├── index.html ├── peb-close.html ├── peb-error.html ├── peb-errno.html ├── peb-connect.html ├── peb-linkinfo.html ├── peb-pconnect.html ├── peb-send-byname.html ├── peb-decode.html ├── peb-receive.html ├── peb-send-bypid.html └── peb-encode.html ├── php_peb.h └── peb.c /CREDITS: -------------------------------------------------------------------------------- 1 | peb 2 | York Liu 3 | Alvaro Videla -------------------------------------------------------------------------------- /EXPERIMENTAL: -------------------------------------------------------------------------------- 1 | this extension is experimental, 2 | its functions may change their names 3 | or move to extension all together 4 | so do not rely to much on them 5 | you have been warned! 6 | 7 | -------------------------------------------------------------------------------- /tests/pong.erl: -------------------------------------------------------------------------------- 1 | 2 | -module( pong ). 3 | -export( [ start/0, pong/0 ] ). 4 | 5 | start() -> 6 | Mypid = spawn( pong, pong, [ ] ), 7 | register( pong, Mypid). 8 | 9 | pong() -> 10 | receive 11 | quit -> ok; 12 | X -> 13 | io:fwrite( "Got ~p.~n", [ X ] ), 14 | pong() 15 | end. 16 | 17 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | PEB INSTALLATION 3 | 4 | 1 Download and compile peb 5 | 6 | $ wget http://mypweb.googlecode.com/files/peb-***.tar.gz 7 | $ tar xzvf peb-***.tar.gz 8 | $ cd peb-*** 9 | $ phpize 10 | $ ./configure --enable-peb 11 | $ make 12 | $ make install 13 | 14 | 2 Enable peb module in your php.ini: 15 | 16 | extension=peb.so 17 | 18 | 3 run test script in peb-****/tests 19 | 20 | 21 | -------------------------------------------------------------------------------- /tests/ping.php: -------------------------------------------------------------------------------- 1 | \r\n"; 7 | else 8 | echo "error:".peb_errorno()."
\r\nerror:".peb_error()."
\r\n"; 9 | 10 | echo "
\r\n"; 11 | echo "
\r\n"; 12 | 13 | peb_status(); 14 | echo "
\r\n"; 15 | echo "
\r\n"; 16 | 17 | $x = peb_vencode("[~a,~a]", array( 18 | array( "hello", "friend" ) 19 | ) 20 | ); 21 | 22 | echo "msg resource :".$x."\r\n"; 23 | 24 | echo "
\r\n"; 25 | echo "
\r\n"; 26 | 27 | peb_send_byname("pong",$x,$link); 28 | echo "
\r\n"; 29 | echo "
\r\n"; 30 | 31 | //peb_close($link); You don't need to close pconnect :) 32 | 33 | ?> 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2010, York Liu . 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above 11 | copyright notice, this list of conditions and the following 12 | disclaimer in the documentation and/or other materials provided 13 | with the distribution. 14 | * Neither the name Message Systems, Inc. nor the names 15 | of its contributors may be used to endorse or promote products 16 | derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MyPeb: PHP Erlang Bridge # 2 | 3 | This project is a fork of [http://code.google.com/p/mypeb/](http://code.google.com/p/mypeb/). All future development and bug fixes will happen in this github repository. 4 | 5 | PEB (Php-Erlang Bridge) is an open-source php extension to run php as an Erlang cnode. 6 | 7 | Checkout the wiki for complete manual https://github.com/videlalvaro/mypeb/wiki 8 | 9 | ## Installation ## 10 | 11 | Run the following commands: 12 | 13 | ```bash 14 | phpize 15 | ./configure --help 16 | ./configure 17 | make 18 | make install 19 | ``` 20 | 21 | ## Note ## 22 | 23 | You can specify the location of both Erlang interface libraries and Erlang interface header files by using `--with-erlang=DIR`. The configure script will look for libraries and headers in DIR/lib and DIR/include respectively. In case libraries and headers do not share a common parent directory, use `--with-erlanglib=LIB` and `--with-erlanginc=INCLUDE` instead. 24 | 25 | For example with a default installation of Erlang from the `ESL Erlang Packages` on a Mac you can run `configure` like this: 26 | 27 | ```bash 28 | ./configure --with-erlanglib=/usr/local/lib/erlang/lib/erl_interface-3.7.11/lib/ --with-erlanginc=/usr/local/lib/erlang/lib/erl_interface-3.7.11/include/ 29 | ``` 30 | Usage example: 31 | 32 | ```php 33 | $msg = peb_vencode('[~p,~a]', array( array($link,'getinfo') ) ); //The sender must include a reply address. use ~p to format a link identifier to a valid Erlang pid. 34 | 35 | peb_send_byname('pong',$msg,$link); 36 | 37 | $message = peb_receive($link); $rs= peb_vdecode( $message) ; print_r($rs); 38 | 39 | $serverpid = $rs[0][0]; 40 | 41 | $message = peb_vencode('[~s]', array( array('how are you') ) ); peb_send_bypid($serverpid,$message,$link); //just demo for how to use peb_send_bypid 42 | 43 | peb_close($link); ?> 44 | ``` 45 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension peb 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | dnl PHP_ARG_WITH(peb, for peb support, 11 | dnl Make sure that the comment is aligned: 12 | dnl [ --with-peb Include peb support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | PHP_ARG_ENABLE(peb, [whether to enable php-erlang bridge support], 17 | [AS_HELP_STRING([--enable-peb], [Enable php-erlang bridge support])]) 18 | 19 | if test "$PHP_PEB" = "yes"; then 20 | 21 | PHP_ARG_WITH([erlang], 22 | [for Erlang interface directory], 23 | [AS_HELP_STRING([--with-erlang], 24 | [Path to Erlang dev directory containing lib and include])], no, no) 25 | PHP_ARG_WITH([erlanglib], 26 | [for Erlang interface libs], 27 | [AS_HELP_STRING([--with-erlanglib=DIR], 28 | [Look for Erlang interface library in DIR])], no, no) 29 | PHP_ARG_WITH([erlanginc], 30 | [for Erlang interface includes], 31 | [AS_HELP_STRING([--with-erlanginc=DIR], 32 | [Look for Erlang interface headers in IDR])], no, no) 33 | 34 | if test "${PHP_ERLANG}" != "no"; then 35 | PHP_ADD_INCLUDE("${PHP_ERLANG}/include") 36 | erlang_libdir="${PHP_ERLANG}/lib" 37 | else 38 | if test "${PHP_ERLANGLIB}" != "no"; then 39 | erlang_libdir="${PHP_ERLANGLIB}" 40 | fi 41 | if test "$PHP_ERLANGINC" != "no"; then 42 | PHP_ADD_INCLUDE("${PHP_ERLANGINC}") 43 | fi 44 | fi 45 | 46 | if test -z "${erlang_libdir}"; then 47 | PHP_ADD_LIBRARY(ei) 48 | PHP_ADD_LIBRARY(erl_interface) 49 | else 50 | PHP_ADD_LIBRARY_WITH_PATH(ei, "${erlang_libdir}") 51 | PHP_ADD_LIBRARY_WITH_PATH(erl_interface, "${erlang_libdir}") 52 | fi 53 | 54 | CPPFLAGS="${CPPFLAGS} ${INCLUDES}" 55 | 56 | AC_CHECK_LIB([pthread], [pthread_mutex_trylock], [], 57 | [AC_MSG_ERROR([Could not find libpthread])]) 58 | AC_CHECK_LIB([ei], [ei_connect_init], [], 59 | [AC_MSG_ERROR([Could not find libei])]) 60 | AC_CHECK_LIB([erl_interface], [erl_connect], [], 61 | [AC_MSG_ERROR([Could not find liberl_interface])]) 62 | AC_CHECK_HEADER([erl_interface.h], [], 63 | [AC_MSG_ERROR([Could not find header file erl_interface.h])]) 64 | AC_CHECK_HEADER([ei.h], [], 65 | [AC_MSG_ERROR([Could not find header file ei.h])]) 66 | 67 | PHP_ADD_LIBRARY(ei, 1, PEB_SHARED_LIBADD) 68 | PHP_NEW_EXTENSION(peb, peb.c , $ext_shared) 69 | PHP_SUBST(PEB_SHARED_LIBADD) 70 | 71 | fi 72 | -------------------------------------------------------------------------------- /manual/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | peb function reference 6 | 7 | 8 | 9 |
10 |
11 |

peb function reference

12 |

peb is an open-source php extension to run php as an Erlang cnode. 13 | 14 | It's similar to the traditional php mysql function , you can communicate with Erlang node easy. 15 |

16 | 17 |
18 | 19 |
20 |

21 |

35 |

36 |
37 | 38 | 39 |
40 | 41 | 42 | -------------------------------------------------------------------------------- /manual/peb-close.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Close Erlang node connection 6 | 7 | 8 | 9 |
10 |
11 |

peb_close

12 |

peb_closeClose Erlang node connection

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | bool peb_close 20 | ([ resource $link_identifier 21 | ] )
22 | 23 |

24 | peb_close() closes the non-persistent connection to 25 | the Erlang node that's associated with the specified link identifier. If 26 | link_identifier 27 | isn't specified, the last opened 28 | link is used. 29 |

30 |
31 | 32 | 33 |
34 |

Parameters

35 |

36 |

37 | 38 |
39 | 40 | link_identifier 41 | 42 |
43 |

The Erlang node connection. If the 44 | link identifier is not specified, the last link opened by 45 | peb_connect() is assumed.

46 | 47 | 48 |
49 |

50 |

51 |
52 | 53 | 54 |
55 |

Return Values

56 |

57 | Returns TRUE on success or FALSE on failure. 58 |

59 |
60 | 61 | 62 |
63 |

Examples

64 |

65 |

66 |

Example #1 peb_close() example

67 |
68 |
69 | <?php
$link 
peb_connect('node@host.domain''secret_cookie');
if (!
$link) {
    die(
'Could not connect: ' peb_error());
}
echo 
'Connected successfully';
peb_close($link);
?> 70 |
71 |
72 |
73 | 74 |

The above example will output:

75 |
76 |
77 | Connected successfully
78 | 
79 |
80 |

81 |

82 |
83 | 84 | 85 |
86 |

See Also

87 |

88 |

91 |

92 |
93 | 94 |
95 | 96 | 97 | -------------------------------------------------------------------------------- /manual/peb-error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Returns the text of the error message from previous peb operation 6 | 7 | 8 | 9 |
10 |
11 |

peb_error

12 |

peb_errorReturns the text of the error message from previous peb operation

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | string peb_error 20 | ()
21 | 22 |

23 | Returns the error text from the last peb function. 24 | Note that this function only returns the 25 | error text from the most recently executed peb function (not 26 | including peb_error() and 27 | peb_errno()), so if you want to use it, make 28 | sure you check the value before calling another peb function. 29 |

30 |
31 | 32 | 33 |
34 |

Parameters

35 |

36 |

37 | 38 |
39 | 40 | None 41 | 42 |
43 |

44 |

45 |

46 |
47 | 48 | 49 |
50 |

Return Values

51 |

52 | Returns the error text from the last peb function, or 53 | '' (empty string) if no error occurred. 54 |

55 |
56 | 57 | 58 |
59 |

Examples

60 |

61 |

62 |

Example #1 peb_error() example

63 |
64 |
65 | <?php
$link 
peb_connect('node@host.domain' 'secret_cookie');
if (!
$link) {
    die(
'Could not connect: ['  66 | 67 | peb_errno() 68 | 69 | ']'  70 | 71 | peb_error() 72 | 73 | );
}
echo 
'Connected successfully';
peb_close($link);
?> 74 |
75 |
76 |
77 | 78 |

The above example will output 79 | something similar to:

80 |
81 |
 82 | Could not connect: [2] ei_connect error
 83 | 
84 |
85 |

86 |

87 |
88 | 89 | 90 |
91 |

See Also

92 |

93 |

    94 |
  • peb_errno() - Returns the numerical value of the error message from previous peb operation
  • 95 |

96 |

97 |
98 | 99 |
100 | 101 | 102 | -------------------------------------------------------------------------------- /manual/peb-errno.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Returns the numerical value of the error message from previous peb operation 6 | 7 | 8 | 9 |
10 |
11 |

peb_errno

12 |

peb_errnoReturns the numerical value of the error message from previous peb operation

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | int peb_errno 20 | ()
21 | 22 |

23 | Returns the error number from the last peb function. 24 |

25 |

26 | Returns the error text from the last peb function. 27 | Note that this function only returns the 28 | error text from the most recently executed peb function (not 29 | including peb_error() and 30 | peb_errno()), so if you want to use it, make 31 | sure you check the value before calling another peb function. 32 |

33 |
34 | 35 | 36 |
37 |

Parameters

38 |

39 |

40 | 41 |
42 | 43 | None 44 | 45 |
46 |

47 |

48 |

49 |
50 | 51 | 52 |
53 |

Return Values

54 |

55 | Returns the error number from the last peb function, or 56 | 0 (zero) if no error occurred. 57 |

58 |
59 | 60 | 61 |
62 |

Examples

63 |

64 |

65 |

Example #1 peb_errno() example

66 |
67 |
68 | <?php
$link 
peb_connect('node@host.domain' 'secret_cookie');
if (!
$link) {
    die(
'Could not connect: ['  69 | 70 | peb_errno() 71 | 72 | ']'  73 | 74 | peb_error() 75 | 76 | );
}
echo 
'Connected successfully';
peb_close($link);
?> 77 |
78 |
79 |
80 | 81 |

The above example will output 82 | something similar to:

83 |
84 |
 85 | Could not connect: [2] ei_connect error
 86 | 
87 |
88 |

89 |

90 |
91 | 92 | 93 |
94 |

See Also

95 |

96 |

    97 |
  • peb_error() - Returns the text of the error message from previous operation
  • 98 |

99 |

100 |
101 | 102 |
103 | 104 | 105 | -------------------------------------------------------------------------------- /manual/peb-connect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Open a connection to an Erlang node 6 | 7 | 8 | 9 | 10 |
11 |
12 |

peb_connect

13 |

peb_connectOpen a connection to an Erlang node

14 | 15 |
16 | 17 |
18 |

Description

19 |
20 | resource peb_connect 21 | ( string $server 22 | , string $cookie 23 | )
24 | 25 |

26 | Open a connection to an Erlang node. 27 |

28 |
29 | 30 | 31 |
32 |

Parameters

33 |

34 |

35 | 36 |
37 | 38 | server 39 | 40 | 41 |
42 | 43 |

44 | The Erlang node. e.g. "nodename@host.domain" 45 |

46 |
47 | 48 | 49 |
50 | 51 | cookie 52 | 53 | 54 |
55 | 56 |

57 | The cookie for communicate with this Erlang node. 58 |

59 |
60 | 61 |
62 |

63 |

64 |
65 | 66 | 67 |
68 |

Return Values

69 |

70 | Returns an Erlang node link identifier on success, or FALSE on failure. 71 |

72 |
73 | 74 | 75 | 76 |
77 |

Examples

78 |

Example #1 peb_connect() example

79 |

80 |

81 |
82 |
83 | <?php
$link 
peb_connect('node@host.domain' 'secret_cookie');
if (!
$link) {
    die(
'Could not connect: ' peb_error());
}
echo 
'Connected successfully';
peb_close($link);
?> 84 |
85 |
86 |
87 | 88 |

The above example will output:

89 |
90 |
 91 | Connected successfully
 92 | 
93 |
94 |

95 |

96 |
97 | 98 | 99 |
100 |

Notes

101 |

Note: 102 | 103 | The link to the server will be closed as soon as the execution of 104 | the script ends, unless it's closed earlier by explicitly calling 105 | peb_close(). 106 |
107 |

108 |
109 | 110 | 111 |
112 |

See Also

113 |

114 |

    115 |
  • peb_pconnect() - Open a persistent connection to an Erlang node
  • 116 |
  • peb_close() - Close Erlang node connection
  • 117 |

118 |

119 |
120 | 121 |
122 | 123 | 124 | -------------------------------------------------------------------------------- /manual/peb-linkinfo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Get information about the link 6 | 7 | 8 | 9 |
10 |
11 |

peb_linkinfo

12 |

peb_linkinfoGet information about the link

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | array peb_linkinfo 20 | ([ resource $link_identifier 21 | ] )
22 | 23 |

24 | Returns an array that contain detailed information about the link. 25 |

26 |
27 | 28 | 29 |
30 |

Parameters

31 |

32 |

33 | 34 |
35 | 36 | link_identifier 37 | 38 |
39 |

The Erlang node connection. If the 40 | link identifier is not specified, the last link opened by 41 | peb_connect() is assumed.

42 | 43 | 44 |
45 |

46 |

47 |
48 | 49 | 50 |
51 |

Return Values

52 |

53 | Returns information about the link on success, or FALSE on 54 | failure.

55 |
56 | 57 | 58 |
59 |

Examples

60 |

61 |

62 |

Example #1 peb_error() example

63 |
64 |
65 | <?php
$link 
peb_connect('sadly-desktop@sadly-desktop' 'secret_cookie');
if (!
$link) {
    die(
'Could not connect: ['  66 | 67 | peb_errno() 68 | 69 | ']'  70 | 71 | peb_error() 72 | 73 | );
}
74 | 75 | $ret =  
peb_linkinfo($link);
76 | 77 | print_r($ret);
78 | 79 | 80 | peb_close($link);
?> 81 |
82 |
83 |
84 | 85 |

The above example will output:

86 |
87 |
 88 | Array
 89 | (
 90 |     [thishostname] => sadly-desktop
 91 |     [thisnodename] => peb_client_8822_12@sadly-desktop
 92 |     [thisalivename] => peb_client_8822_12
 93 |     [connectcookie] => secret_cookie
 94 |     [creation] => 12
 95 |     [is_persistent] => 0
 96 | )
 97 | 
 98 | 
99 |
100 |

101 |

102 | 103 |
104 | 105 |
106 |

See Also

107 |

108 |

    109 |
  • peb_error() - Returns the text of the error message from previous peb operation
  • 110 |
  • peb_errno() - Returns the numerical value of the error message from previous peb operation
  • 111 |

112 |

113 |
114 | 115 |
116 | 117 | 118 | -------------------------------------------------------------------------------- /php_peb.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005-2010, York Liu , Alvaro Videla 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * The names of the contributors may not be used to endorse or promote products 16 | derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */ 33 | 34 | #ifndef PHP_PEB_H 35 | #define PHP_PEB_H 36 | 37 | #define PHP_PEB_EXTNAME "peb" 38 | #define PHP_PEB_VERSION "0.2" 39 | 40 | 41 | #ifdef HAVE_CONFIG_H 42 | #include "config.h" 43 | #endif 44 | 45 | #include "php.h" 46 | #include "php_ini.h" 47 | #include "ext/standard/info.h" 48 | 49 | //Erlang Libraries 50 | #include "ei.h" 51 | #include "erl_interface.h" 52 | 53 | /**************************************** 54 | Errors 55 | ****************************************/ 56 | #define PEB_ERL_ 57 | #define PEB_ERRORNO_INIT 1 58 | #define PEB_ERROR_INIT "ei_connect_init error" 59 | #define PEB_ERRORNO_CONN 2 60 | #define PEB_ERROR_CONN "ei_connect error" 61 | #define PEB_ERRORNO_SEND 3 62 | #define PEB_ERROR_SEND "ei_send error" 63 | #define PEB_ERRORNO_RECV 4 64 | #define PEB_ERROR_RECV "ei_receive error" 65 | #define PEB_ERRORNO_NOTMINE 5 66 | #define PEB_ERROR_NOTMINE "ei_receive got a message but not mine" 67 | #define PEB_ERRORNO_DECODE 6 68 | #define PEB_ERROR_DECODE "ei_decode error, unsupported data type" 69 | 70 | /**************************************** 71 | Resource names 72 | ****************************************/ 73 | #define PEB_RESOURCENAME "PHP-Erlang Bridge" 74 | #define PEB_TERMRESOURCE "Erlang Term" 75 | #define PEB_SERVERPID "Erlang Pid" 76 | 77 | #define PEB_DEFAULT_TMO 1000 78 | // #define DEBUG_PRINTF 1 79 | 80 | extern zend_module_entry peb_module_entry; 81 | #define phpext_peb_ptr &peb_module_entry 82 | 83 | #ifdef PHP_WIN32 84 | #define PHP_PEB_API __declspec(dllexport) 85 | #else 86 | #define PHP_PEB_API 87 | #endif 88 | 89 | #ifdef ZTS 90 | #include "TSRM.h" 91 | #endif 92 | 93 | PHP_MINIT_FUNCTION(peb); 94 | PHP_MSHUTDOWN_FUNCTION(peb); 95 | PHP_RINIT_FUNCTION(peb); 96 | PHP_RSHUTDOWN_FUNCTION(peb); 97 | PHP_MINFO_FUNCTION(peb); 98 | 99 | PHP_FUNCTION(peb_connect); 100 | PHP_FUNCTION(peb_pconnect); 101 | PHP_FUNCTION(peb_close); 102 | PHP_FUNCTION(peb_send_byname); 103 | PHP_FUNCTION(peb_rpc); 104 | PHP_FUNCTION(peb_rpc_to); 105 | PHP_FUNCTION(peb_send_bypid); 106 | PHP_FUNCTION(peb_receive); 107 | PHP_FUNCTION(peb_encode); 108 | PHP_FUNCTION(peb_vencode); 109 | PHP_FUNCTION(peb_decode); 110 | PHP_FUNCTION(peb_vdecode); 111 | PHP_FUNCTION(peb_error); 112 | PHP_FUNCTION(peb_errorno); 113 | 114 | PHP_FUNCTION(peb_linkinfo); 115 | 116 | PHP_FUNCTION(peb_status); 117 | 118 | PHP_FUNCTION(peb_print_term); 119 | 120 | ZEND_BEGIN_MODULE_GLOBALS(peb) 121 | // char *default_nodename; 122 | // char *default_cookie; 123 | // long default_timeout; 124 | 125 | long default_link; 126 | long num_link,num_persistent; 127 | long max_link,max_persistent; 128 | 129 | long errorno; 130 | char *error; 131 | 132 | long instanceid; 133 | ZEND_END_MODULE_GLOBALS(peb) 134 | 135 | /* In every utility function you add that needs to use variables 136 | in php_peb_globals, call TSRMLS_FETCH(); after declaring other 137 | variables used by that function, or better yet, pass in TSRMLS_CC 138 | after the last function argument and declare your utility function 139 | with TSRMLS_DC after the last declared argument. Always refer to 140 | the globals in your function as PEB_G(variable). You are 141 | encouraged to rename these macros something shorter, see 142 | examples in any other php module directory. 143 | */ 144 | 145 | #ifdef ZTS 146 | #define PEB_G(v) TSRMG(peb_globals_id, zend_peb_globals *, v) 147 | #else 148 | #define PEB_G(v) (peb_globals.v) 149 | #endif 150 | 151 | #endif /* PHP_PEB_H */ 152 | 153 | 154 | /* 155 | * Local variables: 156 | * tab-width: 4 157 | * c-basic-offset: 4 158 | * End: 159 | * vim600: noet sw=4 ts=4 fdm=marker 160 | * vim<600: noet sw=4 ts=4 161 | */ 162 | -------------------------------------------------------------------------------- /manual/peb-pconnect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Open a persistent connection to an Erlang node 6 | 7 | 8 | 9 |
10 |
11 |

peb_pconnect

12 |

peb_pconnectOpen a persistent connection to an Erlang node

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | resource peb_pconnect 20 | ( string $server 21 | , string $cookie 22 | )
23 | 24 | 25 |

26 | Establishes a persistent connection to an Erlang node. 27 |

28 | 29 |

30 | peb_pconnect() acts very much like 31 | peb_connect() with two major differences. 32 |

33 |

34 | First, when connecting, the function would first try to find a 35 | (persistent) link that's already open with the same server, 36 | cookie and creation. If one is found, an identifier for it 37 | will be returned instead of opening a new connection. 38 |

39 |

40 | Second, the connection to the Erlang node will not be closed when 41 | the execution of the script ends. Instead, the link will remain 42 | open for future use. 43 |

44 |

45 | This type of link is therefore called 'persistent'. 46 |

47 |
48 | 49 | 50 |
51 |

Parameters

52 |

53 |

54 | 55 |
56 | 57 | server 58 | 59 | 60 |
61 | 62 |

63 | The Erlang node. e.g. "nodename@host.domain" 64 |

65 |
66 | 67 | 68 |
69 | 70 | cookie 71 | 72 | 73 |
74 | 75 |

76 | The cookie for communicate with this Erlang node. 77 |

78 |
79 | 80 |
81 |

82 |

83 |
84 | 85 | 86 |
87 |

Return Values

88 |

89 | Returns an Erlang node persistent link identifier on success, or FALSE on 90 | failure. 91 |

92 |
93 | 94 | 95 | 96 |
97 |

Examples

98 |

Example #1 peb_pconnect() example

99 |

100 |

101 |
102 |
103 | <?php
$link 
peb_pconnect('node@host.domain' 'secret_cookie');
if (!
$link) {
    die(
'Could not connect: ' peb_error());
}
echo 
'Connected successfully';
?> 104 |
105 |
106 |
107 | 108 |

The above example will output:

109 |
110 |
111 | Connected successfully
112 | 
113 |
114 |

115 |

116 |
117 | 118 | 119 | 120 |
121 |

Notes

122 |

Note: 123 | 124 | Note, that these kind of links only work if you are using 125 | a module version of PHP. 126 |
127 |

128 | 129 |
130 | 131 | 132 |
133 |

See Also

134 |

135 |

    136 |
  • peb_connect() - Open a connection to an Erlang node
  • 137 | 138 |

139 |

140 |
141 | 142 |
143 | 144 | 145 | -------------------------------------------------------------------------------- /manual/peb-send-byname.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Send an Erlang message by process name 6 | 7 | 8 | 9 |
10 |
11 |

peb_send_byname

12 |

peb_send_bynameSend an Erlang message by process name

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | bool peb_send_byname 20 | ( 21 | string $registered_process_name 22 | , resource $message_identifier 23 | ,[ resource $link_identifier 24 | ] )
25 | 26 |

27 | peb_send_byname() send an Erlang message to the Erlang node 28 | that's associated with the specified link identifier. If 29 | link_identifier 30 | isn't specified, the last opened 31 | link is used. 32 |

33 |
34 | 35 | 36 |
37 |

Parameters

38 |

39 |

40 | 41 |
42 | 43 | registered_process_name 44 | 45 |
46 |

The registered process name on the Erlang node. 47 |

48 | 49 | 50 |
51 | 52 | message_identifier 53 | 54 |
55 |

An Erlang message term encoded by peb_encode(). 56 |

57 | 58 |
59 | 60 | link_identifier 61 | 62 |
63 |

The Erlang node connection. If the 64 | link identifier is not specified, the last link opened by 65 | peb_connect() is assumed. 66 |

67 | 68 | 69 |
70 |

71 |

72 |
73 | 74 | 75 |
76 |

Return Values

77 |

78 | Returns TRUE on success or FALSE on failure. 79 |

80 |
81 | 82 | 83 |
84 |

Examples

85 |

86 |

87 |

Example #1 peb_send_byname() example

88 |
89 |
90 | 91 | <?php 92 |
$link 
peb_connect('node@host.domain',  'secret_cookie'); 93 |
if (!
$link) { 94 |
    die(
'Could not connect: ' peb_error()); 95 |
} 96 |
97 |
$msg peb_encode('[~a,~a]', array( 98 |
                                   array( 
'hello''friend' ) 99 |
                                  ) 100 |
                 ); 101 |
peb_send_byname('pong',$msg,$link); 102 |
103 |
peb_close($link); 104 |
?> 
105 |
106 |
107 |
108 | 109 |

pong.erl example code

110 |
111 | 112 | 113 |
114 | -module( pong ).
115 | -export( [ start/0, pong/0 ] ).
116 | 
117 | start() ->
118 |     Mypid = spawn( pong, pong, [ ] ),
119 |     register( pong, Mypid).
120 | 
121 | pong() ->
122 |     receive
123 |         quit -> ok;
124 |         X ->
125 |             io:fwrite( "Got ~p.~n", [ X ] ),
126 |             pong()
127 |     end.
128 | 
129 |
130 |
131 |
132 |

will output (on Erlang side):

133 |
134 |
135 | Got [hello,friend].
136 | 
137 |
138 |

139 |

140 |
141 | 142 | 143 |
144 |

See Also

145 |

146 |

150 |

151 |
152 | 153 |
154 | 155 | 156 | -------------------------------------------------------------------------------- /manual/peb-decode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Decode an Erlang message term 6 | 7 | 8 | 9 | 10 |
11 |
12 |

peb_decode

13 |

peb_decodeDecode an Erlang message term

14 | 15 |
16 | 17 |
18 |

Description

19 |
20 | array peb_decode 21 | (resource $message_identifier 22 | )
23 | 24 |

25 | Encode an Erlang message term. 26 |

27 |
28 | 29 | 30 |
31 |

Parameters

32 |

33 |

34 | 35 |
36 | 37 | message_identifier 38 | 39 |
40 |

The resource identifier to an Erlang message received by 41 | peb_receive().

42 |

43 |

44 |
45 | 46 | 47 |
48 |

Return Values

49 |

50 | Returns an array that contain all data in message, or FALSE on failure. 51 |

52 |
53 | 54 | 55 | 56 |
57 |

Examples

58 |

Example #1 peb_decode() example

59 |

60 |

61 |
62 |
63 | 64 | <?php 
$link 
peb_connect('sadly-desktop@sadly-desktop',  'secret'); 
if (!
$link) { 
    die(
'Could not connect: ' peb_error()); 


$msg peb_encode('[~p,~a]', array( 
                                   array(
$link,'getinfo')
                                  ) 
                 ); 
//The sender must include a reply address.  use ~p to format a link identifier to a valid Erlang pid.

peb_send_byname('pong',$msg,$link); 

$message peb_receive($link);
$rspeb_decode$message) ;
print_r($rs);

$serverpid = $rs[0][0];

$message peb_encode('[~s]', array(
                                    array( 
'how are you')
                                   )
                      );
peb_send_bypid($serverpid,$message,$link); 
//just demo for how to use peb_send_bypid

peb_close($link); 
?> 
65 |
66 | 67 |
68 |
69 | 70 |

pong.erl example code

71 |
72 | 73 | 74 |
 75 | -module( pong ).
 76 | -export( [ start/0, pong/0 ] ).
 77 | 
 78 | start() ->
 79 |     Mypid = spawn( pong, pong, [ ] ),
 80 |     register( pong, Mypid).
 81 | 
 82 | pong() ->
 83 |     receive
 84 |         [Pid,getinfo] -> Pid! [self(),welcome],
 85 |             io:fwrite( "Got ~p.~n", [Pid] ),
 86 | 	    pong();
 87 |         quit -> ok;
 88 |         X ->
 89 |             io:fwrite( "Got ~p.~n", [ X ] ),
 90 |             pong()
 91 |     end.
 92 | 
93 |
94 |
95 |
96 | 97 |

will output (on Erlang side):

98 |
99 |
100 | Got <7160.0.0>.
101 | Got ["how are you"].
102 | 
103 | 104 |

will output (on php side):

105 |
106 |
107 | Array
108 | (
109 |     [0] => Array
110 |         (
111 |             [0] => Resource id #5
112 |             [1] => welcome
113 |         )
114 | 
115 | )
116 | 
117 | 118 | 119 |
120 |

121 |

122 |
123 | 124 | 125 |
126 |

See Also

127 |

128 |

132 |

133 |
134 | 135 |
136 | 137 | 138 | -------------------------------------------------------------------------------- /manual/peb-receive.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | receive an Erlang message from Erlang node 6 | 7 | 8 | 9 |
10 |
11 |

peb_receive

12 |

peb_receivereceive an Erlang message from Erlang node

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | resource peb_receive 20 | ([ resource $link_identifier 21 | ] )
22 | 23 |

24 | peb_receive() receive an Erlang message from the Erlang node that's associated with the specified link identifier. If 25 | link_identifier 26 | isn't specified, the last opened link is used. 27 |

28 |
29 | 30 | 31 |
32 |

Parameters

33 |

34 |

35 | 36 |
37 | 38 | link_identifier 39 | 40 |
41 |

The Erlang node connection. If the 42 | link identifier is not specified, the last link opened by 43 | peb_connect() is assumed.

44 | 45 | 46 |
47 |

48 |

49 |
50 | 51 | 52 |
53 |

Return Values

54 |

55 | Returns an Erlang message identifier on success, or FALSE on failure. 56 |

57 |
58 | 59 | 60 |
61 |

Examples

62 |

63 |

64 |

Example #1 peb_receive() example

65 |
66 |
67 | 68 | <?php 
$link 
peb_connect('sadly-desktop@sadly-desktop',  'secret'); 
if (!
$link) { 
    die(
'Could not connect: ' peb_error()); 


$msg peb_encode('[~p,~a]', array( 
                                   array(
$link,'getinfo')
                                  ) 
                 ); 
//The sender must include a reply address.  use ~p to format a link identifier to a valid Erlang pid.

peb_send_byname('pong',$msg,$link); 

$message peb_receive($link);
$rspeb_decode$message) ;
print_r($rs);

$serverpid = $rs[0][0];

$message peb_encode('[~s]', array(
                                    array( 
'how are you')
                                   )
                      );
peb_send_bypid($serverpid,$message,$link); 
//just demo for how to use peb_send_bypid

peb_close($link); 
?> 
69 |
70 |
71 |
72 | 73 |

pong.erl example code

74 |
75 | 76 | 77 |
 78 | -module( pong ).
 79 | -export( [ start/0, pong/0 ] ).
 80 | 
 81 | start() ->
 82 |     Mypid = spawn( pong, pong, [ ] ),
 83 |     register( pong, Mypid).
 84 | 
 85 | pong() ->
 86 |     receive
 87 |         [Pid,getinfo] -> Pid! [self(),welcome],
 88 |             io:fwrite( "Got ~p.~n", [Pid] ),
 89 | 	    pong();
 90 |         quit -> ok;
 91 |         X ->
 92 |             io:fwrite( "Got ~p.~n", [ X ] ),
 93 |             pong()
 94 |     end.
 95 | 
96 |
97 |
98 |
99 | 100 |

will output (on Erlang side):

101 |
102 |
103 | Got <7160.0.0>.
104 | Got ["how are you"].
105 | 
106 | 107 |

will output (on php side):

108 |
109 |
110 | Array
111 | (
112 |     [0] => Array
113 |         (
114 |             [0] => Resource id #5
115 |             [1] => welcome
116 |         )
117 | 
118 | )
119 | 
120 | 121 | 122 |
123 |

124 |

125 |
126 | 127 | 128 |
129 |

See Also

130 |

131 |

134 |

135 |
136 | 137 |
138 | 139 | 140 | -------------------------------------------------------------------------------- /manual/peb-send-bypid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Send an Erlang message by process ID 6 | 7 | 8 | 9 |
10 |
11 |

peb_send_bypid

12 |

peb_send_bypidSend an Erlang message by process ID

13 | 14 |
15 | 16 |
17 |

Description

18 |
19 | bool peb_send_bypid 20 | ( 21 | resource $process_id 22 | , resource $message_identifier 23 | ,[ resource $link_identifier 24 | ] )
25 | 26 |

27 | peb_send_bypid() send an Erlang message to the Erlang node 28 | that's associated with the specified link identifier. If 29 | link_identifier 30 | isn't specified, the last opened 31 | link is used. 32 |

33 |
34 | 35 | 36 |
37 |

Parameters

38 |

39 |

40 | 41 |
42 | 43 | process_id 44 | 45 |
46 |

The process ID on the Erlang node. 47 |

48 | 49 | 50 |
51 | 52 | message_identifier 53 | 54 |
55 |

An Erlang message term encoded by peb_encode(). 56 |

57 | 58 |
59 | 60 | link_identifier 61 | 62 |
63 |

The Erlang node connection. If the 64 | link identifier is not specified, the last link opened by 65 | peb_connect() is assumed. 66 |

67 | 68 | 69 |
70 |

71 |

72 |
73 | 74 | 75 |
76 |

Return Values

77 |

78 | Returns TRUE on success or FALSE on failure. 79 |

80 |
81 | 82 | 83 |
84 |

Examples

85 |

86 |

87 |

Example #1 peb_send_bypid() example

88 |
89 |
90 | 91 | <?php 
$link 
peb_connect('sadly-desktop@sadly-desktop',  'secret'); 
if (!
$link) { 
    die(
'Could not connect: ' peb_error()); 


$msg peb_encode('[~p,~a]', array( 
                                   array(
$link,'getinfo')
                                  ) 
                 ); 
//The sender must include a reply address.  use ~p to format a link identifier to a valid Erlang pid.

peb_send_byname('pong',$msg,$link); 

$message peb_receive($link);
$rspeb_decode$message) ;
print_r($rs);

$serverpid = $rs[0][0];

$message peb_encode('[~s]', array(
                                    array( 
'how are you')
                                   )
                      );
peb_send_bypid($serverpid,$message,$link); 
//just demo for how to use peb_send_bypid

peb_close($link); 
?> 
92 |
93 |
94 |
95 | 96 |

pong.erl example code

97 |
98 | 99 | 100 |
101 | -module( pong ).
102 | -export( [ start/0, pong/0 ] ).
103 | 
104 | start() ->
105 |     Mypid = spawn( pong, pong, [ ] ),
106 |     register( pong, Mypid).
107 | 
108 | pong() ->
109 |     receive
110 |         [Pid,getinfo] -> Pid! [self(),welcome],
111 |             io:fwrite( "Got ~p.~n", [Pid] ),
112 | 	    pong();
113 |         quit -> ok;
114 |         X ->
115 |             io:fwrite( "Got ~p.~n", [ X ] ),
116 |             pong()
117 |     end.
118 | 
119 |
120 |
121 |
122 | 123 |

will output (on Erlang side):

124 |
125 |
126 | Got <7160.0.0>.
127 | Got ["how are you"].
128 | 
129 | 130 |

will output (on php side):

131 |
132 |
133 | Array
134 | (
135 |     [0] => Array
136 |         (
137 |             [0] => Resource id #5
138 |             [1] => welcome
139 |         )
140 | 
141 | )
142 | 
143 | 144 | 145 |
146 |

147 |

148 |
149 | 150 | 151 |
152 |

See Also

153 |

154 |

158 |

159 |
160 | 161 |
162 | 163 | 164 | -------------------------------------------------------------------------------- /manual/peb-encode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Encode an Erlang message term 6 | 7 | 8 | 9 | 10 |
11 |
12 |

peb_encode

13 |

peb_encodeEncode an Erlang message term

14 | 15 |
16 | 17 |
18 |

Description

19 |
20 | resource peb_encode 21 | ( string $format_string 22 | , array $data 23 | )
24 | 25 |

26 | Encode an Erlang message term. 27 |

28 |
29 | 30 | 31 |
32 |

Parameters

33 |

34 |

35 | 36 |
37 | 38 | format_string 39 | 40 | 41 |
42 | 43 |

44 | The format string is composed of one or more directives.
45 |

 46 | 	    ~a - an atom
 47 | 	    ~s - a string
 48 | 	    ~b - a binary (contain 0x0 in string)
 49 | 	    ~i - an integer
 50 | 	    ~l - a long integer
 51 | 	    ~u - an unsigned long integer
 52 | 	    ~f - a float
 53 | 	    ~d - a double float
 54 |       ~p - a php erlang bridge (get by peb_connect)
 55 | 	    ~P - an erlang pid
 56 | 
57 |

58 |
59 | 60 |
61 | 62 | data 63 | 64 | 65 |
66 | 67 |

68 | The data to send to Erlang node. 69 | Initial wrapped with an array, tuple and list data must be wrapped with extra dimension. 70 |

71 |
72 | 73 |
74 |

75 |

76 |
77 | 78 | 79 |
80 |

Return Values

81 |

82 | Returns an Erlang message identifier on success, or FALSE on failure. 83 |

84 |
85 | 86 | 87 | 88 |
89 |

Examples

90 |

Example #1 peb_encode() example

91 |

92 |

93 |
94 |
95 | 96 | 97 | <?php 98 |
99 |
$msg 
peb_encode('~a', array( 100 |
                             
'hello' 101 |
                             
) 102 |
                  ); 103 |
//encode a simple atom 104 |
105 |
$msg peb_encode('~d', array( 106 |
                             
3.1415926 107 |
                             
) 108 |
                  ); 109 |
//encode a simple double 110 |
111 |
$msg peb_encode('[~a]', array( 112 |
                                   array(
'hello') 113 |
                               ) 114 |
                  ); 115 |
//encode a list with only one element 116 |
117 |
$msg peb_encode('[~a,~d]', array( 118 |
                                   array( 
'hello'3.1415926) 119 |
                                  ) 120 |
121 |
                  ); 122 |
//encode a list with two element 123 |
124 |
125 |
$msg peb_encode('{~a}', array( 126 |
                                   array( 
'hello') 127 |
                                  ) 128 |
                  ); 129 |
//encode a tuple with only one element 130 |
131 |
$msg peb_encode('{~a,~i}', array( 132 |
                                   array( 
'hello'1234 ) 133 |
                                  ) 134 |
                  ); 135 |
//encode a list with two element 136 |
137 |
$msg peb_encode('{~i,{~a,[~s,~d]}}', array( 138 |
                                            array( 
1234, 139 |
                                                   array(
'pi', 140 |
                                                          array(
'is',3.1415926) 141 |
                                                        ) 142 |
                                                 ) 143 |
                                            ) 144 |
                 ); 145 |
//a complex data encode  146 |
?> 
147 |
148 | 149 |
150 |
151 | 152 |

153 |

154 |
155 | 156 | 157 |
158 |

See Also

159 |

160 |

165 |

166 |
167 | 168 |
169 | 170 | 171 | -------------------------------------------------------------------------------- /peb.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2005-2010, York Liu , Alvaro Videla 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | * The names of the contributors may not be used to endorse or promote products 16 | derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | /* $Id: header,v 1.16.2.1.2.1 2007/01/01 19:32:09 iliaa Exp $ */ 33 | 34 | #include "php_peb.h" 35 | 36 | /**************************************** 37 | macros define 38 | ****************************************/ 39 | 40 | 41 | ZEND_DECLARE_MODULE_GLOBALS(peb) 42 | 43 | /* True global resources - no need for thread safety here */ 44 | static int le_link,le_plink,le_msgbuff,le_serverpid; 45 | static int fd; 46 | 47 | typedef struct _peb_link{ 48 | ei_cnode * ec; 49 | char * node; 50 | char * secret; 51 | int fd; 52 | int is_persistent; 53 | } peb_link; 54 | 55 | 56 | /* {{{ peb_functions[] 57 | * 58 | * Every user visible function must have an entry in peb_functions[]. 59 | */ 60 | zend_function_entry peb_functions[] = { 61 | PHP_FE(peb_connect, NULL) 62 | PHP_FE(peb_pconnect, NULL) 63 | PHP_FE(peb_close, NULL) 64 | PHP_FE(peb_send_byname, NULL) 65 | PHP_FE(peb_send_bypid, NULL) 66 | PHP_FE(peb_rpc, NULL) 67 | PHP_FE(peb_rpc_to, NULL) 68 | PHP_FE(peb_receive, NULL) 69 | PHP_FE(peb_vencode, NULL) 70 | PHP_FE(peb_encode, NULL) 71 | PHP_FE(peb_decode, NULL) 72 | PHP_FE(peb_vdecode, NULL) 73 | PHP_FE(peb_error, NULL) 74 | PHP_FE(peb_errorno, NULL) 75 | PHP_FE(peb_linkinfo, NULL) 76 | PHP_FE(peb_status, NULL) 77 | PHP_FE(peb_print_term, NULL) 78 | {NULL, NULL, NULL} /* Must be the last line in peb_functions[] */ 79 | }; 80 | /* }}} */ 81 | 82 | /* {{{ peb_module_entry 83 | */ 84 | zend_module_entry peb_module_entry = { 85 | #if ZEND_MODULE_API_NO >= 20010901 86 | STANDARD_MODULE_HEADER, 87 | #endif 88 | PHP_PEB_EXTNAME, 89 | peb_functions, 90 | PHP_MINIT(peb), 91 | PHP_MSHUTDOWN(peb), 92 | PHP_RINIT(peb), /* Replace with NULL if there's nothing to do at request start */ 93 | PHP_RSHUTDOWN(peb), /* Replace with NULL if there's nothing to do at request end */ 94 | PHP_MINFO(peb), 95 | #if ZEND_MODULE_API_NO >= 20010901 96 | PHP_PEB_VERSION, /* Replace with version number for your extension */ 97 | #endif 98 | STANDARD_MODULE_PROPERTIES 99 | }; 100 | /* }}} */ 101 | 102 | #ifdef COMPILE_DL_PEB 103 | ZEND_GET_MODULE(peb) 104 | #endif 105 | 106 | // /* {{{ PHP_INI 107 | // */ 108 | // 109 | // PHP_INI_BEGIN() 110 | // STD_PHP_INI_ENTRY("peb.default_nodename", "server@localhost", PHP_INI_ALL, NULL) 111 | // STD_PHP_INI_ENTRY("peb.default_cookie", "COOKIE", PHP_INI_ALL, NULL) 112 | // STD_PHP_INI_ENTRY("peb.default_timeout", "5000", PHP_INI_ALL, NULL) 113 | // PHP_INI_END() 114 | 115 | /* }}} */ 116 | 117 | 118 | /* {{{ PHP_MINIT_FUNCTION 119 | */ 120 | static ZEND_RSRC_DTOR_FUNC(le_msgbuff_dtor) 121 | { 122 | if(rsrc->ptr) { 123 | ei_x_buff * tmp = (ei_x_buff *) rsrc->ptr; 124 | ei_x_free(tmp); 125 | efree(tmp); 126 | rsrc->ptr = NULL; 127 | } 128 | } 129 | 130 | static ZEND_RSRC_DTOR_FUNC(le_serverpid_dtor) 131 | { 132 | if(rsrc->ptr) 133 | { 134 | erlang_pid * tmp= rsrc->ptr; 135 | efree(tmp); 136 | rsrc->ptr = NULL; 137 | } 138 | } 139 | 140 | static ZEND_RSRC_DTOR_FUNC(le_link_dtor) 141 | { 142 | if(rsrc->ptr) 143 | { 144 | peb_link * tmp = (peb_link *) rsrc->ptr; 145 | int p = tmp->is_persistent; 146 | 147 | pefree(tmp->ec, p); 148 | efree(tmp->node); 149 | efree(tmp->secret); 150 | 151 | #ifdef DEBUG_PRINTF 152 | php_printf("
ZEND_RSRC_DTOR_FUNC called tmo \r\n"); 153 | #endif 154 | close(tmp->fd); 155 | 156 | pefree(tmp, p); 157 | 158 | if(p) 159 | { 160 | PEB_G(num_persistent)--; 161 | } 162 | else 163 | { 164 | PEB_G(num_link)--; 165 | } 166 | 167 | rsrc->ptr = NULL; 168 | } 169 | } 170 | 171 | PHP_MINIT_FUNCTION(peb) 172 | { 173 | PEB_G(default_link) = -1; 174 | PEB_G(num_link) = 0; 175 | PEB_G(num_persistent) = 0; 176 | PEB_G(error) = NULL; 177 | PEB_G(errorno) = 0; 178 | 179 | PEB_G(instanceid) = 0; 180 | #ifdef ZTS 181 | #else 182 | #endif 183 | 184 | le_link = zend_register_list_destructors_ex(le_link_dtor,NULL,PEB_RESOURCENAME,module_number); 185 | le_plink = zend_register_list_destructors_ex(NULL,le_link_dtor,PEB_RESOURCENAME,module_number); 186 | 187 | le_msgbuff = zend_register_list_destructors_ex(le_msgbuff_dtor,NULL,PEB_TERMRESOURCE,module_number); 188 | le_serverpid = zend_register_list_destructors_ex(le_serverpid_dtor,NULL,PEB_SERVERPID,module_number); 189 | 190 | // REGISTER_INI_ENTRIES(); 191 | return SUCCESS; 192 | } 193 | /* }}} */ 194 | 195 | 196 | /* {{{ PHP_MSHUTDOWN_FUNCTION 197 | */ 198 | PHP_MSHUTDOWN_FUNCTION(peb) 199 | { 200 | 201 | #ifdef ZTS 202 | #else 203 | #endif 204 | UNREGISTER_INI_ENTRIES(); 205 | 206 | /* release all link resource here */ 207 | 208 | if(PEB_G(error)!=NULL) 209 | { 210 | efree(PEB_G(error)); 211 | } 212 | 213 | return SUCCESS; 214 | } 215 | /* }}} */ 216 | 217 | /* Remove if there's nothing to do at request start */ 218 | /* {{{ PHP_RINIT_FUNCTION 219 | */ 220 | PHP_RINIT_FUNCTION(peb) 221 | { 222 | PEB_G(default_link) = -1; 223 | PEB_G(num_link) = PEB_G(num_persistent); 224 | PEB_G(error) = NULL; 225 | PEB_G(errorno) = 0; 226 | 227 | return SUCCESS; 228 | } 229 | /* }}} */ 230 | 231 | /* Remove if there's nothing to do at request end */ 232 | /* {{{ PHP_RSHUTDOWN_FUNCTION 233 | */ 234 | PHP_RSHUTDOWN_FUNCTION(peb) 235 | { 236 | if(PEB_G(error)!=NULL) 237 | { 238 | efree(PEB_G(error)); 239 | } 240 | 241 | return SUCCESS; 242 | } 243 | /* }}} */ 244 | 245 | /* {{{ PHP_MINFO_FUNCTION 246 | */ 247 | PHP_MINFO_FUNCTION(peb) 248 | { 249 | php_info_print_table_start(); 250 | php_info_print_table_row(2, "PEB (Php-Erlang Bridge) support", "enabled"); 251 | php_info_print_table_row(2, "version", PHP_PEB_VERSION); 252 | php_info_print_table_end(); 253 | 254 | DISPLAY_INI_ENTRIES(); 255 | } 256 | /* }}} */ 257 | 258 | 259 | /* {{{ proto void peb_status() 260 | Outputs extension status information */ 261 | PHP_FUNCTION(peb_status) 262 | { 263 | php_printf("\r\n
default link: %d", (int) PEB_G(default_link)); 264 | php_printf("\r\n
num link: %d", (int) PEB_G(num_link)); 265 | php_printf("\r\n
num persistent: %d", (int) PEB_G(num_persistent)); 266 | return; 267 | } 268 | /* }}} */ 269 | 270 | /* {{{ proto array peb_linkinfo([resource link_identifier]) 271 | Returns an array that contain detailed information about the link.*/ 272 | PHP_FUNCTION(peb_linkinfo) 273 | { 274 | peb_link *m; 275 | zval * tmp; 276 | 277 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &tmp) ==FAILURE) 278 | { 279 | RETURN_FALSE; 280 | } 281 | 282 | if(ZEND_NUM_ARGS()==0) 283 | { 284 | ALLOC_INIT_ZVAL(tmp); 285 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 286 | } 287 | 288 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 289 | 290 | array_init(return_value); 291 | add_assoc_string(return_value, "thishostname", m->ec->thishostname,1); 292 | add_assoc_string(return_value, "thisnodename", m->ec->thisnodename,1); 293 | add_assoc_string(return_value, "thisalivename", m->ec->thisalivename,1); 294 | add_assoc_string(return_value, "connectcookie", m->ec->ei_connect_cookie,1); 295 | add_assoc_long(return_value, "creation", m->ec->creation); 296 | add_assoc_long(return_value, "is_persistent", m->is_persistent); 297 | 298 | } 299 | /* }}} */ 300 | 301 | 302 | static void php_peb_connect_impl(INTERNAL_FUNCTION_PARAMETERS, int persistent) 303 | { 304 | char *node=NULL, *secret=NULL; 305 | char * thisnode = NULL; 306 | char * key = NULL; 307 | int node_len, secret_len, key_len, this_len; 308 | unsigned int tmo = 0; 309 | 310 | peb_link * alink = NULL; 311 | ei_cnode * ec = NULL; 312 | zend_rsrc_list_entry * le ; 313 | zend_rsrc_list_entry * newle; 314 | 315 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"ss|l",&node,&node_len,&secret,&secret_len,&tmo)==FAILURE) 316 | { 317 | RETURN_FALSE; 318 | } 319 | 320 | #ifdef DEBUG_PRINTF 321 | php_printf("timeout :%d\n", tmo); 322 | #endif 323 | 324 | key_len = spprintf(&key, 0, "peb_%s_%s",node,secret); 325 | 326 | if(persistent) 327 | { 328 | if(SUCCESS==zend_hash_find(&EG(persistent_list), key , key_len+1, (void*)&le)) 329 | { 330 | if(Z_TYPE_P(le)==le_plink) 331 | { 332 | alink = (peb_link *) le->ptr; 333 | 334 | ZEND_REGISTER_RESOURCE(return_value, alink, le_plink); 335 | PEB_G(default_link) = Z_LVAL_P(return_value TSRMLS_CC); 336 | /* php_printf("
found a exist link(persistent) \r\n"); */ 337 | efree(key); 338 | return; 339 | } 340 | else 341 | { 342 | php_error(E_WARNING, "Hash key confilict! Given name associate with non-peb resource!"); 343 | efree(key); 344 | RETURN_FALSE; 345 | } 346 | } 347 | } 348 | 349 | ec = pemalloc(sizeof(ei_cnode),persistent); 350 | 351 | int instance; 352 | if(persistent) 353 | { 354 | instance = 0; 355 | this_len = spprintf(&thisnode, 0, "peb_client_%d_%d", getpid(), instance); 356 | } 357 | else 358 | { 359 | instance = PEB_G(instanceid)++; 360 | this_len = spprintf(&thisnode, 0, "peb_client_%d", getpid()); 361 | } 362 | 363 | // php_printf("node name:%s", thisnode); 364 | 365 | if(ei_connect_init(ec, thisnode, secret, instance) < 0) 366 | { 367 | PEB_G(errorno) = PEB_ERRORNO_INIT; 368 | PEB_G(error)=estrdup(PEB_ERROR_INIT); 369 | efree(key); 370 | efree(thisnode); 371 | pefree(ec, persistent); 372 | RETURN_FALSE 373 | } 374 | 375 | efree(thisnode); 376 | 377 | if((fd = ei_connect_tmo(ec,node, tmo)) < 0) { 378 | #ifdef DEBUG_PRINTF 379 | php_printf("error :%d\n", fd); 380 | #endif 381 | PEB_G(errorno) = PEB_ERRORNO_CONN; 382 | PEB_G(error)=estrdup(PEB_ERROR_CONN); 383 | efree(key); 384 | pefree(ec, persistent); 385 | RETURN_FALSE 386 | } 387 | 388 | alink = pemalloc(sizeof(peb_link),persistent); 389 | alink->ec = ec; 390 | alink->node = estrndup(node,node_len); 391 | alink->secret = estrndup(secret,secret_len); 392 | alink->fd = fd; 393 | alink->is_persistent = persistent; 394 | 395 | if(persistent) 396 | { 397 | PEB_G(num_link)++; 398 | PEB_G(num_persistent)++; 399 | newle = pemalloc(sizeof(zend_rsrc_list_entry),persistent); 400 | newle->ptr = alink; 401 | newle->type = le_plink; 402 | zend_hash_update(&EG(persistent_list), key, key_len+1, newle,sizeof(zend_rsrc_list_entry), NULL ); 403 | PEB_G(default_link) = Z_LVAL_P(return_value TSRMLS_CC); 404 | ZEND_REGISTER_RESOURCE(return_value, alink, le_plink); 405 | } 406 | else 407 | { 408 | PEB_G(num_link)++; 409 | ZEND_REGISTER_RESOURCE(return_value, alink, le_link); 410 | } 411 | 412 | efree(key); 413 | 414 | /* 415 | if(PEB_G(default_link) != -1) { 416 | zend_list_delete(PEB_G(default_link)); 417 | } 418 | PEB_G(default_link) = fd; 419 | zend_list_addref(fd); 420 | */ 421 | } 422 | 423 | /* {{{ proto resource peb_connect(string node_anme, string cookie [, int timeout]) 424 | Open a connection to an Erlang node. 425 | Returns the connection identifier on success or FALSE on failure */ 426 | PHP_FUNCTION(peb_connect) 427 | { 428 | PEB_G(error) = NULL; 429 | PEB_G(errorno) = 0; 430 | 431 | php_peb_connect_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 432 | } 433 | /* }}} */ 434 | 435 | /* {{{ proto resource peb_pconnect(string node_anme, string cookie [, int timeout]) 436 | Open a connection to an Erlang node. 437 | Returns the connection identifier on success or FALSE on failure */ 438 | PHP_FUNCTION(peb_pconnect) 439 | { 440 | PEB_G(error) = NULL; 441 | PEB_G(errorno) = 0; 442 | 443 | php_peb_connect_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 444 | } 445 | /* }}} */ 446 | 447 | /* {{{ proto bool peb_close([resource link_identifier]) 448 | Closes the non-persistent connection to the Erlang node that's associated with the specified link identifier. 449 | If link_identifier isn't specified, the last opened link is used. 450 | Returns TRUE on success or FALSE on failure */ 451 | PHP_FUNCTION(peb_close) 452 | { 453 | peb_link *m; 454 | zval *tmp=NULL; 455 | 456 | PEB_G(error) = NULL; 457 | PEB_G(errorno) = 0; 458 | 459 | if(ZEND_NUM_ARGS()==0) 460 | { 461 | if(PEB_G(default_link)>0) 462 | { 463 | zend_list_delete(PEB_G(default_link)); 464 | PEB_G(default_link) = -1; 465 | } 466 | RETURN_TRUE; 467 | } 468 | else 469 | { 470 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &tmp) ==FAILURE) 471 | { 472 | RETURN_FALSE; 473 | } 474 | } 475 | 476 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC, -1, PEB_RESOURCENAME, le_link, le_plink); 477 | 478 | zend_list_delete(Z_RESVAL_P(tmp)); 479 | 480 | if(Z_RESVAL_P(tmp)==PEB_G(default_link)) 481 | { 482 | PEB_G(default_link) = -1; 483 | } 484 | 485 | RETURN_TRUE; 486 | } 487 | /* }}} */ 488 | 489 | /* {{{ proto bool peb_send_byname(string registered_process_name, resource message_identifier [, resource link_identifier [, int timeout ]]) 490 | Sends an Erlang message to the Erlang node that's associated with the specified link identifier. If link_identifier isn't specified, the last opened link is used. 491 | Returns TRUE on success or FALSE on failure */ 492 | PHP_FUNCTION(peb_send_byname) 493 | { 494 | char * model_name; 495 | int m_len, ret; 496 | unsigned int tmo = 0; 497 | 498 | peb_link *m; 499 | zval * tmp=NULL; 500 | zval * msg=NULL; 501 | ei_x_buff * newbuff; 502 | 503 | PEB_G(error) = NULL; 504 | PEB_G(errorno) = 0; 505 | 506 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sr|rl", &model_name, &m_len, &msg, &tmp, &tmo) ==FAILURE) 507 | { 508 | RETURN_FALSE; 509 | } 510 | 511 | if(ZEND_NUM_ARGS()==2) 512 | { 513 | ALLOC_INIT_ZVAL(tmp); 514 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 515 | } 516 | 517 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 518 | 519 | ZEND_FETCH_RESOURCE(newbuff, ei_x_buff *, &msg TSRMLS_CC,-1 , PEB_TERMRESOURCE ,le_msgbuff); 520 | 521 | ret = ei_reg_send_tmo(m->ec, m->fd, model_name, newbuff->buff, newbuff->index, tmo); 522 | 523 | if(ret<0) 524 | { 525 | /* process peb_error here */ 526 | PEB_G(errorno) = PEB_ERRORNO_SEND; 527 | PEB_G(error)=estrdup(PEB_ERROR_SEND); 528 | RETURN_FALSE; 529 | } 530 | 531 | RETURN_TRUE; 532 | } 533 | /* }}} */ 534 | 535 | /* {{{ proto bool peb_send_bypid(resource process_id, resource message_identifier [, resource link_identifier [, int timeout ]]) 536 | Sends an Erlang message to the Erlang node that's associated with the specified link identifier. If link_identifier isn't specified, the last opened link is used. 537 | Returns TRUE on success or FALSE on failure */ 538 | PHP_FUNCTION(peb_send_bypid) 539 | { 540 | int ret; 541 | unsigned int tmo = 0; 542 | peb_link *m; 543 | zval * tmp=NULL; 544 | zval * msg=NULL; 545 | zval * pid=NULL; 546 | erlang_pid * serverpid; 547 | ei_x_buff * newbuff; 548 | 549 | PEB_G(error) = NULL; 550 | PEB_G(errorno) = 0; 551 | 552 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rr|rl",&pid,&msg, &tmp, &tmo) ==FAILURE) 553 | { 554 | RETURN_FALSE; 555 | } 556 | 557 | if(ZEND_NUM_ARGS()==1) 558 | { 559 | ALLOC_INIT_ZVAL(tmp); 560 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 561 | } 562 | 563 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 564 | ZEND_FETCH_RESOURCE(newbuff, ei_x_buff *, &msg TSRMLS_CC,-1 , PEB_TERMRESOURCE ,le_msgbuff); 565 | ZEND_FETCH_RESOURCE(serverpid, erlang_pid *, &pid TSRMLS_CC,-1 , PEB_SERVERPID ,le_serverpid); 566 | 567 | ret = ei_send_tmo( m->fd, serverpid, newbuff->buff, newbuff->index, tmo); 568 | if(ret<0) 569 | { 570 | /* process peb_error here */ 571 | PEB_G(errorno) = PEB_ERRORNO_SEND; 572 | PEB_G(error)=estrdup(PEB_ERROR_SEND); 573 | RETURN_FALSE; 574 | } 575 | 576 | RETURN_TRUE; 577 | } 578 | /* }}} */ 579 | 580 | /* {{{ proto resource peb_receive([resource link_identifier [,int timeout ]]) 581 | Recieves and Erlang message identifier from the Erlang node asociated with link_identifier and returns it on success or FALSE on failure. 582 | If link_identifier is not specified then the last opened link is used. */ 583 | PHP_FUNCTION(peb_receive) 584 | { 585 | int ret; 586 | unsigned int tmo = PEB_DEFAULT_TMO; 587 | peb_link * m; 588 | zval * tmp; 589 | ei_x_buff * newbuff; 590 | erlang_msg msg; 591 | 592 | PEB_G(error) = NULL; 593 | PEB_G(errorno) = 0; 594 | 595 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|rl", &tmp, &tmo) ==FAILURE) 596 | { 597 | RETURN_FALSE; 598 | } 599 | 600 | if(ZEND_NUM_ARGS()==0) 601 | { 602 | ALLOC_INIT_ZVAL(tmp); 603 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 604 | } 605 | 606 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 607 | 608 | newbuff =emalloc(sizeof(ei_x_buff)); 609 | ei_x_new(newbuff); 610 | 611 | while(1) 612 | { 613 | ret = ei_xreceive_msg_tmo(m->fd, &msg, newbuff,tmo); 614 | switch(ret) 615 | { 616 | case ERL_TICK: /* idle */ 617 | break; 618 | case ERL_MSG: 619 | if( msg.msgtype == ERL_SEND ) 620 | { 621 | ZEND_REGISTER_RESOURCE(return_value, newbuff, le_msgbuff); 622 | return; 623 | } 624 | else 625 | { 626 | /* php_printf("error: not erl_send\r\n"); */ 627 | PEB_G(errorno) = PEB_ERRORNO_NOTMINE; 628 | PEB_G(error)=estrdup(PEB_ERROR_NOTMINE); 629 | ei_x_free(newbuff); 630 | efree(newbuff); 631 | RETURN_FALSE; 632 | } 633 | break; 634 | default: 635 | /* php_printf("error: unknown ret %d\r\n",ret); */ 636 | PEB_G(errorno) = PEB_ERRORNO_RECV; 637 | PEB_G(error)=estrdup(PEB_ERROR_RECV); 638 | ei_x_free(newbuff); 639 | efree(newbuff); 640 | RETURN_FALSE; 641 | } 642 | } 643 | 644 | RETURN_TRUE; 645 | } 646 | /* }}} */ 647 | 648 | 649 | /** {{{ proto mixed peb_rpc(string module, string function, resource message [, resource link_identifier] ) 650 | Makes an Erlang RPC call to the Erlang node that's associated with the specified link identifier. If link_identifier isn't specified, the last opened link is used. 651 | Returns an Erlang message identifier on success, or FALSE on failure. */ 652 | PHP_FUNCTION(peb_rpc) 653 | { 654 | char * model_name; 655 | char * fun_name; 656 | int m_len, f_len, ret; 657 | 658 | peb_link *m; 659 | zval * tmp=NULL; 660 | zval * msg=NULL; 661 | ei_x_buff * newbuff; 662 | ei_x_buff * result; 663 | 664 | PEB_G(error) = NULL; 665 | PEB_G(errorno) = 0; 666 | 667 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssr|r", &model_name, &m_len, &fun_name, &f_len, &msg, &tmp) ==FAILURE) 668 | { 669 | RETURN_FALSE; 670 | } 671 | 672 | 673 | if(ZEND_NUM_ARGS()==3) 674 | { 675 | ALLOC_INIT_ZVAL(tmp); 676 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 677 | } 678 | 679 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 680 | 681 | ZEND_FETCH_RESOURCE(newbuff, ei_x_buff*, &msg TSRMLS_CC,-1 , PEB_TERMRESOURCE ,le_msgbuff); 682 | 683 | result = emalloc(sizeof(ei_x_buff)); 684 | ei_x_new(result); 685 | 686 | ret = ei_rpc(m->ec, m->fd, model_name, fun_name, newbuff->buff, newbuff->index, result); 687 | 688 | //php_printf("ei_rpc ret: %d\r\n
", ret); 689 | 690 | if(ret<0) 691 | { 692 | /* process peb_error here */ 693 | PEB_G(errorno) = PEB_ERRORNO_SEND; 694 | PEB_G(error) = estrdup(PEB_ERROR_SEND); 695 | 696 | ei_x_free(result); 697 | efree(result); 698 | RETURN_FALSE; 699 | } 700 | 701 | ZEND_REGISTER_RESOURCE(return_value, result, le_msgbuff); 702 | } 703 | /* }}} */ 704 | 705 | /* {{{ proto bool peb_rpc_to(string module, string function, resource message [, resource link_identifier]) 706 | Makes an Erlang RPC call to the Erlang node that's associated with the specified link identifier. If link_identifier isn't specified, the last opened link is used. 707 | Returns TRUE on success or FALSE on failure */ 708 | PHP_FUNCTION(peb_rpc_to) 709 | { 710 | char * model_name; 711 | char * fun_name; 712 | int m_len, f_len, ret; 713 | 714 | peb_link *m; 715 | zval * tmp=NULL; 716 | zval * msg=NULL; 717 | ei_x_buff * newbuff; 718 | 719 | PEB_G(error) = NULL; 720 | PEB_G(errorno) = 0; 721 | 722 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssr|r", &model_name, &m_len, &fun_name, &f_len, &msg, &tmp) ==FAILURE) 723 | { 724 | RETURN_FALSE; 725 | } 726 | 727 | 728 | if(ZEND_NUM_ARGS()==3) 729 | { 730 | ALLOC_INIT_ZVAL(tmp); 731 | ZVAL_RESOURCE(tmp,PEB_G(default_link)); 732 | } 733 | 734 | ZEND_FETCH_RESOURCE2(m, peb_link*, &tmp TSRMLS_CC,-1 , PEB_RESOURCENAME ,le_link, le_plink); 735 | 736 | ZEND_FETCH_RESOURCE(newbuff, ei_x_buff *, &msg TSRMLS_CC,-1 , PEB_TERMRESOURCE ,le_msgbuff); 737 | 738 | ret = ei_rpc_to(m->ec, m->fd, model_name, fun_name, newbuff->buff, newbuff->index); 739 | 740 | if(ret<0) 741 | { 742 | /* process peb_error here */ 743 | PEB_G(errorno) = PEB_ERRORNO_SEND; 744 | PEB_G(error)=estrdup(PEB_ERROR_SEND); 745 | RETURN_FALSE; 746 | } 747 | 748 | RETURN_TRUE; 749 | } 750 | /* }}} */ 751 | 752 | void _peb_encode_term(ei_x_buff* x,char **fmt,int * fmtpos, HashTable *arr, unsigned long * arridx) 753 | { 754 | char* p = *fmt + *fmtpos; 755 | int i,v; 756 | zval ** pdata; 757 | ei_x_buff * newbuff, decoded; 758 | peb_link *m; 759 | erlang_pid *ep; 760 | 761 | 762 | ++p; 763 | (*fmtpos)++; 764 | 765 | while (*p==' ') 766 | { 767 | ++p; 768 | (*fmtpos)++; 769 | } 770 | 771 | switch(*p) 772 | { 773 | case 'a': 774 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 775 | { 776 | newbuff = emalloc(sizeof(ei_x_buff)); 777 | ei_x_new(newbuff); 778 | ei_x_encode_atom(newbuff, Z_STRVAL_PP((zval**)pdata)); 779 | ei_x_append(x,newbuff); 780 | ei_x_free(newbuff); 781 | efree(newbuff); 782 | } 783 | ++(*arridx); 784 | break; 785 | case 's': 786 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 787 | { 788 | newbuff = emalloc(sizeof(ei_x_buff)); 789 | ei_x_new(newbuff); 790 | ei_x_encode_string_len(newbuff, Z_STRVAL_PP((zval**)pdata),Z_STRLEN_PP((zval**)pdata)); 791 | ei_x_append(x,newbuff); 792 | ei_x_free(newbuff); 793 | efree(newbuff); 794 | } 795 | ++(*arridx); 796 | break; 797 | case 'b': 798 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 799 | { 800 | newbuff = emalloc(sizeof(ei_x_buff)); 801 | ei_x_new(newbuff); 802 | ei_x_encode_binary(newbuff, Z_STRVAL_PP((zval**)pdata),Z_STRLEN_PP((zval**)pdata)); 803 | ei_x_append(x,newbuff); 804 | ei_x_free(newbuff); 805 | efree(newbuff); 806 | } 807 | ++(*arridx); 808 | break; 809 | case 'i': 810 | case 'l': 811 | case 'u': 812 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 813 | { 814 | newbuff = emalloc(sizeof(ei_x_buff)); 815 | ei_x_new(newbuff); 816 | ei_x_encode_long(newbuff, Z_LVAL_PP((zval**)pdata)); 817 | ei_x_append(x,newbuff); 818 | ei_x_free(newbuff); 819 | efree(newbuff); 820 | } 821 | ++(*arridx); 822 | break; 823 | case 'f': 824 | case 'd': 825 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 826 | { 827 | newbuff = emalloc(sizeof(ei_x_buff)); 828 | ei_x_new(newbuff); 829 | ei_x_encode_double(newbuff, Z_DVAL_PP((zval**)pdata)); 830 | ei_x_append(x,newbuff); 831 | ei_x_free(newbuff); 832 | efree(newbuff); 833 | } 834 | ++(*arridx); 835 | break; 836 | case 'p': 837 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 838 | { 839 | m = (peb_link*) zend_fetch_resource(pdata TSRMLS_CC,-1 , PEB_RESOURCENAME , NULL, 2, le_link, le_plink); 840 | if(m) 841 | { 842 | newbuff = emalloc(sizeof(ei_x_buff)); 843 | ei_x_new(newbuff); 844 | ei_x_encode_pid(newbuff, &(m->ec->self)); 845 | ei_x_append(x,newbuff); 846 | ei_x_free(newbuff); 847 | efree(newbuff); 848 | } 849 | } 850 | ++(*arridx); 851 | break; 852 | case 'P': 853 | if(zend_hash_index_find(arr,*arridx,(void**) &pdata)==SUCCESS) 854 | { 855 | ep = (erlang_pid*) zend_fetch_resource(pdata TSRMLS_CC,-1 , PEB_SERVERPID , NULL, 1, le_serverpid); 856 | if(ep) 857 | { 858 | newbuff = emalloc(sizeof(ei_x_buff)); 859 | ei_x_new(newbuff); 860 | ei_x_encode_pid(newbuff, ep); 861 | ei_x_append(x,newbuff); 862 | ei_x_free(newbuff); 863 | efree(newbuff); 864 | } 865 | } 866 | ++(*arridx); 867 | break; 868 | case ',': 869 | case '~': 870 | break; 871 | default: 872 | return; 873 | break; 874 | } 875 | 876 | _peb_encode_term(x,fmt,fmtpos,arr,arridx); 877 | } 878 | 879 | void _peb_encode(ei_x_buff* x, char** fmt, int fmt_len, int * fmtpos, HashTable *arr, unsigned long * arridx) 880 | { 881 | /* 882 | ~a - an atom, char* 883 | ~s - a string, char* 884 | ~b - a binary, char* 885 | ~i - an integer, int 886 | ~l - a long integer, long int 887 | ~u - an unsigned long integer, unsigned long int 888 | ~f - a float, float 889 | ~d - a double float, double float 890 | ~p - an erlang pid 891 | */ 892 | 893 | char* p = *fmt + *fmtpos; 894 | int res; 895 | unsigned long newidx=0; 896 | 897 | HashTable * newarr; 898 | zval * tmp; 899 | ei_x_buff * newbuff; 900 | 901 | // php_printf("
enter for fmtpos %d fmtstr: %c arridx: %d
\r\n\r\n", *fmtpos, *p , *arridx); 902 | 903 | while (*p==' ') 904 | { 905 | ++p; 906 | (*fmtpos)++; 907 | } 908 | 909 | // Special case, empty list. 910 | if( *p == '[' && *(p+1) == ']') 911 | { 912 | // php_printf("Inside IF: fmt_len: %d\n", fmt_len); 913 | ei_x_encode_empty_list( x ); 914 | ++p; //consume current char 915 | (*fmtpos)++; 916 | ++p; //consume ] char 917 | (*fmtpos)++; 918 | 919 | (*arridx)++; 920 | 921 | if((fmt_len - 1) <= *fmtpos) 922 | { 923 | // php_printf("\n\n\n\nfmt_len: %d fmtpos %d\n\n\n\n", fmt_len, *fmtpos); 924 | return; 925 | } 926 | _peb_encode(x,fmt,fmt_len,fmtpos,arr,arridx); 927 | } 928 | 929 | switch (*p) 930 | { 931 | case '~': 932 | _peb_encode_term(x,fmt,fmtpos,arr, arridx); 933 | break; 934 | case '[': 935 | if(zend_hash_index_find(arr,*arridx,(void**)&tmp)==SUCCESS) 936 | { 937 | newarr= Z_ARRVAL_PP((zval**)tmp); 938 | 939 | //empty list handling 940 | if(zend_hash_num_elements(newarr) == 0 && *(p+1) == '[' && *(p+2) == ']') 941 | { 942 | ei_x_encode_empty_list(x); 943 | ++p; //advance from current char 944 | (*fmtpos)++; 945 | ++p; //skip [ 946 | (*fmtpos)++; 947 | ++p; //skip ] 948 | (*fmtpos)++; 949 | (*arridx)++; 950 | break; 951 | } 952 | 953 | ++p; 954 | (*fmtpos)++; 955 | newbuff = emalloc(sizeof(ei_x_buff)); 956 | ei_x_new(newbuff); 957 | 958 | _peb_encode(newbuff, fmt, fmt_len, fmtpos, newarr,&newidx); 959 | 960 | if(newidx!=0) 961 | { 962 | /* php_printf("newidx:%d",newidx); */ 963 | ei_x_encode_list_header(x,newidx); 964 | ei_x_append(x,newbuff); 965 | ei_x_encode_empty_list(x); 966 | ei_x_free(newbuff); 967 | efree(newbuff); 968 | } 969 | else 970 | { 971 | ei_x_free(newbuff); 972 | efree(newbuff); 973 | } 974 | } 975 | (*arridx)++; 976 | break; 977 | case ']': 978 | ++p; 979 | (*fmtpos)++; 980 | return; 981 | break; 982 | case '{': 983 | if(zend_hash_index_find(arr,*arridx,(void**)&tmp)==SUCCESS) 984 | { 985 | newarr= Z_ARRVAL_PP((zval**)tmp); 986 | ++p; 987 | (*fmtpos)++; 988 | newbuff = emalloc(sizeof(ei_x_buff)); 989 | ei_x_new(newbuff); 990 | 991 | _peb_encode(newbuff, fmt, fmt_len, fmtpos, newarr,&newidx); 992 | 993 | if(newidx!=0) 994 | { 995 | /* php_printf("newidx:%d",newidx); */ 996 | ei_x_encode_tuple_header(x,newidx); 997 | ei_x_append(x,newbuff); 998 | ei_x_free(newbuff); 999 | efree(newbuff); 1000 | } 1001 | else 1002 | { 1003 | ei_x_free(newbuff); 1004 | efree(newbuff); 1005 | } 1006 | } 1007 | (*arridx)++; 1008 | break; 1009 | case '}': 1010 | ++p; 1011 | (*fmtpos)++; 1012 | return; 1013 | break; 1014 | case ',': 1015 | ++p; 1016 | (*fmtpos)++; 1017 | break; 1018 | default: 1019 | return; 1020 | break; 1021 | } 1022 | 1023 | _peb_encode(x,fmt,fmt_len,fmtpos,arr,arridx); 1024 | } 1025 | 1026 | static void php_peb_encode_impl(INTERNAL_FUNCTION_PARAMETERS, int with_version) 1027 | { 1028 | char * fmt; 1029 | int fmt_len; 1030 | int fmtpos=0; 1031 | int res; 1032 | unsigned long arridx=0; 1033 | 1034 | zval * tmp; 1035 | ei_x_buff * x; 1036 | HashTable * htable; 1037 | 1038 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa", &fmt, &fmt_len, &tmp)==FAILURE) 1039 | { 1040 | RETURN_FALSE; 1041 | } 1042 | 1043 | /* find hashtable for array */ 1044 | htable = Z_ARRVAL_P(tmp); 1045 | 1046 | x=emalloc(sizeof(ei_x_buff)); 1047 | 1048 | if(with_version) 1049 | { 1050 | ei_x_new_with_version(x); 1051 | } 1052 | else 1053 | { 1054 | ei_x_new(x); 1055 | } 1056 | 1057 | _peb_encode(x, &fmt, fmt_len, &fmtpos, htable,&arridx); 1058 | 1059 | ZEND_REGISTER_RESOURCE(return_value,x,le_msgbuff); 1060 | } 1061 | 1062 | /* {{{ proto resource peb_encode(string format_string, array data) 1063 | Encodes the PHP variables to Erlang terms according to the specified format with version number 1064 | Returns an Erlang message identifier on success, or FALSE on failure. */ 1065 | PHP_FUNCTION(peb_vencode) 1066 | { 1067 | PEB_G(error) = NULL; 1068 | PEB_G(errorno) = 0; 1069 | php_peb_encode_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1070 | } 1071 | /* }}} */ 1072 | 1073 | /* {{{ proto resource peb_encode(string format_string, array data) 1074 | Encodes the PHP variables to Erlang terms according to the specified format without version number 1075 | Returns an Erlang message identifier on success, or FALSE on failure. */ 1076 | PHP_FUNCTION(peb_encode) 1077 | { 1078 | PEB_G(error) = NULL; 1079 | PEB_G(errorno) = 0; 1080 | php_peb_encode_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1081 | } 1082 | /* }}} */ 1083 | 1084 | int _peb_decode( ei_x_buff * x ,zval * htable) { 1085 | zval * z; 1086 | int type; 1087 | int size; 1088 | char * buff; 1089 | long len; 1090 | long long_value; 1091 | double double_value; 1092 | int i; 1093 | 1094 | ALLOC_INIT_ZVAL(z); 1095 | ei_get_type( x->buff, & x->index, & type, & size ); 1096 | 1097 | switch( type ) 1098 | { 1099 | case ERL_ATOM_EXT: 1100 | buff = emalloc( size + 1 ); 1101 | ei_decode_atom( x->buff, & x->index, buff ); 1102 | buff[ size ] = '\0'; 1103 | ZVAL_STRING(z, buff, 0); 1104 | add_next_index_zval( htable, z); 1105 | break; 1106 | case ERL_STRING_EXT: 1107 | buff = emalloc( size + 1 ); 1108 | ei_decode_string( x->buff, & x->index, buff ); 1109 | buff[ size ] = '\0'; 1110 | ZVAL_STRING(z, buff, 0); 1111 | add_next_index_zval( htable, z); 1112 | break; 1113 | case ERL_BINARY_EXT: 1114 | buff = emalloc( size ); 1115 | ei_decode_binary( x->buff, & x->index, buff, & len ); 1116 | ZVAL_STRINGL(z, buff, size, 0); 1117 | add_next_index_zval( htable, z); 1118 | break; 1119 | case ERL_PID_EXT: 1120 | buff = emalloc( sizeof( erlang_pid ) ); 1121 | ei_decode_pid( x->buff, & x->index, (erlang_pid *) buff ); 1122 | ZEND_REGISTER_RESOURCE(z, buff, le_serverpid); 1123 | add_next_index_zval( htable, z); 1124 | break; 1125 | case ERL_SMALL_BIG_EXT: 1126 | case ERL_SMALL_INTEGER_EXT: 1127 | case ERL_INTEGER_EXT: 1128 | ei_decode_long( x->buff, & x->index, & long_value ); 1129 | ZVAL_LONG(z, long_value); 1130 | add_next_index_zval( htable, z); 1131 | break; 1132 | case ERL_FLOAT_EXT: 1133 | ei_decode_double( x->buff, & x->index, & double_value ); 1134 | ZVAL_DOUBLE(z, double_value); 1135 | add_next_index_zval( htable, z); 1136 | break; 1137 | case ERL_SMALL_TUPLE_EXT: 1138 | case ERL_LARGE_TUPLE_EXT: 1139 | array_init( z ); 1140 | ei_decode_tuple_header( x->buff, & x->index, & size ); 1141 | for( i = 1; i <= size; i++ ) 1142 | { 1143 | if(_peb_decode(x,z)!=SUCCESS) 1144 | { 1145 | return FAILURE; 1146 | } 1147 | } 1148 | add_next_index_zval( htable, z ); 1149 | break; 1150 | case ERL_NIL_EXT: 1151 | case ERL_LIST_EXT: 1152 | array_init( z ); 1153 | ei_decode_list_header( x->buff, & x->index, & size ); 1154 | while( size > 0 ) 1155 | { 1156 | for( i = 1; i <= size; i++ ) 1157 | { 1158 | if(_peb_decode(x,z)!=SUCCESS) 1159 | { 1160 | return FAILURE; 1161 | } 1162 | } 1163 | ei_decode_list_header( x->buff, & x->index, & size ); 1164 | } 1165 | add_next_index_zval( htable, z ); 1166 | break; 1167 | default: 1168 | php_error( E_ERROR, "unsupported data type %d", type ); 1169 | PEB_G(errorno) = PEB_ERRORNO_DECODE; 1170 | PEB_G(error)=estrdup(PEB_ERROR_DECODE); 1171 | return FAILURE; 1172 | } 1173 | 1174 | return SUCCESS; 1175 | } 1176 | 1177 | static void php_peb_decode_impl(INTERNAL_FUNCTION_PARAMETERS, int with_version) 1178 | { 1179 | int v, ret; 1180 | char atom[ MAXATOMLEN ]; 1181 | zval * tmp, * htable; 1182 | ei_x_buff * x; 1183 | 1184 | PEB_G(error) = NULL; 1185 | PEB_G(errorno) = 0; 1186 | 1187 | if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "r", & tmp ) == FAILURE ) 1188 | { 1189 | RETURN_FALSE; 1190 | } 1191 | 1192 | ZEND_FETCH_RESOURCE(x, ei_x_buff *, & tmp, -1, PEB_TERMRESOURCE, le_msgbuff); 1193 | 1194 | x->index = 0; 1195 | if(with_version) 1196 | { 1197 | ei_decode_version( x->buff, & x->index, & v ); 1198 | } 1199 | 1200 | ALLOC_INIT_ZVAL(htable); 1201 | 1202 | array_init(htable); 1203 | 1204 | ret = _peb_decode( x ,htable); 1205 | 1206 | if( ret==SUCCESS) 1207 | { 1208 | *return_value = *htable; 1209 | } 1210 | else 1211 | { 1212 | RETURN_FALSE; 1213 | } 1214 | } 1215 | 1216 | /* {{{ proto mixed peb_decode(resource msgbuffer) 1217 | Decodes and Erlang term that was send without version magic number */ 1218 | PHP_FUNCTION(peb_decode) 1219 | { 1220 | PEB_G(error) = NULL; 1221 | PEB_G(errorno) = 0; 1222 | php_peb_decode_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); 1223 | } 1224 | /* }}} */ 1225 | 1226 | 1227 | /* {{{ proto mixed peb_vdecode(resource msgbuffer) 1228 | Decodes and Erlang term that was send with version magic number */ 1229 | PHP_FUNCTION(peb_vdecode) 1230 | { 1231 | PEB_G(error) = NULL; 1232 | PEB_G(errorno) = 0; 1233 | php_peb_decode_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); 1234 | } 1235 | /* }}} */ 1236 | 1237 | /* {{{ proto int peb_error() 1238 | Returns the error message from the last peb function call that produced an error */ 1239 | PHP_FUNCTION(peb_error) 1240 | { 1241 | if(PEB_G(error)!=NULL) 1242 | { 1243 | RETURN_STRING(PEB_G(error),1); 1244 | } 1245 | } 1246 | /* }}} */ 1247 | 1248 | 1249 | /* {{{ proto int peb_errorno() 1250 | Returns the error number from the last peb function call that produced an error */ 1251 | PHP_FUNCTION(peb_errorno) 1252 | { 1253 | RETURN_LONG(PEB_G(errorno)); 1254 | } 1255 | /* }}} */ 1256 | 1257 | /* {{{ proto resource peb_print_term(resource $term [, bool $return = false]) 1258 | Prints the erlang term to the screen 1259 | If $return is set to true, then it returns the string instead of priting it */ 1260 | PHP_FUNCTION(peb_print_term) 1261 | { 1262 | char *term = NULL; 1263 | zval * msg=NULL; 1264 | ei_x_buff * newbuff; 1265 | int intp = 0; 1266 | 1267 | int ret = 0; 1268 | 1269 | if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|b", &msg, &ret) == FAILURE) 1270 | { 1271 | RETURN_FALSE; 1272 | } 1273 | 1274 | ZEND_FETCH_RESOURCE(newbuff, ei_x_buff*, &msg TSRMLS_CC,-1 ,PEB_TERMRESOURCE, le_msgbuff); 1275 | 1276 | ei_s_print_term(&term, newbuff->buff, &intp); 1277 | 1278 | // intp = NULL; 1279 | 1280 | if(ret) 1281 | { 1282 | RETVAL_STRING(term, 0); 1283 | return; 1284 | } 1285 | else 1286 | { 1287 | php_printf("%s", term); 1288 | return; 1289 | } 1290 | } 1291 | /* }}} */ 1292 | 1293 | /* }}} */ 1294 | /* The previous line is meant for vim and emacs, so it can correctly fold and 1295 | unfold functions in source code. See the corresponding marks just before 1296 | function definition, where the functions purpose is also documented. Please 1297 | follow this convention for the convenience of others editing your code. 1298 | */ 1299 | 1300 | 1301 | /* 1302 | * Local variables: 1303 | * tab-width: 4 1304 | * c-basic-offset: 4 1305 | * End: 1306 | * vim600: noet sw=4 ts=4 fdm=marker 1307 | * vim<600: noet sw=4 ts=4 1308 | */ 1309 | --------------------------------------------------------------------------------