Changeset - 673882671c9a
[Not reviewed]
v0.5.0
12 5 13
Christopher Esterhuyse - 5 years ago 2020-07-28 13:37:00
christopher.esterhuyse@gmail.com
more readmes. cleaned up the examples directory and cleaned up some warnings
18 files changed with 118 insertions and 27 deletions:
0 comments (0 inline, 0 general)
Cargo.toml
Show inline comments
 
@@ -34,15 +34,17 @@ os_socketaddr = { version = "0.1.0", optional = true }
 
[dev-dependencies]
 
# test-generator = "0.3.0"
 
crossbeam-utils = "0.7.2"
 
lazy_static = "1.4.0"
 

	
 
[lib]
 
# compile target: dynamically linked library using C ABI
 
crate-type = ["cdylib"]
 
crate-type = [
 
	"rlib", # for use as a Rust dependency. 
 
	"cdylib" # for FFI use, typically C.
 
]
 

	
 
[features]
 
default = ["ffi", "session_optimization"]
 
ffi = [] # see src/ffi/mod.rs
 
ffi_pseudo_socket_api = ["ffi", "libc", "os_socketaddr"]# see src/ffi/pseudo_socket_api.rs
 
ffi_pseudo_socket_api = ["ffi", "libc", "os_socketaddr"]# see src/ffi/pseudo_socket_api.rs.
 
endpoint_logging = [] # see src/macros.rs
 
session_optimization = [] # see src/runtime/setup.rs
 
\ No newline at end of file
README.md
Show inline comments
 
# Reowolf 1.0 Implementation
 

	
 
