diff options
Diffstat (limited to 'system/doc/tutorial/cnode.xmlsrc')
-rw-r--r-- | system/doc/tutorial/cnode.xmlsrc | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/system/doc/tutorial/cnode.xmlsrc b/system/doc/tutorial/cnode.xmlsrc new file mode 100644 index 0000000000..a5443104de --- /dev/null +++ b/system/doc/tutorial/cnode.xmlsrc @@ -0,0 +1,189 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>C Nodes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>cnode.xml</file> + </header> + <p>This is an example of how to solve the <seealso marker="example">example problem</seealso> by using a C node. Note that a C node would not typically be used for solving a simple problem like this, a port would suffice.</p> + + <section> + <title>Erlang Program</title> + <p>From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions <c>foo</c> and <c>bar</c> only involves sending a message to the C node asking for the function to be called, and receiving the result. Sending a message requires a recipient; a process which can be defined using either a pid or a tuple consisting of a registered name and a node name. In this case a tuple is the only alternative as no pid is known.</p> + <pre> +{RegName, Node} ! Msg</pre> + <p>The node name <c>Node</c> should be the name of the C node. If short node names are used, the plain name of the node will be <c>cN</c> where <c>N</c> is an integer. If long node names are used, there is no such restriction. An example of a C node name using short node names is thus <c>c1@idril</c>, an example using long node names is <c>[email protected]</c>.</p> + <p>The registered name <c>RegName</c> could be any atom. The name can be ignored by the C code, or it could be used for example to distinguish between different types of messages. Below is an example of what the Erlang code could look like when using short node names. + </p> + <codeinclude file="complex3.erl" tag="" type="erl"></codeinclude> + <p> + When using long node names the code is slightly different as shown in the following example: + </p> + <codeinclude file="complex4.erl" tag="" type="erl"></codeinclude> + + </section> + + <section> + <title>C Program</title> + + <section> + <title>Setting Up the Communication</title> + <p>Before calling any other Erl_Interface function, the memory handling must be initiated.</p> + <pre> +erl_init(NULL, 0);</pre> + <p>Now the C node can be initiated. If short node names are used, this is done by calling <c>erl_connect_init()</c>.</p> + <pre> +erl_connect_init(1, "secretcookie", 0);</pre> + <p>The first argument is the integer which is used to construct the node name. In the example the plain node name will be <c>c1</c>. <br></br> + + The second argument is a string defining the magic cookie. <br></br> + + The third argument is an integer which is used to identify a particular instance of a C node.</p> + <p>If long node node names are used, initiation is done by calling <c>erl_connect_xinit()</c>.</p> + <pre> +erl_connect_xinit("idril", "cnode", "[email protected]", + &addr, "secretcookie", 0);</pre> + <p>The first three arguments are the host name, the plain node name, and the full node name. The fourth argument is a pointer to an <c>in_addr</c> struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.</p> + <p>The C node can act as a server or a client when setting up the communication Erlang-C. If it acts as a client, it connects to an Erlang node by calling <c>erl_connect()</c>, which will return an open file descriptor at success.</p> + <pre> +fd = erl_connect("e1@idril");</pre> + <p>If the C node acts as a server, it must first create a socket (call <c>bind()</c> and <c>listen()</c>) listening to a certain port number <c>port</c>. It then publishes its name and port number with <c>epmd</c> (the Erlang port mapper daemon, see the man page for <c>epmd</c>).</p> + <pre> +erl_publish(port);</pre> + <p>Now the C node server can accept connections from Erlang nodes.</p> + <pre> +fd = erl_accept(listen, &conn);</pre> + <p>The second argument to <c>erl_accept</c> is a struct <c>ErlConnect</c> that will contain useful information when a connection has been established; for example, the name of the Erlang node.</p> + </section> + + <section> + <title>Sending and Receiving Messages</title> + <p>The C node can receive a message from Erlang by calling <c>erl_receive msg()</c>. This function reads data from the open file descriptor <c>fd</c> into a buffer and puts the result in an <c>ErlMessage</c> struct <c>emsg</c>. <c>ErlMessage</c> has a field <c>type</c> defining which kind of data was received. In this case the type of interest is <c>ERL_REG_SEND</c> which indicates that Erlang sent a message to a registered process at the C node. The actual message, an <c>ETERM</c>, will be in the <c>msg</c> field.</p> + <p>It is also necessary to take care of the types <c>ERL_ERROR</c> (an error occurred) and <c>ERL_TICK</c> (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.</p> + <pre> + while (loop) { + + got = erl_receive_msg(fd, buf, BUFSIZE, &emsg); + if (got == ERL_TICK) { + /* ignore */ + } else if (got == ERL_ERROR) { + loop = 0; /* exit while loop */ + } else { + if (emsg.type == ERL_REG_SEND) {</pre> + <p>Since the message is an <c>ETERM</c> struct, Erl_Interface functions can be used to manipulate it. In this case, the message will be a 3-tuple (because that was how the Erlang code was written, see above). The second element will be the pid of the caller and the third element will be the tuple <c>{Function,Arg}</c> determining which function to call with which argument. The result of calling the function is made into an <c>ETERM</c> struct as well and sent back to Erlang using <c>erl_send()</c>, which takes the open file descriptor, a pid and a term as arguments.</p> + <pre> + fromp = erl_element(2, emsg.msg); + tuplep = erl_element(3, emsg.msg); + fnp = erl_element(1, tuplep); + argp = erl_element(2, tuplep); + + if (strncmp(ERL_ATOM_PTR(fnp), "foo", 3) == 0) { + res = foo(ERL_INT_VALUE(argp)); + } else if (strncmp(ERL_ATOM_PTR(fnp), "bar", 3) == 0) { + res = bar(ERL_INT_VALUE(argp)); + } + + resp = erl_format("{cnode, ~i}", res); + erl_send(fd, fromp, resp);</pre> + <p>Finally, the memory allocated by the <c>ETERM</c> creating functions (including <c>erl_receive_msg()</c> must be freed.</p> + <pre> + erl_free_term(emsg.from); erl_free_term(emsg.msg); + erl_free_term(fromp); erl_free_term(tuplep); + erl_free_term(fnp); erl_free_term(argp); + erl_free_term(resp);</pre> + <p>The resulting C programs can be found in looks like the following examples. First a C node server using short node names.</p> + <codeinclude file="cnode_s.c" type="c"/> + <p>Below follows a C node server using long node names.</p> + <codeinclude file="cnode_s2.c" type="c"/> + <p>And finally we have the code for the C node client.</p> + <codeinclude file="cnode_c.c" type="c"/> + </section> + </section> + + <section> + <title>Running the Example</title> + <p>1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the <c>socket</c> and <c>nsl</c> libraries.</p> + <p>In R5B and later versions of OTP, the <c>include</c> and <c>lib</c> directories are situated under <c>OTPROOT/lib/erl_interface-VSN</c>, where <c>OTPROOT</c> is the root directory of the OTP installation (<c>/usr/local/otp</c> in the example above) and <c>VSN</c> is the version of the <c>erl_interface</c> application (3.2.1 in the example above). <br></br> + + In R4B and earlier versions of OTP, <c>include</c> and <c>lib</c> are situated under <c>OTPROOT/usr</c>.</p> + <pre> + +> <input>gcc -o cserver \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_s.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input> + +unix> <input>gcc -o cserver2 \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_s2.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input> + +unix> <input>gcc -o cclient \\ </input> +<input>-I/usr/local/otp/lib/erl_interface-3.2.1/include \\ </input> +<input>-L/usr/local/otp/lib/erl_interface-3.2.1/lib \\ </input> +<input>complex.c cnode_c.c \\ </input> +<input>-lerl_interface -lei -lsocket -lnsl</input></pre> + <p>2. Compile the Erlang code.</p> + <pre> +unix> <input>erl -compile complex3 complex4</input></pre> + <p>3. Run the C node server example with short node names.</p> + <p>Start the C program <c>cserver</c> and Erlang in different windows. <c>cserver</c> takes a port number as argument and must be started before trying to call the Erlang functions. The Erlang node should be given the short name <c>e1</c> and must be set to use the same magic cookie as the C node, <c>secretcookie</c>.</p> + <pre> +unix> <input>cserver 3456</input> + +unix> <input>erl -sname e1 -setcookie secretcookie</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +(e1@idril)1> <input>complex3:foo(3).</input> +4 +(e1@idril)2> <input>complex3:bar(5).</input> +10</pre> + <p>4. Run the C node client example. Terminate <c>cserver</c> but not Erlang and start <c>cclient</c>. The Erlang node must be started before the C node client is.</p> + <pre> +unix> <input>cclient</input> + +(e1@idril)3> <input>complex3:foo(3).</input> +4 +(e1@idril)4> <input>complex3:bar(5).</input> +10</pre> + <p>5. Run the C node server, long node names, example.</p> + <pre> +unix> <input>cserver2 3456</input> + +unix> <input>erl -name e1 -setcookie secretcookie</input> +Erlang (BEAM) emulator version 4.9.1.2 + +Eshell V4.9.1.2 (abort with ^G) +([email protected])1> <input>complex4:foo(3).</input> +4 +([email protected])2> <input>complex4:bar(5).</input> +10</pre> + </section> +</chapter> + |