started an article
This commit is contained in:
143
doc/using-libuv-with-erlang-c-node.md
Normal file
143
doc/using-libuv-with-erlang-c-node.md
Normal 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
|
||||
> it’s 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
|
||||
|
||||
Reference in New Issue
Block a user