This library provides connectors as a generalization of sockets for use in communication over the internet. This repository is one of the deliverables of the [Reowolf project](https://nlnet.nl/project/Reowolf/) funded by the NLNet foundation.
 

	
 
## Compilation instructions
 
1. Install the latest stable Rust toolchain using Rustup. See https://rustup.rs/ for further instructions.
 
1. Run `cargo build --release` to download source dependencies, and compile the library with release-level optimizations. 
 
	- The resulting dylib can be found in target/release/, to be used with the header file reowolf.h.
 
	- Note: A list of immediate ancestor dependencies is visible in Cargo.toml.
 
	- Note: Run `cargo test --release` to run unit tests with release-level optimizations.
 

	
 
## Build options
 
- `cargo build --release` produces the dylib object, exposing connector API for Rust. The C FFI is also included, and corresponds to the header file `reowolf.h`.
 
- `cargo build --release --features ffi_pseudo_socket_api` is only available on Linux, and also generates functions which comprise the pseudo-socket C FFI.
 
1. Install the latest stable Rust toolchain (`rustup install stable`) using the [rustup](https://rustup.rs/) CLI tool, available for most platforms.
 
1. Have `cargo` (the Rust language package manager) download source dependencies, and compile the library with release-level optimizations with `cargo build --release`: 
 
	- The resulting dylib can be found in `./target/release/`, to be used with the header file: `./reowolf.h`.
 
	- *Note*: A list of immediate ancestor dependencies is visible in `./Cargo.toml`.
 
	- *Note*: Run `cargo test --release` to run unit tests with release-level optimizations.
 

	
 
## Using the library
 
- The library may be used as a Rust dependency by adding it as a git dependency, i.e., by adding line `reowolf_rs = { git = "https://scm.cwi.nl/FM/reowolf" }` to downstream crate's manifest file, `Cargo.toml`.
 
- The library may be used as a dynamically-linked library using its C ABI as the cdylib written to `./target/release` when compiled with release optimizations, in combination to the header file `./reowolf.h`.
 
- When compiled on Linux, the compiled library will include definitions of pseudo-socket procedures declared in `./pseudo-socket.h` when compiled with `cargo build --release --features ffi_pseudo_socket_api`. The added functionality is only needed when requiring that connectors expose a socket-like API.
 

	
 
## Examples
 
The `examples` directory contains example usages of connectors for message passing over the internet. The programs within require that the library is compiled as a dylib (see above).
 

	
 
## Notes
 
3. Running `cbindgen > reowolf.h` from the root will overwrite the header file. (WIP) This is only necessary to update it.  
 
\ No newline at end of file
examples/README.md
Show inline comments
 
new file 100644
 
# Examples
 
This directory contains a set of programs for demonstrating the use of connectors for communications over the internet.
 

	
 
## Setting up and running
 
First, ensure that the Reowolf has been compiled, such that a dylib is present in `reowolf/target/release/`; see the parent directory for instructions on compiling the library.
 

	
 
The examples are designed to be run with the examples folder as your working directory (`reowolf/examples`), containing a local copy of the dylic. Two convenience scripts are made available for copying the library: `cpy_dll.sh` and `cpy_so.sh` for platforms Linux and Windows respectively.
 

	
 
Compiling the example programs is done using Python 3, with `python3 ./make.py`, which will crawl the example directory's children and compiling any C source files. 
 

	
 
## Groups of examples and takeaways
 
### Incremental Connector API examples
 
The examples contained within directories with names prefixed with `incremental_` demonstrate usage of the connector API. This set of examples is characterized by each example being self-contained, designed to be run in isolation. The examples are best understood when read in the order of their directories' names (from 1 onward), as they demonstrate the functionality of the connector API starting from the most (trivially) simple connectors, to more complex connectors incorporating multiple network channels and components.
 

	
 
Each example source file is prefixed by a multi-line comment, explaining what a reader is intended to take away from the example.
 

	
 
### Presentation examples
 
The examples contained within directories with names matching `pres_` are designed to accompany the Reowolf demonstration slides (inclusion here TODO).
 
Examples include interactions whose distributed sessions span multiple source files. What follows is a list of the sessions' consituent programs, along with what the session intends to demonstrate
 

	
 
1. {pres_1/amy, pres_1/bob}: Connectors can be used to transmit messages over the internet in a fashion comparable to that of UDP sockets.
 

	
 
2. {pres_1/amy, pres_2/bob}: The protocol descriptions used to configure components are loaded and parsed at runtime. Consequently, changing these descriptions can change the behavior of the system without recompiling any of the constituent programs.
 
2. {pres_3/amy, pres_3/bob}: *Atomicity*. Message exchange actions are grouped into synchronous interactions. Actions occur with observable effects IFF their interactions are well-formed, and complete successfully. For example, a put succeeds IFF its accompanying get succeeds.
 
2. {pres_3/amy, pres_4/bob}: *Nondeterminism*. Programs/components can express flexibility by providing mutually-exclusive firing patterns on their ports, as a nondeterministic choice. Which (if any) choice occurs can be determined after synchronization by inspecting the return value of `connector_sync`. Atomicity + Nondeterminism = Specialization of behavior.
 
2. {pres_5/amy, pres_5/bob}: When no synchronous interaction is found before some consituent program times out, the system RECOVERS to the synchronous state at the start of the round, allowing components to try again.
 

	
 
### Interoperability examples
 
The examples contained within directories with names matching `interop_` demonstrate the use of different APIs for communication over UDP channels. The three given programs are intended to be run together, each as its own process.
 

	
 
Each example source file is prefixed by a multi-line comment, explaining what a reader is intended to take away from the example.
 
\ No newline at end of file
examples/incr_1/amy.c
Show inline comments
 
file renamed from examples/1_minimal/amy.c to examples/incr_1/amy.c
 
/* This example demonstrates:
 
- how protocol description structures are created and destroyed
 
- how connectors are created and destroyed
 
- there are procedures allowing for debugging the states of connectors
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
examples/incr_2/amy.c
Show inline comments
 
file renamed from examples/2_runtime_pdl/amy.c to examples/incr_2/amy.c
 
/* This example demonstrates:
 
- protocol descriptions are parsed from ascii text expressed in Reowolf's protocol language, PDL
 
- protocol descriptions load their PDL at runtime; component's definitions can be changed without recompiling the main program
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
examples/incr_3/amy.c
Show inline comments
 
file renamed from examples/3_trivial_connect/amy.c to examples/incr_3/amy.c
 
/* This example demonstrates:
 
- Connectors begin in a "setup" state, which is existing with `connector_connect`
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
examples/incr_4/amy.c
Show inline comments
 
file renamed from examples/4_port_pair/amy.c to examples/incr_4/amy.c
 
/* This example demonstrates:
 
- Connectors in the setup state can add new channels by creating port pairs
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
examples/incr_5/amy.c
Show inline comments
 
file renamed from examples/5_put_get/amy.c to examples/incr_5/amy.c
 
/* This example demonstrates:
 
- After connecting, ports can exchange messages
 
- Message exchange is conducted in two phases:
 
	1. preparing with `connector_put`, `connector_get`, and
 
	2. completing with `connector_sync`.
 
	This paradigm is similar to that for sockets in non-blocking mode.
 
- The connector stores messages received during sync. they can be inspected using `connector_gotten_bytes`.
 
- Ports created using `connector_add_port_pair` behave as a synchronous channel; messages sent in one end are received at the other.
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
 
@@ -14,13 +23,13 @@ int main(int argc, char** argv) {
 
	connector_connect(c, -1);
 
	connector_print_debug(c);
 
	
 
	connector_put_bytes(c, putter, "hello", 5);
 
	connector_get(c, getter);
 
	
 
	connector_sync(c, -1);
 
	connector_sync(c, -1); // -1 means infinite timeout duration
 
	size_t msg_len;
 
	const char * msg_ptr = connector_gotten_bytes(c, getter, &msg_len);
 
	printf("Got msg `%.*s`\n", (int) msg_len, msg_ptr);
 
	
 
	
 
	protocol_description_destroy(pd);
examples/incr_6/amy.c
Show inline comments
 
file renamed from examples/6_atomic/amy.c to examples/incr_6/amy.c
 
/* This example demonstrates:
 
- Synchronized PUTs and GETs always succeed together.
 
- Attemping to put without a corresponding GET results in `connector_sync` failing at runtime.
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
 
@@ -16,13 +20,13 @@ int main(int argc, char** argv) {
 
	connector_connect(c, -1);
 
	connector_print_debug(c);
 
	
 
	printf("Let's try to put without get\n");
 
	connector_put_bytes(c, putter, "hello", 5);
 
	// connector_get(c, getter);
 
	int err = connector_sync(c, 5000);
 
	int err = connector_sync(c, 5000); // 5000 means 5000millisec timeout duration
 
	printf("Error code %d with string `%s`\n", err, reowolf_error_peek(NULL));
 
	
 
	protocol_description_destroy(pd);
 
	connector_destroy(c);
 
	free(pdl_ptr);
 
	return 0;
examples/incr_7/amy.c
Show inline comments
 
file renamed from examples/7_recovery/amy.c to examples/incr_7/amy.c
 
/* This example demonstrates:
 
- Synchronous rounds that fail result in RECOVERY; no messages are sent or received.
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
examples/incr_8/amy.c
Show inline comments
 
file renamed from examples/8_net_ports/amy.c to examples/incr_8/amy.c
 
/* This example demonstrates:
 
- Synchronous channels can span the network if created by pairs of `connector_add_net_port` calls,
 
	each binding a port to the same address, with complementary polarities.
 
- Ports created this way have two notions of polarity:
 
	- (port) Polarity in {Putter, Getter}:
 
		- Putter => resulting port can `connector_put`,
 
		- Getter => resulting port can `connector_get`,
 
	- Endpoint Polarity in {Active, Passive}:
 
		- Passive => underlying transport socket will `bind` to the given address,
 
		- Active  => underlying transport socket will `connect` to the given address,
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
 
	Arc_ProtocolDescription * pd = protocol_description_parse("", 0);
 
	char logpath[] = "./8_amy_log.txt";
 
	Connector * c = connector_new_logging(pd, logpath, sizeof(logpath)-1);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	PortId putter, getter;
 
	FfiSocketAddr addr = {{127,0,0,1}, 8000};
 
	FfiSocketAddr addr = {{127, 0, 0, 1}, 8000}; // ipv4 127.0.0.1 (localhost) transport port 8000
 
	connector_add_net_port(c, &putter, addr, Polarity_Putter, EndpointPolarity_Active);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	connector_add_net_port(c, &getter, addr, Polarity_Getter, EndpointPolarity_Passive);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	connector_connect(c, 4000);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	
 
	protocol_description_destroy(pd);
 
	connector_destroy(c);
 
	return 0;
 
}
 
\ No newline at end of file
examples/incr_9/amy.c
Show inline comments
 
file renamed from examples/9_net_self_putget/amy.c to examples/incr_9/amy.c
 
/* This example demonstrates:
 
- Once created, ports transport messages regardless of whether
 
	they were created with `connector_add_port_pair` or `connector_add_net_port`.
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 
int main(int argc, char** argv) {
 
	Arc_ProtocolDescription * pd = protocol_description_parse("", 0);
 
	char logpath[] = "./9_amy_log.txt";
 
	Connector * c = connector_new_logging(pd, logpath, sizeof(logpath)-1);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	PortId putter, getter;
 
	FfiSocketAddr addr = {{127,0,0,1}, 8000};
 
	FfiSocketAddr addr = {{127, 0, 0, 1}, 8000};
 
	connector_add_net_port(c, &putter, addr, Polarity_Putter, EndpointPolarity_Active);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	connector_add_net_port(c, &getter, addr, Polarity_Getter, EndpointPolarity_Passive);
 
	printf("Error str `%s`\n", reowolf_error_peek(NULL));
 
	
 
	connector_connect(c, 4000);
examples/interop_1_socket/main.c
Show inline comments
 
file renamed from examples/interop_socket/main.c to examples/interop_1_socket/main.c
 
/* This example demonstrates:
 
- conventional UDP socket API can be used in a connection-oriented fashion
 
    - first setup with `bind` and `connect`
 
    - henceforth communicating with connected peer using `send` and `recv` in blocking mode.
 
*/
 
#include <netinet/in.h> // definies socketaddr_in
 
#include <stdio.h>  // defines printf
 
#include <stdlib.h> // defines malloc, free
 
#include <unistd.h> // defines close
 
#include <arpa/inet.h> // defines inet_addr
 
#define BUFSIZE 512
examples/interop_2_pseudo_socket/main.c
Show inline comments
 
file renamed from examples/interop_pseudo_socket/main.c to examples/interop_2_pseudo_socket/main.c
 
/* This example demonstrates:
 
- Reowolf's pseudo-socket API mimics the API of UDP sockets
 
- This example corresponds closely with that of the socket API, differing only in:
 
    1. an added import of the pseudo-socket header file
 
    2. (pseudo-)socket operations' identifiers are prefixed with `rw_` (short for "Reowolf"). 
 
*/
 
#include <netinet/in.h> // definies socketaddr_in
 
#include <stdio.h>  // defines printf
 
#include <stdlib.h> // defines malloc, free
 
#include <unistd.h> // defines close
 
#include <arpa/inet.h> // defines inet_addr
 
#include "../../pseudo_socket.h"
examples/interop_3_connector/main.c
Show inline comments
 
file renamed from examples/interop_connector/main.c to examples/interop_3_connector/main.c
 
/* This example demonstrates:
 
- connector API can create UDP mediator components, each given a BIND and CONNECT socket address,
 
  which communicates via a returned putter and getter port pair.
 
- messages passed to the UDP mediator are forwarded as UDP datagrams into the network.
 
*/
 
#include <stdio.h>
 
#include <string.h>
 
#include "../../reowolf.h"
 

	
 
int main(int argc, char** argv) {
 
  // --- setup ---
examples/pres_1/amy.c
Show inline comments
 

	
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 

	
 
int main(int argc, char** argv) {
 
	char msgbuf[64];
 
	// ask user what message to send
 
	size_t msglen = get_user_msg(msgbuf, sizeof(msgbuf));
 

	
 
	// Create a connector, configured with our (trivial) protocol.
 
@@ -13,13 +10,13 @@ int main(int argc, char** argv) {
 
	char logpath[] = "./pres_1_amy.txt";
 
	Connector * c = connector_new_logging(pd, logpath, sizeof(logpath)-1);
 
	rw_err_peek(c);
 
	
 
	// ... with 1 outgoing network connection
 
	PortId p0;
 
	FfiSocketAddr addr = {{127,0,0,1}, 8000};
 
	FfiSocketAddr addr = {{127, 0, 0, 1}, 8000};
 
	connector_add_net_port(c, &p0, addr, Polarity_Putter, EndpointPolarity_Passive);
 
	rw_err_peek(c);
 
	
 
	// Connect with peers (5000ms timeout).
 
	connector_connect(c, 5000);
 
	rw_err_peek(c);
examples/pres_1/bob.c
Show inline comments
 

	
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 

	
 
int main(int argc, char** argv) {
 
	// Create a connector, configured with our (trivial) protocol.
 
	Arc_ProtocolDescription * pd = protocol_description_parse("", 0);
 
	char logpath[] = "./pres_1_bob.txt";
 
	Connector * c = connector_new_logging(pd, logpath, sizeof(logpath)-1);
 
	rw_err_peek(c);
examples/pres_2/bob.c
Show inline comments
 

	
 
#include "../../reowolf.h"
 
#include "../utility.c"
 

	
 

	
 
int main(int argc, char** argv) {
 
	// Create a connector, configured with a protocol defined in a file
 
	char * pdl = buffer_pdl("./eg_protocols.pdl");
 
	Arc_ProtocolDescription * pd = protocol_description_parse(pdl, strlen(pdl));
 
	char logpath[] = "./pres_2_bob.txt";
 
	Connector * c = connector_new_logging(pd, logpath, sizeof(logpath)-1);
0 comments (0 inline, 0 general)