aboutsummaryrefslogtreecommitdiffstats
path: root/system/doc/tutorial/cnode.xmlsrc
diff options
context:
space:
mode:
Diffstat (limited to 'system/doc/tutorial/cnode.xmlsrc')
-rw-r--r--system/doc/tutorial/cnode.xmlsrc189
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]",
+ &amp;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, &amp;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, &amp;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>
+