summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Wiger <ulf@feuerlabs.com>2016-02-24 22:51:35 +0100
committerUlf Wiger <ulf@feuerlabs.com>2016-02-24 22:51:35 +0100
commit3b6dbd2e33fc907216bbe549a7c3e176db43a41e (patch)
tree7e6ec52a9351b95be802d93b11246327bb523d62
parent4a00319e359f8e994532d2b9b9f0ee4ee802e53d (diff)
parentb3d0291216b06b01cc7975297d1219570e942e5e (diff)
downloadrvi_core-3b6dbd2e33fc907216bbe549a7c3e176db43a41e.tar.gz
Merge branch 'uw-tjamison-53177' into uw-0_5_0
-rw-r--r--BUILD.md42
-rw-r--r--INSTALL_debian.md111
-rw-r--r--INSTALL_raspbian.md102
-rw-r--r--INSTALL_ubuntu.md143
-rw-r--r--README.debian_build14
-rw-r--r--README.md80
-rw-r--r--components/dlink_bt/src/dlink_bt_rpc.erl19
-rw-r--r--components/dlink_sms/src/dlink_sms_rpc.erl25
-rw-r--r--components/dlink_tcp/src/dlink_tcp_rpc.erl58
-rw-r--r--components/dlink_tls/src/dlink_tls_rpc.erl47
-rw-r--r--components/proto_json/src/proto_json_rpc.erl13
-rw-r--r--components/proto_msgpack/src/proto_msgpack_rpc.erl10
-rw-r--r--components/service_edge/src/service_edge_rpc.erl2
-rw-r--r--doc/pdf/BUILD.pdfbin295900 -> 321970 bytes
-rw-r--r--doc/pdf/CONFIGURE.pdfbin1642409 -> 1655447 bytes
-rw-r--r--doc/pdf/rvi_certificates.pdfbin0 -> 595909 bytes
-rw-r--r--doc/pdf/rvi_fragmentation.pdfbin424532 -> 428947 bytes
-rw-r--r--doc/pdf/rvi_protocol.pdfbin1083617 -> 738301 bytes
-rw-r--r--doc/pdf/rvi_services.pdfbin1576836 -> 1667867 bytes
-rw-r--r--doc/rvi_certificates.md254
-rw-r--r--doc/rvi_fragmentation.md9
-rw-r--r--doc/rvi_protocol.md339
-rw-r--r--doc/rvi_services.md54
-rw-r--r--test/rvi_core_SUITE.erl62
24 files changed, 916 insertions, 468 deletions
diff --git a/BUILD.md b/BUILD.md
index d7367e6..0af810b 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -1,9 +1,4 @@
-<style type="text/css" media="print">
- div.pagebreak
- {
- page-break-before: always;
- }
-</style>
+<style type="text/css" media="print"> div.pb { page-break-before: always; } </style>
Copyright (C) 2014-2016, Jaguar Land Rover
This document is licensed under Creative Commons
@@ -13,8 +8,10 @@ Attribution-ShareAlike 4.0 International.
# BUILD INSTRUCTIONS FOR RVI #
-This document describes the build process for the RVI project on an
-Ubuntu 14.04 Linux machine.
+This document describes the build process from source for the RVI
+project on an Ubuntu 14.04 Linux machine. Packages are also available
+for [Ubuntu](INSTALL_ubuntu.md), [Debian](INSTALL_debian.md),
+and [Raspbian](INSTALL_raspbian.md).
Please see ```README.md``` for a general description of the project
and its structure.
@@ -43,7 +40,7 @@ Please note that the configuration process described in
----
-<div class="pagebreak"></div>
+<div class="pb"></div>
# INSTALLATION PROCESS #
@@ -54,7 +51,8 @@ Grade Linux repositories where the code resides:
sudo apt-get install git
-Also ensure that you have the latest BlueZ Linux Bluetooth headers and that g++ is installed on your system:
+Also ensure that you have the latest BlueZ Linux Bluetooth headers
+and that g++ is installed on your system:
sudo apt-get install libbluetooth-dev g++
@@ -62,22 +60,25 @@ Also ensure that you have the latest BlueZ Linux Bluetooth headers and that g++
Install Erlang 18.2, or a later version 18 release:
-Tested packages of the latest versions of Erlang can be downloaded from [packages.erlang-solutions.com](https://www.erlang-solutions.com/resources/download.html)
+Tested packages of the latest versions of Erlang can be downloaded from
+[packages.erlang-solutions.com](https://www.erlang-solutions.com/resources/download.html)
Add the following line to your /etc/apt/sources.list
deb http://packages.erlang-solutions.com/ubuntu trusty contrib
-Update and install erlang
+Update and install esl-erlang
sudo apt-get update
- sudo apt-get install erlang
+ sudo apt-get install esl-erlang
-**If you receive an authentication error** (such as NO_PUBKEY): note the hexadecimal value (e.g., 6D975C4791E7EE5E) and request the key:
+**If you receive an authentication error** (such as NO_PUBKEY):
+note the hexadecimal value (e.g., 6D975C4791E7EE5E) and request the key:
- sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys HEXVALUE
+ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys HEX
-where HEXVALUE is the hexadecimal value specified in the error. Then rerun the ```update``` and ```install``` commands.
+where HEX is the hexadecimal value specified in the error.
+Then rerun the ```update``` and ```install``` commands.
## CLONE THE RVI REPOSITORY ##
@@ -88,7 +89,7 @@ to the build system.
The clone will be downloaded into a newly created ```rvi_core``` subdirectory.
-----
+<div class="pb"></div>
## BUILD THE RVI SYSTEM ##
@@ -101,8 +102,6 @@ The local ```rebar``` command is used to retrieve the dependencies. See
```rebar.config``` and ```deps/*/rebar.config``` for a list of
dependencies.
-<div class="pagebreak"></div>
-
See the [rebar](https://github.com/basho/rebar) project for a detailed
description of the rebar Erlang build tool.
@@ -137,6 +136,7 @@ The compiled code is available under ```ebin/```, ```components/*/ebin``` and ``
## CREATE A RELEASE ##
-See ```CONFIGURE.md``` for details on configuring and creating a
-developer and production release that can be launched.
+See [CONFIGURE.md](CONFIGURE.md) ([PDF](doc/pdf/CONFIGURE.pdf)) for details
+on configuring and creating a developer and production release that can be
+launched.
diff --git a/INSTALL_debian.md b/INSTALL_debian.md
new file mode 100644
index 0000000..590bc12
--- /dev/null
+++ b/INSTALL_debian.md
@@ -0,0 +1,111 @@
+Copyright (C) 2014-2016, Jaguar Land Rover
+
+This document is licensed under Creative Commons
+Attribution-ShareAlike 4.0 International.
+
+**Version 0.5.0**
+
+# INSTALLATION OF RVI (DEBIAN) #
+
+This document describes the installation process for the RVI project
+on a Debian 8 ("jessie") Linux machine. Packages are also available
+for [Ubuntu](INSTALL_ubuntu.md) and [Raspbian](INSTALL_raspbian.md).
+See ```BUILD.md``` for building from source.
+
+Please see ```README.md``` for a general description of the project
+and its structure.
+
+Please see ```CONFIGURE.md``` for details on configuring and launching
+the system once it has been built.
+
+The first milestone of the RVI project is the HVAC demo. Please see
+```hvac_demo/README.md``` for details on how to setup, launch and
+drive the demo.
+
+# READER ASSUMPTIONS #
+In order to build the system, the reader is assumed to be able to:
+
+1. Have a basic understanding of Linux system operations.
+2. Install packages on the system.
+
+Please note that the configuration process described in
+```CONFIGURE.md``` may have additional skill requirements.
+
+# PREREQUISITES #
+
+1. The Debian 8 system has the latest updates installed.
+2. The user can gain root access to install packages.
+3. There is at least 5GB of space availabled for packages and code.
+
+----
+
+# INSTALLATION PROCESS #
+
+## INSTALL DEPENDENCIES ##
+
+Install dependent libraries via ```apt-get``` - note you must be root:
+
+ apt-get install python-jsonrpclib
+
+## INSTALL ESL-ERLANG ##
+
+Install `esl-erlang` 18.2, or a later version 18 release:
+
+Tested packages of the latest versions of Erlang can be downloaded from
+[packages.erlang-solutions.com](https://www.erlang-solutions.com/resources/download.html)
+
+Add the following line to your /etc/apt/sources.list
+
+ deb http://packages.erlang-solutions.com/debian jessie contrib
+
+Update and install `esl-erlang`:
+
+ apt-get update
+ apt-get install esl-erlang
+
+**If you receive an authentication error** (such as NO_PUBKEY): note
+the hexadecimal value (e.g., 6D975C4791E7EE5E) and request the key:
+
+ apt-key adv --keyserver keyserver.ubuntu.com --recv-keys HEX
+
+where HEX is the hexadecimal value specified in the error.
+Then rerun the ```update``` and ```install``` commands.
+
+## DOWNLOAD AND INSTALL RVI ##
+
+Download the RVI package from https://github.com/PDXostc/rvi_core/releases.
+
+Then install RVI via dpkg:
+
+ sudo dpkg -i rvi_0.5.0-1_amd64.deb
+
+----
+
+## TEST THE RVI SYSTEM ##
+
+To confirm that RVI has started, use `systemctl` as root user:
+
+ systemctl status rvi
+
+Expected output:
+
+ ● rvi.service - Remote Vehicle Interaction Service
+ Loaded: loaded (/lib/systemd/system/rvi.service; disabled)
+ Active: active (running) since Mon 2016-02-22 14:16:27 PST; 15min ago
+ Process: 1922 ExecStart=/usr/bin/rvi_ctl -c /etc/rvi/rvi.config start (code=exited, status=0/SUCCESS)
+ Main PID: 1954 (run_erl)
+ CGroup: /system.slice/rvi.service
+ ├─1954 run_erl -daemon /tmp/rvi_1922/ /var/log/rvi exec erl -boot /tmp/rvi_1922/rvi/start -sname rvi -config /tmp/rvi_1922/rvi/sys -setcookie rvi_cookie
+ ├─1955 /usr/lib/erlang/erts-7.2/bin/beam.smp -- -root /usr/lib/erlang -progname erl -- -home /usr/lib/rvi_core -- -boot /tmp/rvi_1922/rvi/start -sname rvi -config /tmp/rvi_1922/rvi/sys -setcookie rvi_cookie
+ ├─1962 /usr/lib/erlang/erts-7.2/bin/epmd -daemon
+ ├─1983 /usr/lib/rvi_core/deps/bt/priv/bt
+ ├─1989 inet_gethost 4
+ └─1990 inet_gethost 4
+
+## CREATE A RELEASE ##
+
+The installer configures a release with default (insecure) credentials.
+
+See ```CONFIGURE.md``` for additional details on configuring and
+creating a developer and production release.
+
diff --git a/INSTALL_raspbian.md b/INSTALL_raspbian.md
new file mode 100644
index 0000000..7d0da34
--- /dev/null
+++ b/INSTALL_raspbian.md
@@ -0,0 +1,102 @@
+Copyright (C) 2014-2016, Jaguar Land Rover
+
+This document is licensed under Creative Commons
+Attribution-ShareAlike 4.0 International.
+
+**Version 0.5.0**
+
+# INSTALLATION OF RVI (RASPBIAN) #
+
+This document describes the installation process for the RVI project
+on Raspbian. Packages are also available for
+[Ubuntu](INSTALL_ubuntu.md) and [Raspbian](INSTALL_raspbian.md).
+See ```BUILD.md``` for building from source.
+
+Please see ```README.md``` for a general description of the project
+and its structure.
+
+Please see ```CONFIGURE.md``` for details on configuring and launching
+the system once it has been built.
+
+The first milestone of the RVI project is the HVAC demo. Please see
+```hvac_demo/README.md``` for details on how to setup, launch and
+drive the demo.
+
+# READER ASSUMPTIONS #
+In order to build the system, the reader is assumed to be able to:
+
+1. Have a basic understanding of Linux system operations.
+2. Install packages on the system.
+
+Please note that the configuration process described in
+```CONFIGURE.md``` may have additional skill requirements.
+
+# PREREQUISITES #
+
+1. The Raspbian system has the latest updates installed.
+2. The user has sudo access to install packages.
+3. There is at least 5GB of space availabled for packages and code.
+
+----
+
+# INSTALLATION PROCESS #
+
+## GET RASPBIAN PACKAGES ##
+
+Download the Raspbian package from https://github.com/PDXostc/rvi_core/releases. Then extract the tarball to get packages for Erlang and RVI, as well as an install script.
+
+## INSTALL ERLANG AND RVI ##
+
+Make the install script executable:
+
+ sudo chmod +x installRVI
+
+Then run the install script:
+
+ ./installRVI
+
+This does the following:
+
+1. Extracts the Erlang tarball
+2. Installs the required Erlang packages
+ * `erlang-base`
+ * `erlang-asnl`
+ * `erlang-crypto`
+ * `erlang-eunit`
+ * `erlang-public key`
+ * `erlang-ssl`
+ * `erlang-syntax-tools`
+3. Installs other dependencies (`bluez` and `python-jsonrpclib`)
+4. Installs `rvi`
+5. Starts `rvi` via `systemctl`
+6. Checks the status of `rvi` via `systemctl`.
+
+----
+
+## TEST THE RVI SYSTEM ##
+
+To confirm that RVI has started, use `systemctl` as root user:
+
+ systemctl status rvi
+
+Expected output:
+
+ ● rvi.service - Remote Vehicle Interaction Service
+ Loaded: loaded (/lib/systemd/system/rvi.service; disabled)
+ Active: active (running) since Tue 2016-02-23 18:30:03 UTC; 48ms ago
+ Process: 6049 ExecStart=/usr/bin/rvi_ctl -c /etc/rvi/rvi.config start (code=exited, status=0/SUCCESS)
+ Main PID: 6081 (run_erl)
+ CGroup: /system.slice/rvi.service
+ ├─6081 run_erl -daemon /tmp/rvi_6049/ /var/log/rvi exec erl -boot /tmp/rvi_6049/rvi/start -sname rvi -config /tmp/rvi_6049/rvi/sys -setcookie rvi_cookie
+ ├─6084 /usr/lib/erlang/erts-7.2/bin/erlexec -boot /tmp/rvi_6049/rvi/start -sname rvi -config /tmp/rvi_6049/rvi/sys -setcookie rvi_cookie
+ ├─6093 sh -c "/usr/lib/erlang/erts-7.2/bin/epmd" -daemon
+ └─6094 /usr/lib/erlang/erts-7.2/bin/epmd -daemon
+
+
+## CREATE A RELEASE ##
+
+The installer configures a release with default (insecure) credentials.
+
+See ```CONFIGURE.md``` for additional details on configuring and
+creating a developer and production release.
+
diff --git a/INSTALL_ubuntu.md b/INSTALL_ubuntu.md
new file mode 100644
index 0000000..36ca07c
--- /dev/null
+++ b/INSTALL_ubuntu.md
@@ -0,0 +1,143 @@
+Copyright (C) 2014-2016, Jaguar Land Rover
+
+This document is licensed under Creative Commons
+Attribution-ShareAlike 4.0 International.
+
+**Version 0.5.0**
+
+# INSTALLATION OF RVI (UBUNTU 14.04 TRUSTY) #
+
+This document describes the installation process for the RVI project on
+an Ubuntu 14.04 Linux machine. Packages are also available for
+[Debian](BUILD_debian.md) and [Raspbian](BUILD_raspbian.md).
+See [```BUILD.md```](BUILD.md) for building from source.
+
+Please see [```README.md```](README.md) for a general description of the project
+and its structure.
+
+Please see [```CONFIGURE.md```](CONFIGURE.md) for details on configuring and launching
+the system once it has been built.
+
+The first milestone of the RVI project is the HVAC demo. Please see
+```hvac_demo/README.md``` for details on how to setup, launch and
+drive the demo.
+
+# READER ASSUMPTIONS #
+In order to build the system, the reader is assumed to be able to:
+
+1. Have a basic understanding of Linux system operations.
+2. Install packages on the system.
+
+Please note that the configuration process described in
+```CONFIGURE.md``` may have additional skill requirements.
+
+# PREREQUISITES #
+
+1. The Ubuntu 14.04 system have the latest updates installed.
+2. The user can gain root access to install packages.
+3. There is at least 5GB of space availabled for packages and code.
+
+----
+
+<div class="pagebreak"></div>
+
+# INSTALLATION PROCESS #
+
+## INSTALL DEPENDENCIES ##
+
+Install dependent libraries via `apt-get`:
+
+ sudo apt-get install python-jsonrpclib
+
+## INSTALL ESL-ERLANG ##
+
+Install `esl-erlang` 18.2, or a later version 18 release:
+
+Tested packages of the latest versions of Erlang can be downloaded from
+[packages.erlang-solutions.com](https://www.erlang-solutions.com/resources/download.html)
+
+Add the following line to your /etc/apt/sources.list
+
+ deb http://packages.erlang-solutions.com/ubuntu trusty contrib
+
+Update and install esl-erlang
+
+ sudo apt-get update
+ sudo apt-get install esl-erlang
+
+**If you receive an authentication error** (such as NO_PUBKEY):
+note the hexadecimal value (e.g., 6D975C4791E7EE5E) and request the key:
+
+ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys HEX
+
+where HEX is the hexadecimal value specified in the error.
+Then rerun the ```update``` and ```install``` commands.
+
+## DOWNLOAD AND INSTALL RVI ##
+
+Download the RVI package from https://github.com/PDXostc/rvi_core/releases.
+
+Then install RVI via dpkg:
+
+ sudo dpkg -i rvi_0.5.0-1ubuntu1_amd64.deb
+
+----
+
+## TEST THE RVI SYSTEM ##
+
+To confirm that RVI has installed successfully, run:
+
+ sudo service rvi start
+
+Expected output:
+
+ * Starting Remote Vehicle Interaction Node... rvi [ OK ]
+
+Find out which services are registered through `rvi_get_services`:
+
+ /usr/lib/rvi_core/rvi_get_services
+
+The command should return no output, since we have not registered any services yet.
+
+Register a service by calling `rvi_service` -- start with "hello":
+
+ /usr/lib/rvi_core/rvi_service hello
+
+Expected output:
+
+ RVI General Service.
+ RVI node URL: http://localhost:9001
+ Service: genivi.org/vin/default_vin/hello
+ Press enter to quit:
+
+In another terminal, call `rvi_get_services` again to see the newly registered service:
+
+ genivi.org/vin/default_vin/hello
+
+Invoke the service through `rvi_call` and the full service name:
+
+ /usr/lib/rvi_core/rvi_call genivi.org/vin/default_vin/hello
+
+In terminal 1 (where you called `rvi_service`), you should see the following output:
+
+ Service invoked!
+ args: {}
+
+In terminal 2 (where you called `rvi_call`), you should see the following output:
+
+ RVI Node: http://localhost:9001
+ Service: genivi.org/vin/default_vin/hello
+ args: {}
+
+You can pass arguments to a service call with the format name=value:
+
+ /usr/lib/rvi_core/rvi_call genivi.org/vin/default_vin/hello \
+ a=b message=hello
+
+## CREATE A RELEASE ##
+
+The installer configures a release with default (insecure) values.
+
+See ```CONFIGURE.md``` for details on configuring and creating a
+developer and production release that can be launched.
+
diff --git a/README.debian_build b/README.debian_build
deleted file mode 100644
index 8614727..0000000
--- a/README.debian_build
+++ /dev/null
@@ -1,14 +0,0 @@
-Erlang
-
-apt-get install devscripts
-apt-get install bluez
-apt-get install libbluetooth-dev
-apt-get install git
-apt-get install g++
-apt-get install make
-apt-get install python-jsonrpclib
-apt-get install libwxgtk3.0-0
-apt-get install dh-systemd
-
-wget https://packages.erlang-solutions.com/erlang/esl-erlang/FLAVOUR_1_general/esl-erlang_18.2-1~debian~jessie_amd64.deb
-dpkg -i esl-erlang_18.2-1~debian~jessie_amd64.deb
diff --git a/README.md b/README.md
index 1c1b405..ef8e0c3 100644
--- a/README.md
+++ b/README.md
@@ -1,31 +1,44 @@
-Copyright (C) 2014-2015 Jaguar Land Rover
+Copyright (C) 2014-2016 Jaguar Land Rover
This document is licensed under Creative Commons
Attribution-ShareAlike 4.0 International.
-# REMOTE VEHICLE INTERACTION (RVI) 0.4.0 #
+# REMOTE VEHICLE INTERACTION (RVI) 0.5.0 #
This document gives a brief introduction to the codebase of the RVI
project and explains the reasoning behind some of the technical
choices.
# ADDITIONAL DOCUMENTATION AND RESOURCES#
-For a high level description, with an exhaustive master usecase
+
+For a high level description, with an exhaustive master use-case
walkthrough, please see the High Level Design document
-[here](https://wiki.automotivelinux.org/_media/eg-rvi/15-456-poc-rvi-hld_reva.pdf)
+[here](https://wiki.automotivelinux.org/_media/eg-rvi/15-456-poc-rvi-hld_reva.pdf) (**NOTE: HLD not updated to reflect RVI Core 0.5.0**)
-Git branch management is JLR OSTCs standard git document
-[Git strategy](https://docs.google.com/document/d/1xG86q2o5Y-aSn7m8QARIH8hcTpH_yNMWCLQJD47IP48/edit/)
-[Git strategy](https://docs.google.com/document/d/1ko12dTXGeb2-E18SHOzGuC1318hGYSCIq3ADSzFOlGM/edit)
+Packages are available for some distributions. See installation
+instructions for [Ubuntu](INSTALL_ubuntu.md), [Debian](INSTALL_debian.md),
+and [Raspbian](INSTALL_raspbian.md).
-For build instructions, please check the build instructions:
+For build instructions, please check the **build instructions**:
[Markdown](BUILD.md) |
[PDF](doc/pdf/BUILD.pdf)
-For configuration and launch instructions, please check the configuration documentation:
+For configuration and launch instructions, please check the **configuration documentation**:
[Markdown](CONFIGURE.md) |
[PDF](doc/pdf/CONFIGURE.pdf)
+For instructions on how to create RVI Core certificates, keys and credentials, please check the **certificates documentation**:
+[Markdown](doc/rvi_certificates.md) |
+[PDF](doc/pdf/rvi_certificates.pdf)
+
+For instructions on using the Services API, please check the **services documentation**:
+[Markdown](doc/rvi_services.md) |
+[PDF](doc/pdf/rvi_services.pdf)
+
+For a detailed description of the RVI Core Peer-to-peer protocol, please check the **rvi_protocol documentation**:
+[Markdown](doc/rvi_protocol.md) |
+[PDF](doc/pdf/rvi_protocol.pdf)
+
Technical RVI disussions are held at the GENIVI project mailing list:
[GENIVI](https://lists.genivi.org/mailman/listinfo/genivi-projects)
@@ -78,8 +91,8 @@ RVI shall be able to function over transient and unreliable data channels, but a
# TECHNOLOGY CHOICES #
The following chapters describe the technology choices made for the
reference implementation. An overall goal was to avoid technology
-lock-in while easing adoption by allowing organiztions to replace
-individual components with in-house developted variants using their
+lock-in while easing adoption by allowing organizations to replace
+individual components with in-house developed variants using their
own technology.
## INTERCHANGEABILITY ##
@@ -100,7 +113,7 @@ and a backend server, in an RVI network. An organization is free to
integrate with any existing protocols, or develop new ones, as
necessary.
-The reference implemantation provides an example of how to handle a
+The reference implementation provides an example of how to handle a
classic client-server model. The RVI design, however, can easily
handle such cases such as wakeup-SMS (used to get a vehicle to call in
to a server), packet-based data, peer-to-peer networks without any
@@ -112,7 +125,7 @@ management and data encoding / decoding over any media (IP or non-IP).
[Erlang](http://www.erlang.org) was chosen to implementation the core
components of the RVI system. Each component (see the
[HLD](https://wiki.automotivelinux.org/_media/eg-rvi/15-456-poc-rvi-hld_reva.pdf)
-for details) run as an erlang application inside a single erlang node.
+for details) run as an Erlang application inside a single Erlang node.
Several reasons exist for this somewhat unorthodox choice of
implementation language:
@@ -120,32 +133,32 @@ implementation language:
* **Robustness**<br>
Erlang has the ability to gracefully handle component crashes /
restarts without availability degradation. This makes a deployment
-resiliant against the occasional bug and malfunction. In a similar
+resilient against the occasional bug and malfunction. In a similar
manner, redundant sites can be setup to handle catastrophic failures
and geographically distributed deployments.
* **Tool availability**<br>
-There are a multitude of open source erlang components available to
+There are a multitude of open source Erlang components available to
handle SMS, GPIO, CAN buses, GPS, PPP links, and almost any protocol
-out there. Since erlang was designed to handle the mobile
+out there. Since Erlang was designed to handle the mobile
communication requirements that is at the center of the connected
vehicle, integrating with existing systems and protocols is often a
straight-forward process.
* **Scalability**<br>
-The concurrent nature of an erlang system sets the stage for
+The concurrent nature of an Erlang system sets the stage for
horizontal scalaility by simply adding hosts to a deployment, allowing
-an organziation to expand from a pilot fleet to a full fledged
+an organization to expand from a pilot fleet to a full fledged
international deployment.
* **Carrier grade availability**<br>
-The robustness and scalaiblity, in conjunction with the built-in
-erlang feature of runtime code upgrades, is a part of erlang's
+The robustness and scalability, in conjunction with the built-in
+Erlang feature of runtime code upgrades, is a part of Erlang's
five-nines uptime design that is rapidly becoming a core requirement
of the automotive industry.
* **Proven embedded system solution**<br>
-Erlang has been adapted to operate well in embeded environments
+Erlang has been adapted to operate well in embedded environments
with unreliable power, limited resources, and the need to integrate
with a wide variety of hardware.
@@ -153,7 +166,7 @@ with a wide variety of hardware.
Python is used to implement all demonstrations, beginning
with the HVAC demo available in the `hvac_demo` subdirectory.
-By using Python for the demos, which is better known than erlang,
+By using Python for the demos, which is better known than Erlang,
examples are given on how to write applications and services
interfacing with the RVI system.
@@ -166,38 +179,39 @@ understanding and adoption.
One example is the use of JSON-RPC (over HTTP) to handle internal
communication between components in a single Erlang node.
-Using a traditional erlang solution such as genserver, the
+Using a traditional Erlang solution such as genserver, the
overhead for internal transactions could be cut to a few percent in
comparison with the current JSON-RPC implementation. That route,
however, would force all components of the RVI system to be
-implemented in Erlang, thus severly limiting an organizations
+implemented in Erlang, thus severely limiting an organization's
abilities to replace individual components with their own versions.
## CODE STRATEGY ##
-All code in the RVI reference implementaion and its demonstrations are
+All code in the RVI reference implementation and its demonstrations are
written with a minimum of complexity and "magic". Readability is
-paramount, even if it severly impact performance and memory usage.
+paramount, even if it severely impacts performance and memory usage.
+
-All components in the RVI are kept small and distcinct, with a
-well-defined JSON-RPC external interface and a simple call flows.
+All components in the RVI are kept small and distinct, with a
+well-defined JSON-RPC external interface and simple call flows.
Only three external modules (lager, bert and exo) are used by the
code, with two more (setup and edown) used for release and
documentation management.
The reason for minimizing external module usage is to make the code
-comprehensible and minimize the time a developer has to travesrse
+comprehensible and minimize the time a developer has to traverse
through obscure libraries trying to understand what a specific call
flow actually does.
-The entire reference implementation (as of the first alpa release) is
+The entire reference implementation (as of the first alpha release) is
2800 lines of code, broken down into six standalone modules and one
library of shared primitive functions.
## JSON-RPC ##
-JSON-RPC is used for all communication between components in an RVI
-system, and also to communicate with services connected to it. The
-ubiquity of JSON-RPC, and its close relationship with Java/Javascript,
+JSON-RPC is used for all communication between components in an RVI
+system, and also to communicate with services connected to it. The
+ubiquity of JSON-RPC, and its close relationship with Java/JavaScript,
provides maximum of freedom of technology choices when new components,
services, and applications are developed.
diff --git a/components/dlink_bt/src/dlink_bt_rpc.erl b/components/dlink_bt/src/dlink_bt_rpc.erl
index 74a49cc..c4276bd 100644
--- a/components/dlink_bt/src/dlink_bt_rpc.erl
+++ b/components/dlink_bt/src/dlink_bt_rpc.erl
@@ -338,6 +338,13 @@ process_authorize(FromPid, PeerBTAddr, PeerBTChannel,
?info("dlink_bt:authorize(): Protocol: ~p", [ Protocol ]),
?debug("dlink_bt:authorize(): Credentials: ~p", [ Credentials ]),
+ case Protocol of
+ <<"1.", _/binary>> -> ok;
+ undefined -> ok;
+ _ ->
+ throw({protocol_failure, {unknown_version, Protocol}})
+ end,
+
%% If FromPid (the genserver managing the socket) is not yet registered
%% with the conneciton manager, this is an incoming connection
%% from the client. We should respond with our own authorize followed by
@@ -368,9 +375,15 @@ handle_socket(FromPid, PeerBTAddr, PeerChannel, data,
?DLINK_ARG_CREDENTIALS],
Elems, undefined),
- process_authorize(FromPid, PeerBTAddr, RemoteChannel,
- RemoteAddress, RemoteChannel,
- RVIProtocol, Credentials, CS);
+ try
+ process_authorize(FromPid, PeerBTAddr, RemoteChannel,
+ RemoteAddress, RemoteChannel,
+ RVIProtocol, Credentials, CS)
+ catch
+ throw:{protocol_failure, What} ->
+ ?error("Protocol failure (~p): ~p", [FromPid, What]),
+ exit(FromPid, protocol_failure)
+ end;
?DLINK_CMD_SERVICE_ANNOUNCE ->
[ Status,
diff --git a/components/dlink_sms/src/dlink_sms_rpc.erl b/components/dlink_sms/src/dlink_sms_rpc.erl
index 4bf5f14..2f20d2d 100644
--- a/components/dlink_sms/src/dlink_sms_rpc.erl
+++ b/components/dlink_sms/src/dlink_sms_rpc.erl
@@ -305,12 +305,10 @@ handle_sms(FromPid, Addr, data, Payload, [CompSpec]) ->
case opt(?DLINK_ARG_CMD, Elems, undefined) of
?DLINK_CMD_AUTHORIZE ->
[ TransactionID,
- RemoteAddress,
ProtoVersion,
CertificatesTmp,
Signature ] =
opts([?DLINK_ARG_TRANSACTION_ID,
- ?DLINK_ARG_ADDRESS,
?DLINK_ARG_VERSION,
?DLINK_ARG_CERTIFICATES,
?DLINK_ARG_SIGNATURE],
@@ -321,8 +319,15 @@ handle_sms(FromPid, Addr, data, Payload, [CompSpec]) ->
{array, C} -> C;
undefined -> []
end,
- process_authorize(FromPid, Addr, TransactionID, RemoteAddress,
- ProtoVersion, Signature, Certificates, CompSpec);
+ try
+ process_authorize(
+ FromPid, Addr, TransactionID,
+ ProtoVersion, Signature, Certificates, CompSpec)
+ catch
+ throw:{protocol_failure, What} ->
+ ?error("Protocol failure (~p): ~p", [FromPid, What]),
+ exit(FromPid, protocol_failure)
+ end;
?DLINK_CMD_SERVICE_ANNOUNCE ->
[ TransactionID,
@@ -613,14 +618,20 @@ availability_msg(Availability, Services) ->
status_string(available ) -> ?DLINK_ARG_AVAILABLE;
status_string(unavailable) -> ?DLINK_ARG_UNAVAILABLE.
-process_authorize(FromPid, PeerAddr, TransactionID, RemoteAddress,
+process_authorize(FromPid, PeerAddr, TransactionID,
ProtoVersion, Signature, Certificates, CompSpec) ->
?info("dlink_sms:authorize(): Peer Address: ~p" , [PeerAddr]),
- ?info("dlink_sms:authorize(): Remote Address: ~p" , [RemoteAddress]),
?info("dlink_sms:authorize(): Protocol Ver: ~p" , [ProtoVersion]),
?debug("dlink_sms:authorize(): TransactionID: ~p", [TransactionID]),
?debug("dlink_sms:authorize(): Signature: ~p", [Signature]),
+ case ProtoVersion of
+ <<"1.", _/binary>> -> ok;
+ undefined -> ok;
+ _ ->
+ throw({protocol_failure, {unknown_version, ProtoVersion}})
+ end,
+
Conn = {PeerAddr, 0}, % add dummy port (necessary?)
case validate_auth_jwt(Signature, Certificates, Conn, CompSpec) of
true ->
@@ -631,14 +642,12 @@ process_authorize(FromPid, PeerAddr, TransactionID, RemoteAddress,
end.
send_authorize(Pid, CompSpec) ->
- LocalAddr = rvi_common:node_msisdn(),
sms_connection:send_auth(
Pid,
term_to_json(
{struct,
[ { ?DLINK_ARG_TRANSACTION_ID, 1 },
{ ?DLINK_ARG_CMD, ?DLINK_CMD_AUTHORIZE },
- { ?DLINK_ARG_ADDRESS, LocalAddr },
{ ?DLINK_ARG_VERSION, ?DLINK_SMS_VERSION },
{ ?DLINK_ARG_CERTIFICATES, {array, get_certificates(CompSpec)} },
{ ?DLINK_ARG_SIGNATURE, get_authorize_jwt(CompSpec) } ]})).
diff --git a/components/dlink_tcp/src/dlink_tcp_rpc.erl b/components/dlink_tcp/src/dlink_tcp_rpc.erl
index 31184bd..f094fff 100644
--- a/components/dlink_tcp/src/dlink_tcp_rpc.erl
+++ b/components/dlink_tcp/src/dlink_tcp_rpc.erl
@@ -338,19 +338,20 @@ handle_socket_(FromPid, PeerIP, PeerPort, data, Elems, CompSpec) ->
case opt(?DLINK_ARG_CMD, Elems, undefined) of
?DLINK_CMD_AUTHORIZE ->
?debug("got authorize ~s:~w", [PeerIP, PeerPort]),
- [ RemoteAddress,
- RemotePort,
- ProtoVersion,
+ [ ProtoVersion,
Credentials ] =
- opts([?DLINK_ARG_ADDRESS,
- ?DLINK_ARG_PORT,
- ?DLINK_ARG_VERSION,
+ opts([?DLINK_ARG_VERSION,
?DLINK_ARG_CREDENTIALS],
Elems, undefined),
- process_authorize(FromPid, PeerIP, PeerPort,
- RemoteAddress, RemotePort,
- ProtoVersion, Credentials, CS);
+ try
+ process_authorize(FromPid, PeerIP, PeerPort,
+ ProtoVersion, Credentials, CS)
+ catch
+ throw:{protocol_failure, What} ->
+ ?error("Protocol failure (~p): ~p", [FromPid, What]),
+ exit(FromPid, protocol_failure)
+ end;
?DLINK_CMD_SERVICE_ANNOUNCE ->
?debug("got service_announce ~s:~w", [PeerIP, PeerPort]),
@@ -663,19 +664,18 @@ availability_msg(Availability, Services, CompSpec) ->
status_string(available ) -> ?DLINK_ARG_AVAILABLE;
status_string(unavailable) -> ?DLINK_ARG_UNAVAILABLE.
-bin(S) ->
- iolist_to_binary(S).
+%% bin(S) ->
+%% iolist_to_binary(S).
-process_authorize(FromPid, PeerIP, PeerPort, RemoteAddress,
- RemotePort, ProtoVersion, Credentials, CompSpec) ->
+process_authorize(FromPid, PeerIP, PeerPort,
+ ProtoVersion, Credentials, CompSpec) ->
?info("dlink_tcp:authorize(): Peer Address: ~p:~p", [PeerIP, PeerPort ]),
- ?info("dlink_tcp:authorize(): Remote Address: ~p~p", [ RemoteAddress, RemotePort ]),
?info("dlink_tcp:authorize(): Protocol Ver: ~p", [ ProtoVersion ]),
?debug("dlink_tcp:authorize(): Credentials: ~p", [ [authorize_keys:abbrev_bin(C) || C <- Credentials] ]),
F = fun() ->
- process_authorize_(FromPid, PeerIP, PeerPort, RemoteAddress,
- RemotePort, ProtoVersion, Credentials, CompSpec)
+ process_authorize_(FromPid, PeerIP, PeerPort,
+ ProtoVersion, Credentials, CompSpec)
end,
case connection_manager:find_connection_by_address(PeerIP, PeerPort) of
not_found ->
@@ -704,27 +704,23 @@ deconflict_conns(APid, BPid, CsA, F) ->
end.
-process_authorize_(FromPid, PeerIP, PeerPort, RemoteAddress, RemotePort,
- _ProtoVersion, Credentials, CompSpec) ->
- {NRemoteAddress, NRemotePort} = Conn = {PeerIP, PeerPort},
- %% {NRemoteAddress, NRemotePort} = Conn =
- %% case { RemoteAddress, RemotePort } of
- %% { "0.0.0.0", 0 } ->
- %% ?info("dlink_tcp:authorize(): Remote is behind firewall. Will use ~p:~p",
- %% [ PeerIP, PeerPort]),
- %% { PeerIP, PeerPort };
- %% _ -> { RemoteAddress, RemotePort}
- %% end,
- log(result, "auth ~s:~w", [NRemoteAddress, NRemotePort], CompSpec),
+process_authorize_(FromPid, PeerIP, PeerPort,
+ ProtoVersion, Credentials, CompSpec) ->
+ case ProtoVersion of
+ <<"1.", _/binary>> -> ok;
+ undefined -> ok;
+ _ ->
+ ?error("Unknown/unsupported protocol version: ~p", [ProtoVersion]),
+ throw({protocol_failure, {unknown_version, ProtoVersion}})
+ end,
+ Conn = {PeerIP, PeerPort},
+ log(result, "auth ~s:~w", [PeerIP, PeerPort], CompSpec),
authorize_rpc:store_creds(CompSpec, Credentials, Conn),
connection_authorized(FromPid, Conn, CompSpec).
send_authorize(Pid, CompSpec) ->
- {LocalIP, LocalPort} = rvi_common:node_address_tuple(),
connection:send(Pid,
[{ ?DLINK_ARG_CMD, ?DLINK_CMD_AUTHORIZE },
- { ?DLINK_ARG_ADDRESS, bin(LocalIP) },
- { ?DLINK_ARG_PORT, integer_to_binary(LocalPort) },
{ ?DLINK_ARG_VERSION, ?DLINK_TCP_VERSION },
{ ?DLINK_ARG_CREDENTIALS, get_credentials(CompSpec) }
| log_id_tail(CompSpec) ]).
diff --git a/components/dlink_tls/src/dlink_tls_rpc.erl b/components/dlink_tls/src/dlink_tls_rpc.erl
index 6a90129..ad0d512 100644
--- a/components/dlink_tls/src/dlink_tls_rpc.erl
+++ b/components/dlink_tls/src/dlink_tls_rpc.erl
@@ -365,16 +365,20 @@ handle_socket(FromPid, PeerIP, PeerPort, data, Elems, CompSpec) ->
case opt(?DLINK_ARG_CMD, Elems, undefined) of
?DLINK_CMD_AUTHORIZE ->
?debug("got authorize ~s:~w", [PeerIP, PeerPort]),
- [ RemoteAddress,
- RemotePort,
+ [ ProtoVersion,
Credentials ] =
- opts([?DLINK_ARG_ADDRESS,
- ?DLINK_ARG_PORT,
+ opts([?DLINK_ARG_VERSION,
?DLINK_ARG_CREDENTIALS],
Elems, undefined),
- process_authorize(FromPid, PeerIP, PeerPort, RemoteAddress, RemotePort,
- Credentials, CS);
+ try
+ process_authorize(FromPid, PeerIP, PeerPort,
+ Credentials, ProtoVersion, CS)
+ catch
+ throw:{protocol_failure, What} ->
+ ?error("Protocol failure (~p): ~p", [FromPid, What]),
+ exit(FromPid, protocol_failure)
+ end;
%% ?DLINK_CMD_CRED_EXCHANGE ->
%% ?debug("got cred exch ~s:~w", [PeerIP, PeerPort]),
@@ -684,40 +688,29 @@ availability_msg(Availability, Services) ->
status_string(available ) -> ?DLINK_ARG_AVAILABLE;
status_string(unavailable) -> ?DLINK_ARG_UNAVAILABLE.
-process_authorize(FromPid, PeerIP, PeerPort, RemoteAddress,
- RemotePort, Credentials, CompSpec) ->
+process_authorize(FromPid, PeerIP, PeerPort,
+ Credentials, ProtoVersion, CompSpec) ->
?info("dlink_tls:authorize(): Peer Address: ~s:~p", [PeerIP, PeerPort ]),
- ?info("dlink_tls:authorize(): Remote Address: ~s:~p", [ RemoteAddress, RemotePort ]),
-
- {NRemoteAddress, NRemotePort} = Conn = {PeerIP, PeerPort},
- %% { NRemoteAddress, NRemotePort} = Conn =
- %% case { RemoteAddress, RemotePort } of
- %% { <<"0.0.0.0">>, 0 } ->
-
- %% ?info("dlink_tls:authorize(): Remote is behind firewall. Will use ~p:~p",
- %% [ PeerIP, PeerPort]),
- %% { PeerIP, PeerPort };
- %% _ -> { RemoteAddress, RemotePort}
- %% end,
- log("auth ~s:~w", [NRemoteAddress, NRemotePort], CompSpec),
+ case ProtoVersion of
+ <<"1.", _/binary>> -> ok;
+ undefined -> ok;
+ _ ->
+ throw({protocol_failure, {unknown_version, ProtoVersion}})
+ end,
+ Conn = {PeerIP, PeerPort},
+ log("auth ~s:~w", [PeerIP, PeerPort], CompSpec),
PeerCert = rvi_common:get_value(dlink_tls_peer_cert, not_found, CompSpec),
authorize_rpc:store_creds(CompSpec, Credentials, Conn, PeerCert),
connection_authorized(FromPid, Conn, CompSpec).
send_authorize(Pid, CompSpec) ->
?debug("send_authorize() Pid = ~p; CompSpec = ~p", [Pid, abbrev(CompSpec)]),
- {LocalIP, LocalPort} = rvi_common:node_address_tuple(),
Creds = get_credentials(CompSpec),
dlink_tls_conn:send(Pid, rvi_common:pass_log_id(
[{?DLINK_ARG_CMD, ?DLINK_CMD_AUTHORIZE},
{?DLINK_ARG_VERSION, ?DLINK_TLS_VERSION},
- {?DLINK_ARG_ADDRESS, bin(LocalIP)},
- {?DLINK_ARG_PORT, LocalPort},
{?DLINK_ARG_CREDENTIALS, Creds}], CompSpec)).
-bin(S) ->
- iolist_to_binary(S).
-
connection_authorized(FromPid, {RemoteIP, RemotePort} = Conn, CompSpec) ->
%% If FromPid (the genserver managing the socket) is not yet registered
%% with the connection manager, this is an incoming connection
diff --git a/components/proto_json/src/proto_json_rpc.erl b/components/proto_json/src/proto_json_rpc.erl
index 9f10ee3..85f1aa6 100644
--- a/components/proto_json/src/proto_json_rpc.erl
+++ b/components/proto_json/src/proto_json_rpc.erl
@@ -129,12 +129,10 @@ handle_call({rvi, send_message,
?debug(" protocol:send(): data_link_mod: ~p~n", [DataLinkMod]),
?debug(" protocol:send(): data_link_opts: ~p~n", [DataLinkOpts]),
?debug(" protocol:send(): parameters: ~p~n", [Parameters]),
- Data = jsx:encode([
- { <<"tid">>, TID },
- { <<"service">>, ServiceName },
- { <<"timeout">>, Timeout },
- { <<"parameters">>, Parameters }
- ]),
+ Data = [{ <<"service">>, ServiceName },
+ { <<"timeout">>, Timeout },
+ { <<"parameters">>, Parameters }
+ ],
RviOpts = rvi_common:rvi_options(Parameters),
Res = DataLinkMod:send_data(
St#st.cs, ?MODULE, ServiceName, RviOpts ++ DataLinkOpts, Data),
@@ -145,9 +143,8 @@ handle_call(Other, _From, St) ->
{ reply, [ invalid_command ], St}.
%% Convert list-based data to binary.
-handle_cast({rvi, receive_message, [Payload, IP, Port | _LogId]} = Msg, St) ->
+handle_cast({rvi, receive_message, [Elems, IP, Port | _LogId]} = Msg, St) ->
?debug("~p:handle_cast(~p)", [?MODULE, Msg]),
- Elems = jsx:decode(iolist_to_binary(Payload)),
[ ServiceName, Timeout, Parameters ] =
opts([<<"service">>, <<"timeout">>, <<"parameters">>],
diff --git a/components/proto_msgpack/src/proto_msgpack_rpc.erl b/components/proto_msgpack/src/proto_msgpack_rpc.erl
index c8b083a..07352eb 100644
--- a/components/proto_msgpack/src/proto_msgpack_rpc.erl
+++ b/components/proto_msgpack/src/proto_msgpack_rpc.erl
@@ -132,10 +132,9 @@ handle_call({rvi, send_message,
?debug(" protocol:send(): data_link_mod: ~p~n", [DataLinkMod]),
?debug(" protocol:send(): data_link_opts: ~p~n", [DataLinkOpts]),
?debug(" protocol:send(): parameters: ~p~n", [Parameters]),
- Data = msgpack:pack([ { <<"tid">>, TID },
- { <<"service">>, ServiceName },
- { <<"timeout">>, Timeout },
- { <<"parameters">>, Parameters } ], St#st.pack_opts),
+ Data = [ { <<"service">>, ServiceName },
+ { <<"timeout">>, Timeout },
+ { <<"parameters">>, Parameters } ],
RviOpts = rvi_common:rvi_options(Parameters),
Res = DataLinkMod:send_data(
St#st.cs, ?MODULE, ServiceName, RviOpts ++ DataLinkOpts, Data),
@@ -147,9 +146,8 @@ handle_call(Other, _From, St) ->
%% Convert list-based data to binary.
-handle_cast({rvi, receive_message, [Payload, IP, Port | LogId]} = Msg, St) ->
+handle_cast({rvi, receive_message, [Elems, IP, Port | LogId]} = Msg, St) ->
?debug("~p:handle_cast(~p)", [?MODULE, Msg]),
- {ok, Elems} = msgpack:unpack(Payload, St#st.pack_opts),
[ ServiceName, Timeout, Parameters ] =
opts([<<"service">>, <<"timeout">>, <<"parameters">>],
diff --git a/components/service_edge/src/service_edge_rpc.erl b/components/service_edge/src/service_edge_rpc.erl
index f27448e..bee503e 100644
--- a/components/service_edge/src/service_edge_rpc.erl
+++ b/components/service_edge/src/service_edge_rpc.erl
@@ -619,7 +619,7 @@ do_handle_local_message_([SvcName, TimeoutArg, Parameters | _Tail], CS) ->
[TimeoutArg]),
(Now * 1000) + TimeoutArg;
- false -> %% Absolute timoeut. Convert to unix time msec
+ false -> %% Absolute timeout. Convert to unix time msec
TimeoutArg * 1000
end,
%%
diff --git a/doc/pdf/BUILD.pdf b/doc/pdf/BUILD.pdf
index dc14200..4760113 100644
--- a/doc/pdf/BUILD.pdf
+++ b/doc/pdf/BUILD.pdf
Binary files differ
diff --git a/doc/pdf/CONFIGURE.pdf b/doc/pdf/CONFIGURE.pdf
index 013da57..3b697d1 100644
--- a/doc/pdf/CONFIGURE.pdf
+++ b/doc/pdf/CONFIGURE.pdf
Binary files differ
diff --git a/doc/pdf/rvi_certificates.pdf b/doc/pdf/rvi_certificates.pdf
new file mode 100644
index 0000000..f3cc127
--- /dev/null
+++ b/doc/pdf/rvi_certificates.pdf
Binary files differ
diff --git a/doc/pdf/rvi_fragmentation.pdf b/doc/pdf/rvi_fragmentation.pdf
index 754566d..164bd82 100644
--- a/doc/pdf/rvi_fragmentation.pdf
+++ b/doc/pdf/rvi_fragmentation.pdf
Binary files differ
diff --git a/doc/pdf/rvi_protocol.pdf b/doc/pdf/rvi_protocol.pdf
index 95f72e1..1030081 100644
--- a/doc/pdf/rvi_protocol.pdf
+++ b/doc/pdf/rvi_protocol.pdf
Binary files differ
diff --git a/doc/pdf/rvi_services.pdf b/doc/pdf/rvi_services.pdf
index b42829f..bfc5f21 100644
--- a/doc/pdf/rvi_services.pdf
+++ b/doc/pdf/rvi_services.pdf
Binary files differ
diff --git a/doc/rvi_certificates.md b/doc/rvi_certificates.md
new file mode 100644
index 0000000..1d46259
--- /dev/null
+++ b/doc/rvi_certificates.md
@@ -0,0 +1,254 @@
+<style type="text/css" media="print"> div.pb { page-break-before: always; } </style>
+Copyright (C) 2015-16 Jaguar Land Rover
+
+This document is licensed under Creative Commons
+Attribution-ShareAlike 4.0 International.
+
+# CREATING RVI CERTIFICATES
+
+This document describes how to generate the necessary certificates,
+keys and credentials needed for RVI Core. The example certificates
+are used in (rvi_protocol.md)[rvi_protocol.md].
+
+# STANDARDS USED
+[1] JSON Web Token RFC7519- JWT (link)[https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32]<br>
+[2] base64url - (link)[https://en.wikipedia.org/wiki/Base64)<br>
+[3] Transport Layer Security (TLS) - (link)[https://en.wikipedia.org/wiki/Transport_Layer_Security]<br>
+[4] X.509 Certificates - (link)[https://en.wikipedia.org/wiki/X.509]<br>
+
+For all examples below the following certificates are used:
+
+## Sample root certificate
+The self signed root certificate used in the examples throughout this
+document was generated using the following commands:
+
+```Shell
+# Create root key pair
+openssl genrsa -out insecure_root_key.pem 1024
+
+# Create a self-signed root CA certificate, signed by the root key created above
+openssl req -x509 -new -nodes -key insecure_root_key.pem -days 365 -out insecure
+_root_cert.crt
+```
+
+The content of the sample ```insecure_root_key.pem``` private key
+file, which has no password protection, is:
+
+```
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDg5A1uZ5F36vQEYbMWCV4wY4OVmicYWEjjl/8YPA01tsz4x68i
+/NnlMNalqpGCIZ0AwqGI5DZAWWoR400L3SAmYD6sWj2L9ViIAPk3ceDU8olYrf/N
+wj78wVoG7qqNLgMoBNM584nlY4jy8zJ0Ka9WFBS2aDtB3Aulc1Q8ZfhuewIDAQAB
+AoGAfD+C7CxsQkSc7I7N0q76SuGwIUc5skmUe6nOViVXZwXH2Or55+qqt+VzsbO7
+EJphk7n0ZR0wm/zKjXd3acaRq5j3fOyXip9fDoNj+oUKAowDJ9vub0NOPpU2bgb0
+xDnDeR0BRVBOTWqrkDeDPBSxw5RlJunesDkamAmj4VXHHgECQQDzqDtaEuEZ7x7d
+kJKCmfGyP01s+YPlquDgogzAeMAsz17TFt8JS4RO0rX71+lmx7qqpRqIxVXIsR58
+NI2Th7tRAkEA7Eh1C1WahLCxojQOam/l7GyE+2ignZYExqonOOvsk6TG0LcFm7W9
+x39ouTlfChM26f8VYAsPxIrvsDlI1DDCCwJBAITmA8lzdrgQhwNOsbrugLg6ct63
+kcuZUqLzgIUS168ZRJ1aYjjNqdLcd0pwT+wxkI03FKv5Bns6sGgKuhX3+KECQFm/
+Z93HRSrTZpViynr5R88WpShNZHyW5/eB1+YSDslB1FagvhuX2570MRXxybys8bXN
+sxPI/9M6prI8AALBBmMCQD+2amH2Y9ukJy10WuYei943mrCsp1oosWjcoMADRCpj
+ZA2UwSzj67PBc5umDIAlhVRMX0zH/gLj54rfIkH5zLk=
+-----END RSA PRIVATE KEY-----
+```
+
+The root key above is checked in as ```priv/keys/insecure_root_key.pem```.
+
+<div class="pb"></div>
+
+The content of the sample ```insecure_root_cert.crt``` file is:
+
+```
+-----BEGIN CERTIFICATE-----
+MIICUjCCAbugAwIBAgIJAMI080XZPsPUMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
+BAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMQ8wDQYD
+VQQKDAZHRU5JVkkwHhcNMTUxMTI3MjMxMTQ0WhcNMTYxMTI2MjMxMTQ0WjBCMQsw
+CQYDVQQGEwJVUzEPMA0GA1UECAwGT3JlZ29uMREwDwYDVQQHDAhQb3J0bGFuZDEP
+MA0GA1UECgwGR0VOSVZJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDg5A1u
+Z5F36vQEYbMWCV4wY4OVmicYWEjjl/8YPA01tsz4x68i/NnlMNalqpGCIZ0AwqGI
+5DZAWWoR400L3SAmYD6sWj2L9ViIAPk3ceDU8olYrf/Nwj78wVoG7qqNLgMoBNM5
+84nlY4jy8zJ0Ka9WFBS2aDtB3Aulc1Q8ZfhuewIDAQABo1AwTjAdBgNVHQ4EFgQU
+4Sz8rAMA+dHymJTlZSkap65qnfswHwYDVR0jBBgwFoAU4Sz8rAMA+dHymJTlZSka
+p65qnfswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQDFOapf3DNEcXgp
+1u/g8YtBW24QsyB+RRavA9oKcFiIaHMkbJyUsOergwOXxBYhduuwVzQQo9P5nR0W
+RdUfwtE0GuaiC8WUmjR//vKwakj9Bjuu73ldYj9ji9+eXsL/gtpGWTIlHeGugpFs
+mVrUm0lY/n2ilJQ1hzBZ9lFLq0wfjw==
+-----END CERTIFICATE-----
+```
+
+The root certificate above is checked in as ```priv/certificates/insecure_root_cert.crt```.
+
+
+**DO NOT USE THE KEYS AND CERTIFICATES ABOVE IN PRODUCTION!<br>
+ANY PRODUCTION KEYS SHOULD BE GENERATED BY THE ORGANIZATION AND BE 4096 BITS LONG.**
+
+## Sample device certificate
+
+The sample device x.509 certificate, signed by the root certificate above,
+was generated with the following command:
+
+```Shell
+# Create the device key. In production, increase the bit size to 4096+
+openssl genrsa -out insecure_device_key.pem 1024
+
+# Create a certificate signing request
+openssl req -new -key insecure_device_key.pem -out insecure_device_cert.csr
+
+# Sign the signing request and create the insecure_device_cert.crt file
+openssl x509 -req -days 365 -in insecure_device_cert.csr \
+ -CA insecure_root_cert.crt -CAkey insecure_root_key.pem \
+ -set_serial 01 -out insecure_device_cert.crt
+```
+
+
+The ```insecure_device_cert.csr``` intermediate certificate signing
+request can be deleted once the three steps above have been executed.
+
+<div class="pb"></div>
+
+The content of the sample ```insecure_device_key.pem``` private key
+file, which has no password protection, is:
+
+```
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQCbb4jPAESKxarj3NJsgfQbhfTHZAP9kmram2TFnkzlCRxq4wQx
+BDC0O85PAMgZou0armGGbOu0si4cpVRioerCQJXnMWx1MI+3GUktW5ijI3ui+tYC
+sMQZtjSBVNXFZdoyZU2lPVWITOMZOe8o9vJ5DcUmFj9b2xV9jQ19oh+2+QIDAQAB
+AoGAVCYV0rs6YEaTNbke0k+ocB4dXrTu1CCoaKEn9TS2PGiqUdOFOWQjWe/myS6L
+JhXmd0Ng2P2uvayY+jknbh5qkNeEgTDhXJlAjiXlCADYArhgib+evRHgKz7RLTjX
+tGklbmc7oECTEpjkchJC5XcJhXzHCIjroyOJvBuAVa+SeAECQQDNC+KW7fTKQpiG
+YNGIt5MxCMjRparLz0fWod9J9U56wrWzU9Rnb7h9iwzTEJUEcVl9z8rnUdWtYQ8X
+3lsz5cDhAkEAwg+kDWbLtXWlIvXhhla7q0+RfKb8vu/gXnkXJa6rcJdJztKRbP3b
+9fehVeu9m+1+abahjC1zmQimwd2QVc8BGQJADbtfCGaVPzpoho9TWQmaRO1mrYuf
+vZh7IiejEYvpHpWNn53cmrTDsTyvti7lG/APYzqYRxeW7M6UOS/+AaLAYQJAJbEW
+AwhZPphoB59MO2RzNPXSYyyn4IoEwTSxuz7uy4KG8mXRmyK/a0m6i06rWDLLn8q6
+G9jkH/AfO35GP3RiWQJBAJLWBlKpHf8TxT65jAwxBhd9ZOkC2w0WidbSYjX9wkkD
+38K7ZDm1LSIR69Ut6tdwotkytXvDniOMPY6ENar5IUs=
+-----END RSA PRIVATE KEY-----
+```
+
+The content of the sample ```insecure_device_cert.crt``` file is:
+
+```
+-----BEGIN CERTIFICATE-----
+MIIB8zCCAVwCAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCVVMxDzANBgNV
+BAgMBk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxDzANBgNVBAoMBkdFTklWSTAe
+Fw0xNTExMjcyMzE0NTJaFw0xNjExMjYyMzE0NTJaMEIxCzAJBgNVBAYTAlVTMQ8w
+DQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMQ8wDQYDVQQKDAZHRU5J
+VkkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJtviM8ARIrFquPc0myB9BuF
+9MdkA/2SatqbZMWeTOUJHGrjBDEEMLQ7zk8AyBmi7RquYYZs67SyLhylVGKh6sJA
+lecxbHUwj7cZSS1bmKMje6L61gKwxBm2NIFU1cVl2jJlTaU9VYhM4xk57yj28nkN
+xSYWP1vbFX2NDX2iH7b5AgMBAAEwDQYJKoZIhvcNAQELBQADgYEAhbqVr9E/0M72
+9nc6DI+qgqsRSMfoyvA3Cmn/ECxl1ybGkuzO7sB8fGjgMQ9zzcb6q1uP3wGjPioq
+MymiYYjUmCTvzdvRBZ+6SDjrZfwUuYexiKqI9AP6XKaHlAL14+rK+6HN4uIkZcIz
+PwSMHih1bsTRpyY5Z3CUDcDJkYtVbYs=
+-----END CERTIFICATE-----
+```
+
+These files are checked into ```priv/certificates``` and ```priv/keys```.
+
+**DO NOT USE THE KEYS AND CERTIFICATES ABOVE IN PRODUCTION!<br>
+ANY PRODUCTION KEYS SHOULD BE GENERATED BY THE ORGANIZATION AND BE 4096 BITS LONG.**
+
+<div class="pb"></div>
+
+## RVI credentials format
+
+A credential is a JWT-encoded JSON structure, signed by the root X.509
+certificate's private key, describing the rights that the sender
+has. A received RVI credential is validated as follows.
+
+1. **Receive remote party's X.509 device certificate**<br>
+The TLS handshake process will exchange the X.509 certificates setup in
+the previous chapter.
+
+2. **Validate remote party's X.509 device certificate**<br>
+The received device X.509 certificate has its signature validated by the
+root X.509 certificate that is pre-provisioned in all RVI nodes.<br>
+The receiver now knows that the remote RVI node has an identiy
+generated by a trusted provsioning server using the private root key.
+
+3. **Receive one or more RVI credentials**<br>
+Each credential is encoded as JWT, signed by the root X.509 certificate.
+
+4. **Validate each RVI credential signature**<br>
+The root X.509 certificate is used to validate the signature of each
+received RVI credential. <br>
+A successful validation proves that the certificate was generated by a
+trusted provisioning server using the private root key.
+
+5. **Validate the credential-embedded X.509 device certificate**<br>
+Each received RVI credential will have its embedded device X.509
+certificate compared with the device X.509 certificate received in
+step 1 above.<br>
+A match proves that the certificate was generated by a trusted provisioning
+server explictly for the RVI node at the remote end.
+
+An RVI credential has the following format in its native JSON state:
+
+```JSON
+{
+ "create_timestamp": 1439925416,
+ "right_to_invoke": [
+ "jlr.com/vin/"
+ ],
+ "right_to_register": [
+ "jlr.com/backend/sota"
+ ],
+ "id": "insecure_cert",
+ "iss": "jaguarlandrover.com",
+ "device_cert": "",
+ "validity": {
+ "start": 1420099200,
+ "stop": 1925020799
+ }
+}
+```
+
+<div class="pb"></div>
+
+The members are as follows:
+
+Member | Description
+--------------------|---------------------
+create\_timestamp | Unix timestamp of when the credential was created
+right\_to\_invoke | A list of service prefixes that the sender has the right to invoke on any node that has registered matching services that start with the given string(s).
+right\_to\_register | A list of services that the sender has the right to to register for other nodes to invoke.
+id | A system-wide unique identifier for the credential.
+iss | The issuing organization.
+device_certificate | The PEM-encoded device X.509 certificate to match against the sender's TLS certificate.
+validity.start | The Unix timestamps when the credential becomes active.
+validity.stop | The Unix timestamps when the credential becomes inactive.
+
+## Generating RVI credentials
+
+To create a credential, tie it to a device X.509 certificate, and sign it with a root X.509 certificate private key, the following command is used:
+
+
+```Shell
+rvi_create_credential.py --cred_out="insecure_credential.json" \
+ --jwt_out='insecure_credential.jwt' \
+ --id="xxx" \
+ --issuer="genivi.org" \
+ --root_key=insecure_root_key.pem \
+ --device_cert=insecure_device_cert.crt \
+ --invoke='genivi.org/' \
+ --register='genivi.org/'
+```
+
+The following command line parameters are accepted:
+
+Parameter | Required | Description
+-------------- | -------- | ---------
+--cred\_out | No | Output file containing the JSON-formatted un-encoded credential.
+--jwt\_out | Yes | JWT-encoded, JSON-formatted, root keyp-signed credential.
+--issuer | Yes | Organization that issued the credential.
+--root\_key | Yes | Private, PEM-encoded root key to sign the credential. Must be the same key used to sign the root X.509 certificate.
+--device\_cert | Yes | The PEM-encoded device X.509 certificate to embed into the credential as the device_cert member.
+--invoke | Yes | Space separated list (within quotes) of RVI service prefixes that the owner of the credential has the right to invoke.
+--register | Yes | Space separated list (within quotes) of RVI service prefixes that the owner of the credential has the right to register for others to call (with the right credential).
+--start | No | The Unix timestamps when the credential becomes active.
+--stop | No | The Unix timestamps when the credential becomes inactive.
+
+The generated ```insecure_credential.json```
+and ```insecure_credential.jwt``` are checked into ```priv/credentials```.
diff --git a/doc/rvi_fragmentation.md b/doc/rvi_fragmentation.md
index 0992005..1cad4a5 100644
--- a/doc/rvi_fragmentation.md
+++ b/doc/rvi_fragmentation.md
@@ -1,9 +1,4 @@
-<style type="text/css" media="print">
- div.pagebreak
- {
- page-break-before: always;
- }
-</style>
+<style type="text/css" media="print"> div.pb { page-break-before: always; } </style>
# The RVI Core Fragmentation Protocol
## Abstract
@@ -49,7 +44,7 @@ Term | Meaning
`Server` | Receiving side of the interaction
`MTU` | Message Transfer Unit
-<div class="pagebreak"></div>
+<div class="pb"></div>
## System Overview
diff --git a/doc/rvi_protocol.md b/doc/rvi_protocol.md
index ce9c445..85c3290 100644
--- a/doc/rvi_protocol.md
+++ b/doc/rvi_protocol.md
@@ -1,9 +1,4 @@
-<style type="text/css" media="print">
- div.pagebreak
- {
- page-break-before: always;
- }
-</style>
+<style type="text/css" media="print"> div.pb { page-break-before: always; }</style>
Copyright (C) 2015-16 Jaguar Land Rover
This document is licensed under Creative Commons
@@ -12,13 +7,15 @@ Attribution-ShareAlike 4.0 International.
# RVI CORE PROTOCOL
This document describes the core protocol between two RVI nodes.
+For all examples below the certificates and credentials used are the samples
+created as described in [rvi_certificates.md](rvi_certificates.md).
+
# STANDARDS USED
-[1] Transport Layer Security - TLS (link)[https://tools.ietf.org/html/rfc5246]<br>
-[2] JSON Web Token RFC7519- JWT (link)[https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32]<br>
-[3] MessagePack - (link)[http://msgpack.org/index.html]<br>
-[4] base64url - (link)[https://en.wikipedia.org/wiki/Base64)<br>
-[5] Transport Layer Security (TLS) - (link)[https://en.wikipedia.org/wiki/Transport_Layer_Security]<br>
-[6] X.509 Certificates - (link)[https://en.wikipedia.org/wiki/X.509]<br>
+[1] [Transport Layer Security - TLS](https://tools.ietf.org/html/rfc5246)<br>
+[2] [JSON Web Token RFC7519 - JWT](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32)<br>
+[3] [MessagePack](http://msgpack.org/index.html)<br>
+[4] [base64url](https://en.wikipedia.org/wiki/Base64)<br>
+[5] [X.509 Certificates](https://en.wikipedia.org/wiki/X.509)<br>
# FEATURES COVERED BY PROTOCOL
1. **Authorization**<br>
@@ -33,7 +30,7 @@ is authorized to invoke.
Invoke services on remote RVI nodes.
# FEATURES NOT COVERED BY PROTOCOL
-For all but the last item, TLS 1.2 [5] an be used as an underlying
+For all but the last item, TLS 1.2 [1] an be used as an underlying
protocol to provide the features lacking in RVI Core protocol.
1. **Authentication**<br>
@@ -55,7 +52,7 @@ Public Key Infrastructure and certificate distribution.
6. **RVI Node Discovery**<br>
Allowing two unconnected RVI nodes to discover each other so that they can initiate connection.
-<div class="pagebreak"></div>
+<div class="pb"></div>
# OVERVIEW
The RVI core protocol is the default protocol used between two RVI
@@ -73,7 +70,7 @@ peer.
## Certificates and credentials
Three types of certificates and credentials are used by the RVI Core
-protocol in conjunciton with TLS. See [6] for details on X.509.
+protocol in conjunciton with TLS. See [5] for details on X.509.
1. **Root certificate [X.509]**<br>
Generated by a trusted provisioning server and pre-provisioned on all
@@ -90,7 +87,7 @@ services that the device has right to register.
Embeds the device X.509 certificate as a PEM-encoded string.
Signed by root cert.
-<div class="pagebreak"></div>
+<div class="pb"></div>
## Integration between TLS and RVI Core RVI
Client and server X.509 certificates are exchanged when the original
@@ -109,6 +106,14 @@ signed by the root x.509 certificate.
# PROTOCOL FLOW
+The messages used for illustration below are all presented in JSON format.
+Other encodings (currently only msgpack) are supported, but all RVI messages
+can be encoded as JSON. Each message is identified by a `"cmd": Cmd`
+attribute, where `Cmd` can be `"au"`, `"sa"`, `"rcv"`, `"frg"`, `"ping"`.
+
+The receiver of a message should be able to handle the presence of attributes
+other than the ones described here.
+
## Sequence Diagram
The diagram below outlines the sequence between the client and the server.
@@ -118,20 +123,38 @@ client-server terminology only denotes who initiates the connection
<img src="images/rvi_protocol_flow.png" alt="RVI Core protocol Sequence Diagram" style="width:800">
-<div class="pagebreak"></div>
+<div class="pb"></div>
## Authorize command
The ```authorize``` command contains a list of RVI credentials, each specifying
a set of services that the sender has the right to invoke on the receiving node,
and a set of services that the sender has the right to register.
-Please see the "RVI Credentials" chapter for detailss on RVI credentials.
+```json
+{"cmd" : "au",
+ "ver" : "1.1",
+ "creds": [ "eyJhbGci..." ]
+}
+```
+
+Attributes that may be present, but not currently used: `"addr"`, `"port"`.
+
+Please see the [rvi_certificates.md](rvi_certificates.md) document for details on RVI credentials.
## Service Announce command
The ```service_authorize``` command contains a list of services
available on the sender that match services listed in RVI credentials
received from the remote party.
+```json
+{"cmd" : "sa",
+ "stat" : "av" | "un",
+ "svcs" : [ "genivi.com/vin/d32cef88-.../hvac/seat_heat_left", ... ]
+}
+```
+
+The `"stat"` attribute can have the value `"av"` (available) or `"un"` (unavailable) and indicates the status of all services listed in `"svcs"`.
+
## Message command
The ```message``` command contains a service name and a number of
arguments to be presented to the corresponding service at the
@@ -139,6 +162,39 @@ receiving end. This is an asynchronous command that does not expect
an answer. Replies, publish/subscribe, and other higher-level
functions are (for now) outside the scope of the RVI Core protocol.
+```json
+{"cmd" : "rcv",
+ "tid" : Tid,
+ "mod" : Mod,
+ "data" : Data
+}
+```
+
+Note: The `"tid"` attribute is currently not checked by RVI.
+
+The content of `Data` is parsed and then encoded according to the
+protocol used to forward the message. The modules `proto_json_rpc` and
+`proto_msgpack` expect it to be a 'struct' (or corresponding), as follows:
+
+```json
+{"service" : ServiceName,
+ "timeout" : Timeout,
+ "parameters: Parameters
+}
+```
+
+`Timeout` is either a relative time in milliseconds, or an absolut time
+(unix time) in seconds.
+
+`Parameters` is a 'struct' containing named arguments to be passed to the
+service. It _can_ also contain RVI-specific arguments, named as `"rvi.Opt"`.
+Currently supported RVI options are
+
+* `"rvi.max_msg_size"` (integer > 0)
+* `"rvi.reliable"` (true | false)
+
+<div class="pb"></div>
+
## Double connect resolution
There is a risk that two parties try to initiate a connection to each
other in a race condition, creating two connections between them, as
@@ -179,7 +235,7 @@ Node1 Address | Node2 Address | Connecting side to be terminated
The connection is terminated regardless of its current protocol
session state.
-<div class="pagebreak"></div>
+<div class="pb"></div>
## Chunking of large messages
@@ -209,7 +265,8 @@ will currently be unreliable when using JSON encoding, due to escaping of
binary data.
When including these options in the "parameters" list of a message invocation,
-the names can be prefixed with "rvi.", e.g. "rvi.max_msg_size".
+the names can be prefixed with "rvi.", e.g. "rvi.max_msg_size", or
+"rvi.reliable".
**TODO**: Introduce timers. Currently there are none.
@@ -221,7 +278,7 @@ fragment (with a starting offset of 1), and then wait for the receiving side
to request more fragments using "frg-get" messages. When the sending side
receives a "frg-end" message, it will forget about the message.
-<div class="pagebreak"></div>
+<div class="pb"></div>
### Encoding
@@ -238,7 +295,7 @@ non-whitespace byte.
Configuring fragmentation encoding in RVI Core is done for the specific
data link module, e.g.
-```
+```json
{ data_link,
[ { dlink_tcp_rpc, gen_server,
[
@@ -251,241 +308,3 @@ data link module, e.g.
]
}
```
-
-# PROTOCOL DEFINITION
-This chapter describes the protocol message formats and how the various fields are used.
-
-For all examples below the following certifcates are used:
-
-## Sample root certificate
-The self signed root certificate used in the examples throughout this
-document was generated using the following commands:
-
-```Shell
-# Create root key pair
-openssl genrsa -out insecure_root_key.pem 1024
-
-# Create a self-signed root CA certificate, signed by the root key created above
-openssl req -x509 -new -nodes -key insecure_root_key.pem -days 365 -out insecure_root_cert.crt
-```
-
-The content of the sample ```insecure_root_key.pem``` private key
-file, which has no password protection, is:
-
-```
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDg5A1uZ5F36vQEYbMWCV4wY4OVmicYWEjjl/8YPA01tsz4x68i
-/NnlMNalqpGCIZ0AwqGI5DZAWWoR400L3SAmYD6sWj2L9ViIAPk3ceDU8olYrf/N
-wj78wVoG7qqNLgMoBNM584nlY4jy8zJ0Ka9WFBS2aDtB3Aulc1Q8ZfhuewIDAQAB
-AoGAfD+C7CxsQkSc7I7N0q76SuGwIUc5skmUe6nOViVXZwXH2Or55+qqt+VzsbO7
-EJphk7n0ZR0wm/zKjXd3acaRq5j3fOyXip9fDoNj+oUKAowDJ9vub0NOPpU2bgb0
-xDnDeR0BRVBOTWqrkDeDPBSxw5RlJunesDkamAmj4VXHHgECQQDzqDtaEuEZ7x7d
-kJKCmfGyP01s+YPlquDgogzAeMAsz17TFt8JS4RO0rX71+lmx7qqpRqIxVXIsR58
-NI2Th7tRAkEA7Eh1C1WahLCxojQOam/l7GyE+2ignZYExqonOOvsk6TG0LcFm7W9
-x39ouTlfChM26f8VYAsPxIrvsDlI1DDCCwJBAITmA8lzdrgQhwNOsbrugLg6ct63
-kcuZUqLzgIUS168ZRJ1aYjjNqdLcd0pwT+wxkI03FKv5Bns6sGgKuhX3+KECQFm/
-Z93HRSrTZpViynr5R88WpShNZHyW5/eB1+YSDslB1FagvhuX2570MRXxybys8bXN
-sxPI/9M6prI8AALBBmMCQD+2amH2Y9ukJy10WuYei943mrCsp1oosWjcoMADRCpj
-ZA2UwSzj67PBc5umDIAlhVRMX0zH/gLj54rfIkH5zLk=
------END RSA PRIVATE KEY-----
-```
-
-The root key above is checked in as ```priv/keys/insecure_root_key.pem```.
-
-<div class="pagebreak"></div>
-
-The content of the sample ```insecure_root_cert.crt``` file is:
-
-```
------BEGIN CERTIFICATE-----
-MIICUjCCAbugAwIBAgIJAMI080XZPsPUMA0GCSqGSIb3DQEBCwUAMEIxCzAJBgNV
-BAYTAlVTMQ8wDQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMQ8wDQYD
-VQQKDAZHRU5JVkkwHhcNMTUxMTI3MjMxMTQ0WhcNMTYxMTI2MjMxMTQ0WjBCMQsw
-CQYDVQQGEwJVUzEPMA0GA1UECAwGT3JlZ29uMREwDwYDVQQHDAhQb3J0bGFuZDEP
-MA0GA1UECgwGR0VOSVZJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDg5A1u
-Z5F36vQEYbMWCV4wY4OVmicYWEjjl/8YPA01tsz4x68i/NnlMNalqpGCIZ0AwqGI
-5DZAWWoR400L3SAmYD6sWj2L9ViIAPk3ceDU8olYrf/Nwj78wVoG7qqNLgMoBNM5
-84nlY4jy8zJ0Ka9WFBS2aDtB3Aulc1Q8ZfhuewIDAQABo1AwTjAdBgNVHQ4EFgQU
-4Sz8rAMA+dHymJTlZSkap65qnfswHwYDVR0jBBgwFoAU4Sz8rAMA+dHymJTlZSka
-p65qnfswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQDFOapf3DNEcXgp
-1u/g8YtBW24QsyB+RRavA9oKcFiIaHMkbJyUsOergwOXxBYhduuwVzQQo9P5nR0W
-RdUfwtE0GuaiC8WUmjR//vKwakj9Bjuu73ldYj9ji9+eXsL/gtpGWTIlHeGugpFs
-mVrUm0lY/n2ilJQ1hzBZ9lFLq0wfjw==
------END CERTIFICATE-----
-```
-
-The root certificate above is checked in as ```priv/certificates/insecure_root_cert.crt```.
-
-
-**DO NOT USE THE KEYS AND CERTIFICATES ABOVE IN PRODUCTION!<br>
-ANY PRODUCTION KEYS SHOULD BE GENERATED BY THE ORGANIZATION AND BE 4096 BITS LONG.**
-
-## Sample device certificate
-
-The sample device x.509 certificate, signed by the root certificate above,
-was generated with the following command:
-
-```Shell
-# Create the device key. In production, increase the bit size to 4096+
-openssl genrsa -out insecure_device_key.pem 1024
-
-# Create a certificate signing request
-openssl req -new -key insecure_device_key.pem -out insecure_device_cert.csr
-
-# Sign the signing request and create the insecure_device_cert.crt file
-openssl x509 -req -days 365 -in insecure_device_cert.csr \
- -CA insecure_root_cert.crt -CAkey insecure_root_key.pem \
- -set_serial 01 -out insecure_device_cert.crt
-```
-
-
-The ```insecure_device_cert.csr``` intermediate certificate signing
-request can be deleted once the three steps above have been executed.
-
-The content of the sample ```insecure_device_key.pem``` private key
-file, which has no password protection, is:
-
-```
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQCbb4jPAESKxarj3NJsgfQbhfTHZAP9kmram2TFnkzlCRxq4wQx
-BDC0O85PAMgZou0armGGbOu0si4cpVRioerCQJXnMWx1MI+3GUktW5ijI3ui+tYC
-sMQZtjSBVNXFZdoyZU2lPVWITOMZOe8o9vJ5DcUmFj9b2xV9jQ19oh+2+QIDAQAB
-AoGAVCYV0rs6YEaTNbke0k+ocB4dXrTu1CCoaKEn9TS2PGiqUdOFOWQjWe/myS6L
-JhXmd0Ng2P2uvayY+jknbh5qkNeEgTDhXJlAjiXlCADYArhgib+evRHgKz7RLTjX
-tGklbmc7oECTEpjkchJC5XcJhXzHCIjroyOJvBuAVa+SeAECQQDNC+KW7fTKQpiG
-YNGIt5MxCMjRparLz0fWod9J9U56wrWzU9Rnb7h9iwzTEJUEcVl9z8rnUdWtYQ8X
-3lsz5cDhAkEAwg+kDWbLtXWlIvXhhla7q0+RfKb8vu/gXnkXJa6rcJdJztKRbP3b
-9fehVeu9m+1+abahjC1zmQimwd2QVc8BGQJADbtfCGaVPzpoho9TWQmaRO1mrYuf
-vZh7IiejEYvpHpWNn53cmrTDsTyvti7lG/APYzqYRxeW7M6UOS/+AaLAYQJAJbEW
-AwhZPphoB59MO2RzNPXSYyyn4IoEwTSxuz7uy4KG8mXRmyK/a0m6i06rWDLLn8q6
-G9jkH/AfO35GP3RiWQJBAJLWBlKpHf8TxT65jAwxBhd9ZOkC2w0WidbSYjX9wkkD
-38K7ZDm1LSIR69Ut6tdwotkytXvDniOMPY6ENar5IUs=
------END RSA PRIVATE KEY-----
-```
-
-<div class="pagebreak"></div>
-
-The content of the sample ```insecure_device_cert.crt``` file is:
-
-```
------BEGIN CERTIFICATE-----
-MIIB8zCCAVwCAQEwDQYJKoZIhvcNAQELBQAwQjELMAkGA1UEBhMCVVMxDzANBgNV
-BAgMBk9yZWdvbjERMA8GA1UEBwwIUG9ydGxhbmQxDzANBgNVBAoMBkdFTklWSTAe
-Fw0xNTExMjcyMzE0NTJaFw0xNjExMjYyMzE0NTJaMEIxCzAJBgNVBAYTAlVTMQ8w
-DQYDVQQIDAZPcmVnb24xETAPBgNVBAcMCFBvcnRsYW5kMQ8wDQYDVQQKDAZHRU5J
-VkkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJtviM8ARIrFquPc0myB9BuF
-9MdkA/2SatqbZMWeTOUJHGrjBDEEMLQ7zk8AyBmi7RquYYZs67SyLhylVGKh6sJA
-lecxbHUwj7cZSS1bmKMje6L61gKwxBm2NIFU1cVl2jJlTaU9VYhM4xk57yj28nkN
-xSYWP1vbFX2NDX2iH7b5AgMBAAEwDQYJKoZIhvcNAQELBQADgYEAhbqVr9E/0M72
-9nc6DI+qgqsRSMfoyvA3Cmn/ECxl1ybGkuzO7sB8fGjgMQ9zzcb6q1uP3wGjPioq
-MymiYYjUmCTvzdvRBZ+6SDjrZfwUuYexiKqI9AP6XKaHlAL14+rK+6HN4uIkZcIz
-PwSMHih1bsTRpyY5Z3CUDcDJkYtVbYs=
------END CERTIFICATE-----
-```
-
-These files are checked into ```priv/certifcates``` and ```priv/keys```.
-
-**DO NOT USE THE KEYS AND CERTIFICATES ABOVE IN PRODUCTION!<br>
-ANY PRODUCTION KEYS SHOULD BE GENERATED BY THE ORGANIZATION AND BE 4096 BITS LONG.**
-
-
-## RVI credentials format
-
-A credential is a JWT-encoded JSON structure, signed by the root X.509
-certificate's private key, describing the rights that the sender
-has. A received RVI credential is validated as follows.
-
-1. **Receive remote party's X.509 device certificate**<br>
-The TLS handshake process will exchange the X.509 certificates setup in
-the previous chapter.
-
-2. **Validate remote party's X.509 device certificate**<br>
-The received device X.509 certificate has its signature validated by the
-root X.509 certificate that is pre-provisioned in all RVI nodes.<br>
-The receiver now knows that the remote RVI node has an identiy
-generated by a trusted provsioning server using the private root key.
-
-3. **Receive one or more RVI credentials**<br>
-Each credential is encoded as JWT, signed by the root X.509 certificate.
-
-4. **Validate each RVI credential signature**<br>
-The root X.509 certificate is used to validate the signature of each
-received RVI credential. <br>
-A successful validation proves that the certificate was generated by a
-trusted provisioning server using the private root key.
-
-5. **Validate the credential-embedded X.509 device certificate**<br>
-Each received RVI credential will have its embedded device X.509
-certificate compared with the device X.509 certificate received in
-step 1 above.<br>
-A match proves that the certificate was generated by a trusted provisioning
-server explictly for the RVI node at the remote end.
-
-An RVI credential has the following format in its native JSON state:
-
-```JSON
-{
- "create_timestamp": 1439925416,
- "right_to_invoke": [
- "jlr.com/vin/"
- ],
- "right_to_register": [
- "jlr.com/backend/sota"
- ],
- "id": "insecure_cert",
- "iss": "jaguarlandrover.com",
- "device_cert": "",
- "validity": {
- "start": 1420099200,
- "stop": 1925020799
- }
-}
-```
-
-<div class="pagebreak"></div>
-
-The members are as follows:
-
-Member | Description
---------------------|---------------------
-create\_timestamp | Unix timestamp of when the credential was created
-right\_to\_invoke | A list of service prefixes that the sender has the right to invoke on any node that has registered matching services that start with the given string(s).
-right\_to\_register | A list of services that the sender has the right to to register for other nodes to invoke.
-id | A system-wide unique identifier for the credential.
-iss | The issuing organization.
-device_certificate | The PEM-encoded device X.509 certificate to match against the sender's TLS certificate.
-validity.start | The Unix timestamps when the credential becomes active.
-validity.stop | The Unix timestamps when the credential becomes inactive.
-
-## Generating RVI credentials
-
-To create a credential, tie it to a device X.509 certificate, and sign it with a root X.509 certificate private key, the following command is used:
-
-
-```Shell
-rvi_create_credential.py --cred_out="insecure_credential.json" \
- --jwt_out='insecure_credential.jwt' \
- --id="xxx" \
- --issuer="genivi.org" \
- --root_key=insecure_root_key.pem \
- --device_cert=insecure_device_cert.crt \
- --invoke='genivi.org/' \
- --register='genivi.org/'
-```
-
-The following command line parameters are accepted:
-
-Parameter | Required | Description
--------------- | -------- | ---------
---cred\_out | No | Output file containing the JSON-formatted un-encoded credential.
---jwt\_out | Yes | JWT-encoded, JSON-formatted, root keyp-signed credential.
---issuer | Yes | Organization that issued the credential.
---root\_key | Yes | Private, PEM-encoded root key to sign the credential. Must be the same key used to sign the root X.509 certificate.
---device\_cert | Yes | The PEM-encoded device X.509 certificate to embed into the credential as the device_cert member.
---invoke | Yes | Space separated list (within quotes) of RVI service prefixes that the owner of the credential has the right to invoke.
---register | Yes | Space separated list (within quotes) of RVI service prefixes that the owner of the credential has the right to register for others to call (with the right credential).
---start | No | The Unix timestamps when the credential becomes active.
---stop | No | The Unix timestamps when the credential becomes inactive.
-
-The generated ```insecure_credential.json```
-and ```insecure_credential.jwt``` are checked into ```priv/credentials```.
diff --git a/doc/rvi_services.md b/doc/rvi_services.md
index 11d77da..ce32997 100644
--- a/doc/rvi_services.md
+++ b/doc/rvi_services.md
@@ -1,9 +1,4 @@
-<style type="text/css" media="print">
- div.pagebreak
- {
- page-break-before: always;
- }
-</style>
+<style type="text/css" media="print"> div.pb { page-break-before: always; } </style>
Copyright (C) 2014, 2015 Jaguar Land Rover
This document is licensed under Creative Commons
@@ -43,7 +38,7 @@ manage all subpaths below itself.
A typical service name for a vehicle that specifies a service to lock a door:
message:jaguarlandrover.com/vin/1HGCM82633A004352/services/body/lock
-
+
Services can freely be defined and implemented by anyone for any purpose as long
as the global name space is not violated (hence the organization). RVI defines
a couple of core services that are specified by this document.
@@ -65,7 +60,7 @@ Procedure Calls (RPC) (JSON-RPC).
"reporting_interval": 5000
}
}
-
+
* jsonrpc - JSON-RPC version number.
* id - Request ID, used to match the response to the request.
* method - Method to be invoked. For RVI the method is ```message```.
@@ -106,10 +101,10 @@ The parameters are:
* keyid - Unique key ID.
* key - JWT encoded key, signed by the private root key, where the
payload is a JWK-formatted JSON object.
-
+
After receiving a key the device will typically store it in its key store.
-<div class="pagebreak"></div>
+<div class="pb"></div>
##### Provision Certificate
@@ -133,7 +128,7 @@ The parameters are:
* certid - Unique certificate ID.
* checksum - The md5 checksum calculated over the entire certificate
* certificate - The certificate encoded as base64.
-
+
After receiving a certificate the device will typically store it in its certificate
store.
@@ -155,11 +150,11 @@ Erase a certificate from the device's certificate store.
The parameters are:
* certid - Unique certificate ID.
-
+
After receiving an erase certificate request the device must remove it from its
certificate store.
-<div class="pagebreak"></div>
+<div class="pb"></div>
##### Clear Certificates
@@ -180,7 +175,6 @@ The parameters are:
* dummy - Placeholder parameter
-
After receiving an erase certificate request the device must remove all certificates
from its certificate store.
@@ -204,7 +198,7 @@ from it.
The parameters are:
* certid - Unique certificate ID.
-
+
After receiving a revoke certificate request the device must add it to its
certificate blacklist. When the device is presented with a blacklisted certificate
or a certificate that has been derived from a blacklisted certificate it must
@@ -214,6 +208,8 @@ reject that certificate as invalid.
Services to manage device configuration.
+<div class="pb"></div>
+
##### Read Configuration Variables
Retrieve the value of one or more configuration variables from the device.
@@ -234,7 +230,7 @@ The server sends to the device:
The parameters are:
* variable - The name of the variable.
-
+
The device responds with:
{
@@ -251,14 +247,14 @@ The device responds with:
]
}
}
-
+
The parameters are:
* vin - The VIN of the device reporting the variable.
* variables - An array of dictionaries with variable names and values.
* value - The value of the variable.
-<div class="pagebreak"></div>
+<div class="pb"></div>
##### Write Configuration Variables
@@ -315,7 +311,7 @@ Sequence of events:
6. Once the client receives the `finish` message and has assembled and verified
the download it sends `download_complete` to the server with a status indicator.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Notify
@@ -364,7 +360,7 @@ The parameters are:
match the ID from the `notify` message this message is sent in response
to.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Start Download
@@ -411,7 +407,7 @@ The parameters are:
may not arrive in order.
* msg - File chunk encoded with base64.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Finish Transmission
@@ -456,7 +452,7 @@ The parameters are:
match the ID from the `notify` message this message is sent in response
to.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Cancel Download
@@ -506,7 +502,7 @@ The parameters are:
* channels - An array with the data channels to subscribe to.
* reporting_interval - The reporting interval in milliseconds [ms].
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Unsubscribe
@@ -563,7 +559,7 @@ The parameters are:
JSON data type. In particular `value` can be a dictionary in itself, as it is
with the `location` channel.
-<div class="pagebreak"></div>
+<div class="pb"></div>
Currently defined channels:
@@ -617,7 +613,7 @@ The parameters are:
```trunk``` is the rear trunk.<br>
```hood``` is the rear hood.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Start / Stop Engine
@@ -662,7 +658,7 @@ The parameters are:
```open``` open the trunk.<br>
```close``` close the trunk.
-<div class="pagebreak"></div>
+<div class="pb"></div>
#### Horn
Activate the horn.
@@ -701,8 +697,8 @@ The parameters are:
* duration - The duration, in milliseconds, that the lights should be on for
+<div class="pb"></div>
-
#### Windows
Open/close windows and other hatches
@@ -718,6 +714,8 @@ Open/close windows and other hatches
}
}
+<div class="pb"></div>
+
The parameters are:
* windows - The windows to operate on
@@ -839,7 +837,7 @@ will be listed.
}
}
-<div class="pagebreak"></div>
+<div class="pb"></div>
The parameters are:
diff --git a/test/rvi_core_SUITE.erl b/test/rvi_core_SUITE.erl
index bd1a996..63a36ca 100644
--- a/test/rvi_core_SUITE.erl
+++ b/test/rvi_core_SUITE.erl
@@ -141,9 +141,9 @@ groups() ->
t_register_lock_service,
t_register_sota_service,
t_call_lock_service,
- t_call_sota_service,
- t_multicall_sota_service,
- t_remote_call_lock_service,
+ %% t_call_sota_service,
+ %% t_multicall_sota_service,
+ %% t_remote_call_lock_service,
t_no_errors
]}
].
@@ -327,19 +327,35 @@ t_multicall_sota_service(_Config) ->
client3,
client4,
client5]],
- collect(Pids).
+ Ref = erlang:send_after(5000, self(), collect_timeout),
+ collect(Pids, Ref).
-collect([{Pid, Ref} | T]) ->
+collect([{_, Ref} | T] = L, TRef) ->
receive
{'DOWN', Ref, _, _, {ok, ok}} ->
- collect(T);
+ collect(T, Ref);
{'DOWN', Ref, _, _, Reason} ->
- [exit(P, kill) || {P,_} <- T],
- error(Reason)
+ flush_reqs(T),
+ error(Reason);
+ {timeout, TRef, collect_timeout} ->
+ flush_reqs(T),
+ error(timeout)
after 30000 ->
+ flush_reqs(L),
error(timeout)
end;
-collect([]) ->
+collect([], _) ->
+ ok.
+
+flush_reqs([{Pid, Ref}|T]) ->
+ receive
+ {'DOWN', Ref, _, _, _} ->
+ flush_reqs(T)
+ after 0 ->
+ erlang:demonitor(Ref),
+ exit(Pid, kill)
+ end;
+flush_reqs([]) ->
ok.
@@ -367,7 +383,7 @@ call_sota_service_(RegName, Data) ->
{message, Other} ->
ct:log("wrong message: ~p", [Other]),
error({unmatched, Other})
- after 30000 ->
+ after 5000 ->
error(timeout)
end.
@@ -456,7 +472,11 @@ sota_bin() ->
"00000000000000000000000000000000000000000000000000">>.
json_result({ok, {http_response, {_V1, _V2}, 200, _Text, _Hdr}, JSON}) ->
- jsx:decode(JSON).
+ jsx:decode(JSON);
+json_result(Other) ->
+ ct:log("json_result(~p)", [Other]),
+ error({unexpected, Other}).
+
start_json_rpc_server(Port) ->
{ok, Pid} = exo_http_server:start(Port, [{request_handler,
@@ -464,7 +484,7 @@ start_json_rpc_server(Port) ->
save({server,Port}, Pid),
Pid.
-handle_body(Socket, Request, Body, St) ->
+handle_body(Socket, _Request, Body, _St) ->
ct:log("handle_body(Body = ~p)", [Body]),
JSON = jsx:decode(Body),
ct:log("Got JSON Req: ~p", [JSON]),
@@ -889,15 +909,15 @@ hex(X) when X >= 10, X =< 15 ->
$a + X - 10.
-json_rpc(URL, Method, Args) ->
- Req = binary_to_list(
- iolist_to_binary(
- exo_json:encode({struct, [{"jsonrpc", "2.0"},
- {"id", 1},
- {"method", Method},
- {"params", Args}]}))),
- Hdrs = [{'Content-Type', "application/json"}],
- exo_http:wpost(URL, {1,1}, Hdrs, Req, 1000).
+%% json_rpc(URL, Method, Args) ->
+%% Req = binary_to_list(
+%% iolist_to_binary(
+%% exo_json:encode({struct, [{"jsonrpc", "2.0"},
+%% {"id", 1},
+%% {"method", Method},
+%% {"params", Args}]}))),
+%% Hdrs = [{'Content-Type', "application/json"}],
+%% exo_http:wpost(URL, {1,1}, Hdrs, Req, 1000).
t_no_errors(Config) ->
no_errors(?config(test_nodes, Config), ?config(test_dir, Config)).