started an article

This commit is contained in:
niamtokik
2020-06-19 16:23:43 +00:00
parent d726a6cc3b
commit 6481b1ff32

View File

@@ -0,0 +1,143 @@
# Using libuv with Erlang C-node
> libuv is a multi-platform support library with a focus on
> asynchronous I/O. It was primarily developed for use by Node.js, but
> its also used by Luvit, Julia, pyuv, and others.
Erlang is a great piece of software, with strong isolation and many
crazy features. Unfortunately, Erlang was not designed to execute
processes in other languages and to schedule the world outside of its
own universe. Some projects are already present on net, like
[`erlexec`](https://github.com/saleyn/erlexec),
[`alcove`](https://github.com/uselessd/alcove) or
[`exile`](https://github.com/akash-akya/exile) (in Elixir). Both of
these tools are good implementation and work pretty well but are not
portable. When you want to execute a process in an heterogeneous way,
you should probably use a more robust and tested library available on
the market. That why libuv is probably a great choice.
libuv offers facilities to create an event loop, support tcp and udp
sockets (useless in our case), can deal with file system events, can
spawn processes, manages thread pool and uses signal handling. Well,
seems pretty nice.
All this article was created and tested under OpenBSD-current and with
the last erlang relesease at time of writing, Erlang-R23.
## Introduction to Erlang C-node
If you are using Erlang, you should probably know Distributed Erlang,
a framework integrated with OTP to create distributed systems where an
Erlang virtual machine become a single node running multiple
processes. C-node is using the same principle but instead of running
an Erlang node, the node is coded in C. The library used to create
this relation with the remote node is called `libei` and present with
`erl_interface` module. To use this library, like any other C library,
`ei.h` must be available.
```c
#include <ei.h>
int
main(int argc, char *argv[]) {
return 0;
}
```
To compile this simple C code file, the path must be also given to the
compiler.
```
cc -L/usr/local/lib/erlang23/usr/lib \
-I/usr/local/lib/erlang23/usr/include \
-lei -o ${source}.c ${source}
```
### Connect to an Erlang node
A c-node need to be initialized with different kind of variables, like
the name of the c-node (a string), the name of the target node (a
string based on the domain name of the node), a cookie (a secret
string shared with the c-node and the erlang node), and the date of
the creation. Erlang offers
[`ei_connect_init()`](https://erlang.org/doc/man/ei_connect.html#ei_connect_init)
function to initialize `ei_cnode` data structure, called `ec` in the
following code.
When this data-structure is initialized,
[`ei_connect()`](https://erlang.org/doc/man/ei_connect.html#ei_connect)
function can be called. This function will try to reach the erlang
node and make a connection to it. At this moment in the execution
process, if a timer is created or an infinite loop is present, a
hidden node should be present on the erlang node. This can be checked
by executing `erlang:nodes(hidden)` and should return a list of the
hidden nodes connected.
Finally, the [`shutdown()`](https://man.openbsd.org/man2/shutdown.2)
and [`close()`](https://man.openbsd.org/close) functions can be called
when the c-node goes away. Both of these functions are present in the
standard C library.
```c
#include <stdio.h> // fprintf()
#include <stdlib.h>
#include <ei.h> // ei_connect_init(), ei_connect()
#include <time.h> // time()
#include <sys/socket.h> // shutdown()
#include <unistd.h> // close()
int
main(int argc, char *argv[]) {
/* name of the c-node /*
char *node_name = "";
/* erlang node name */
char *target_node;
/* cookie used to connect to erlang node */
char *cookie = "";
/* time's creation of the node */
char creation = time(NULL)+1;
/* ei_cnode structure contains node's information */
ei_cnode ec;
/* connect to erlang node with previous variable */
ei_connect_init(&ec, node_name, cookie, creation);
/* open file descriptor, a reference to the connection */
int sockfd;
sockfd = ei_connect(&ec, node_target))
if (sockfd != 0)
fprintf(stderr, "ERROR: ei_connect failed\n");
/* stop the connection */
shutdown(sockfd, 1);
/* close the socket */
close(sockfd);
return 0;
}
```
### Sending a message to an Erlang node
### Receiving a message from an Erlang node
## Introduction to libuv
# Resources
## Libuv
* http://docs.libuv.org/en/v1.x/
* https://github.com/trevnorris/libuv-examples
## Erlang
* https://erlang.org/doc/apps/erl_interface/ei_users_guide.html
* https://erlang.org/doc/apps/erl_interface/index.html
* https://github.com/erlang/otp/tree/master/lib/erl_interface/test