C Nodes

## 7 C Nodes

This is an example of how to solve the example problem 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.

### 7.1 Erlang Program

From Erlang's point of view, the C node is treated like a normal Erlang node. Therefore, calling the functions `foo` and `bar` 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.

    {RegName, Node} ! Msg

The node name `Node` should be the name of the C node. If short node names are used, the plain name of the node will be `cN` where `N` 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 `c1@idril`, an example using long node names is `cnode@idril.ericsson.se`.

The registered name `RegName` 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, complex3.erl.

    -module(complex3).
    -export([foo/1, bar/1]).

    foo(X) ->
        call_cnode({foo, X}).
    bar(Y) ->
        call_cnode({bar, Y}).

    call_cnode(Msg) ->
        {any, c1@idril} ! {call, self(), Msg},
        receive
            {cnode, Result} ->
                Result
        end.

In complex4.erl. there is an example of what the Erlang code could look like when using long node names.

### 7.2 C Program

#### 7.2.1 Setting Up the Communication

Before calling any other Erl_Interface function, the memory handling must be initiated.

    erl_init(NULL, 0);

Now the C node can be initiated. If short node names are used, this is done by calling `erl_connect_init()`.

    erl_connect_init(1, "secretcookie", 0);

The first argument is the integer which is used to construct the node name. In the example the plain node name will be `c1`.
The second argument is a string defining the magic cookie.
The third argument is an integer which is used to identify a particular instance of a C node.

If long node node names are used, initiation is done by calling `erl_connect_xinit()`.

    erl_connect_xinit("idril", "cnode", "cnode@idril.ericsson.se",
                      &addr, "secretcookie", 0);

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 `in_addr` struct with the IP address of the host, and the fifth and sixth arguments are the magic cookie and instance number.

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 `erl_connect()`, which will return an open file descriptor at success.

    fd = erl_connect("e1@idril");

If the C node acts as a server, it must first create a socket (call `bind()` and `listen()`) listening to a certain port number `port`. It then publishes its name and port number with `epmd` (the Erlang port mapper daemon, see the man page for `epmd`).

    erl_publish(port);

Now the C node server can accept connections from Erlang nodes.

    fd = erl_accept(listen, &conn);

The second argument to `erl_accept` is a struct `ErlConnect` that will contain useful information when a connection has been established; for example, the name of the Erlang node.

#### 7.2.2 Sending and Receiving Messages

The C node can receive a message from Erlang by calling `erl_receive msg()`. This function reads data from the open file descriptor `fd` into a buffer and puts the result in an `ErlMessage` struct `emsg`. `ErlMessage` has a field `type` defining which kind of data was received. In this case the type of interest is `ERL_REG_SEND` which indicates that Erlang sent a message to a registered process at the C node. The actual message, an `ETERM`, will be in the `msg` field.

It is also necessary to take care of the types `ERL_ERROR` (an error occurred) and `ERL_TICK` (alive check from other node, should be ignored). Other possible types indicate process events such as link/unlink and exit.

      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) {

Since the message is an `ETERM` 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 `{Function,Arg}` determining which function to call with which argument. The result of calling the function is made into an `ETERM` struct as well and sent back to Erlang using `erl_send()`, which takes the open file descriptor, a pid and a term as arguments.

            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);

Finally, the memory allocated by the `ETERM` creating functions (including `erl_receive_msg()` must be freed.

            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);

The resulting C programs can be found in cnode_s.c (C node server, short node names), cnode_s2.c (C node server, long node names) and cnode_c.c (C node client).

### 7.3 Running the Example

1. Compile the C code, providing the paths to the Erl_Interface include files and libraries, and to the `socket` and `nsl` libraries.

In R5B and later versions of OTP, the `include` and `lib` directories are situated under `OTPROOT/lib/erl_interface-VSN`, where `OTPROOT` is the root directory of the OTP installation (`/usr/local/otp` in the example above) and `VSN` is the version of the `erl_interface` application (3.2.1 in the example above).
In R4B and earlier versions of OTP, `include` and `lib` are situated under `OTPROOT/usr`.

    >  gcc -o cserver \
    -I/usr/local/otp/lib/erl_interface-3.2.1/include \
    -L/usr/local/otp/lib/erl_interface-3.2.1/lib \
    complex.c cnode_s.c \
    -lerl_interface -lei -lsocket -lnsl

    unix> gcc -o cserver2 \
    -I/usr/local/otp/lib/erl_interface-3.2.1/include \
    -L/usr/local/otp/lib/erl_interface-3.2.1/lib \
    complex.c cnode_s2.c \
    -lerl_interface -lei -lsocket -lnsl

    unix> gcc -o cclient \
    -I/usr/local/otp/lib/erl_interface-3.2.1/include \
    -L/usr/local/otp/lib/erl_interface-3.2.1/lib \
    complex.c cnode_c.c \
    -lerl_interface -lei -lsocket -lnsl

2. Compile the Erlang code.

    unix> erl -compile complex3 complex4

3. Run the C node server example with short node names.

Start the C program `cserver` and Erlang in different windows. `cserver` 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 `e1` and must be set to use the same magic cookie as the C node, `secretcookie`.

    unix> cserver 3456

    unix> erl -sname e1 -setcookie secretcookie
    Erlang (BEAM) emulator version 4.9.1.2

    Eshell V4.9.1.2  (abort with ^G)
    (e1@idril)1> complex3:foo(3).
    4
    (e1@idril)2> complex3:bar(5).
    10

4. Run the C node client example. Terminate `cserver` but not Erlang and start `cclient`. The Erlang node must be started before the C node client is.

    unix> cclient

    (e1@idril)3> complex3:foo(3).
    4
    (e1@idril)4> complex3:bar(5).
    10

5. Run the C node server, long node names, example.

    unix> cserver2 3456

    unix> erl -name e1 -setcookie secretcookie
    Erlang (BEAM) emulator version 4.9.1.2

    Eshell V4.9.1.2  (abort with ^G)
    (e1@idril.du.uab.ericsson.se)1> complex4:foo(3).
    4
    (e1@idril.du.uab.ericsson.se)2> complex4:bar(5).
    10

Copyright © 1991-2006 Ericsson AB