summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Wiger <ulf@wiger.net>2016-02-24 23:04:36 +0100
committerUlf Wiger <ulf@wiger.net>2016-02-24 23:04:36 +0100
commit2f7d12a5b7843228052e9b9ed3919733652a5f89 (patch)
treef3ce8b8344ab37106dc104662592cab3057b08f1
parentcb97583d4a105667cc2d2b590f0e6351e94f7d2e (diff)
parent86618c1bed88a4057daa971cbe8a84afecd8b57a (diff)
downloadrvi_core-2f7d12a5b7843228052e9b9ed3919733652a5f89.tar.gz
Merge pull request #87 from uwiger/uw-0_5_0
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--Makefile25
-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
-rwxr-xr-xdebian_template/rules2
-rw-r--r--deps/setup/src/setup_gen.erl14
-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--priv/config/add_bt_apps.config5
-rw-r--r--priv/config/rvi_common.config10
-rw-r--r--priv/config/rvi_debian.config344
-rw-r--r--priv/config/rvi_ubuntu.config34
-rw-r--r--priv/config/rvi_yocto.config50
-rw-r--r--priv/test_config/backend.config20
-rw-r--r--priv/test_config/basic_backend.config1
-rw-r--r--priv/test_config/basic_sample.config3
-rw-r--r--priv/test_config/bt_backend.config1
-rw-r--r--priv/test_config/sample.config10
-rw-r--r--python/rvi_ws.py141
-rw-r--r--raspbian_template/README.Debian10
-rw-r--r--raspbian_template/README.source6
-rw-r--r--raspbian_template/changelog5
-rw-r--r--raspbian_template/compat1
-rw-r--r--raspbian_template/control13
-rw-r--r--raspbian_template/copyright11
-rw-r--r--raspbian_template/docs0
-rwxr-xr-xraspbian_template/rules21
-rwxr-xr-xraspbian_template/rvi.init70
-rw-r--r--raspbian_template/rvi.lintian-overrides3
-rw-r--r--raspbian_template/rvi.postinst45
-rw-r--r--raspbian_template/rvi.postrm40
-rw-r--r--raspbian_template/rvi.service18
-rw-r--r--raspbian_template/source/format1
-rw-r--r--raspbian_template/source/lintian-overrides1
-rw-r--r--scripts/rvi_ctl.template25
-rwxr-xr-xscripts/rvi_install113
-rw-r--r--test/rvi_core_SUITE.erl181
55 files changed, 1909 insertions, 637 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/Makefile b/Makefile
index 1c594cc..72bbb4b 100644
--- a/Makefile
+++ b/Makefile
@@ -71,6 +71,9 @@ ubuntu_clean:
debian_clean:
rm -rf ./debian_build
+raspbian_clean:
+ rm -rf ./raspbian_build
+
rpm_clean:
rm -rf ./rpm/BUILD/* \
./rpm/BUILDROOT/* \
@@ -137,6 +140,28 @@ debian_package: clean debian_clean escript
(cd ./debian_build/rvi-$(VERSION); debuild -uc -us)
+# Create a raspbian package
+raspbian_package: clean raspbian_clean escript
+ install --mode=0755 -d ./raspbian_build
+
+# Pack up all relevant files, and debian/, necessary for a build.
+# Add rvi-$(VERSION) at the beginning of each file so
+# that they get packed up into a correctly named subdirectory
+#
+ tar czf ./raspbian_build/rvi_$(VERSION).orig.tar.gz \
+ --exclude-vcs --transform="s|^|./rvi-$(VERSION)/|" \
+ $(SRC_LIST) \
+ raspbian_template
+ rm -rf raspbian/missing-sources
+# Unpack the created tar file
+ (cd ./raspbian_build; tar xf rvi_$(VERSION).orig.tar.gz)
+# Move the debian template to be the debian package
+ mv ./raspbian_build/rvi-$(VERSION)/raspbian_template ./raspbian_build/rvi-$(VERSION)/debian
+ install -d -m 0755 ./raspbian_build/rvi-$(VERSION)/debian/missing-sources
+# Descend into the unpacked directory and build.
+ (cd ./raspbian_build/rvi-$(VERSION); debuild --prepend-path /usr/local/bin -uc -us)
+
+
rpm: rpmclean rpm_tarball
rpmbuild --define "_topdir $$PWD/rpm" -ba rpm/SPECS/rvi-$(VERSION).spec
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/debian_template/rules b/debian_template/rules
index b6b8c0a..fc2f6c0 100755
--- a/debian_template/rules
+++ b/debian_template/rules
@@ -18,4 +18,4 @@ override_dh_auto_install:
# Copy out rvi_ctl to /usr/bin
install -D -m 0755 ./debian/rvi/usr/lib/rvi_core/rvi_ctl ./debian/rvi/usr/bin/rvi_ctl
# Install default config
- install -D -m 0644 ./priv/config/rvi_ubuntu.config ./debian/rvi/etc/rvi/rvi.config
+ install -D -m 0644 ./priv/config/rvi_debian.config ./debian/rvi/etc/rvi/rvi.config
diff --git a/deps/setup/src/setup_gen.erl b/deps/setup/src/setup_gen.erl
index 7a74107..9f95030 100644
--- a/deps/setup/src/setup_gen.erl
+++ b/deps/setup/src/setup_gen.erl
@@ -83,7 +83,10 @@ help() ->
%% option.
%% * `{remove_apps, Apps}' - Remove `Apps' from the list of applications.
%% * `{sort_app, App, Before}' - Change the sort order so that `App' comes
-%% before `Before'.
+%% before `Before'. `Before' can be either an application
+%% name or a list of names. In the latter case, `App'
+%% is inserted before either of the applications in
+%% the list, whichever comes first.
%% * `{include, ConfigFile}' - include options from the given file. The file
%% is processed using `file:script/2'.
%% * `{include_lib, ConfigFile}' - As above, but ConfigFile is named as with
@@ -600,7 +603,8 @@ sort_apps(Options, Apps) ->
lists:foldl(fun({sort_app, A, Before}, Acc) ->
case is_in_set(A, Acc) of
{true, App} ->
- insert_before(Acc -- [App], App, Before);
+ insert_before(Acc -- [App], App,
+ mk_set(Before));
false ->
abort("Cannot re-sort ~p - not found~n", [A])
end;
@@ -636,6 +640,12 @@ del_from_set(As, Set) ->
end
end, Set, As).
+%% ensure that this is a 'set' (well, at least a list)
+mk_set(Set) when is_list(Set) ->
+ Set;
+mk_set(Entry) ->
+ [Entry].
+
is_in_set(Entry, Set) ->
A = if is_tuple(Entry) -> element(1, Entry);
is_atom(Entry) -> Entry
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/priv/config/add_bt_apps.config b/priv/config/add_bt_apps.config
new file mode 100644
index 0000000..9eb9c9b
--- /dev/null
+++ b/priv/config/add_bt_apps.config
@@ -0,0 +1,5 @@
+%% -*- erlang -*-
+[
+ {add_apps, [bt, dlink_bt]},
+ {sort_app, bt, rvi_core} %% start bt before rvi_core (not required)
+].
diff --git a/priv/config/rvi_common.config b/priv/config/rvi_common.config
index c8aa389..0b6cb8d 100644
--- a/priv/config/rvi_common.config
+++ b/priv/config/rvi_common.config
@@ -9,8 +9,6 @@
%% Configuration include file for rvi config files
%%
Out = filename:absname(proplists:get_value(outdir, OPTIONS)).
-LagerRoot = Out ++ "/log/lager".
-LagerDebugFmt = [time,"<",module,"/",line,">",message,"\n"].
%% Parameters for simpler modification
Env = fun(V, Def) ->
@@ -22,6 +20,9 @@ Env = fun(V, Def) ->
end
end.
+LogDir = Env("RVI_LOGDIR", Out ++ "/log").
+LagerRoot = LogDir ++ "/lager".
+LagerDebugFmt = [time,"<",module,"/",line,">",message,"\n"].
LogLevel = Env("RVI_LOGLEVEL", info).
[
%% All erlang apps needed to fire up a node. Do not touch.
@@ -63,11 +64,9 @@ LogLevel = Env("RVI_LOGLEVEL", info).
service_edge,
authorize,
schedule,
- bt,
dlink,
dlink_tcp,
dlink_tls,
- dlink_bt,
dlink_sms,
proto_bert,
proto_json,
@@ -80,7 +79,8 @@ LogLevel = Env("RVI_LOGLEVEL", info).
[
{setup,
[
- {home, Out}
+ {home, Out},
+ {log_dir, LogDir}
]},
{lager,
[
diff --git a/priv/config/rvi_debian.config b/priv/config/rvi_debian.config
new file mode 100644
index 0000000..4e1eeb5
--- /dev/null
+++ b/priv/config/rvi_debian.config
@@ -0,0 +1,344 @@
+%% -*- erlang -*-
+
+%% Copyright (C) 2014,2015,2016 Jaguar Land Rover
+%%
+%% This program is licensed under the terms and conditions of the
+%% Mozilla Public License, version 2.0. The full text of the
+%% Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+%%
+%% Configuration file for RVI deployed on Debian systems.
+%%
+%% See ../CONFIGURE.md for a details on the configuration process
+%% itself.
+%%
+
+%% Parameters for simpler modification
+Env = fun(V, Def) ->
+ case os:getenv(V) of
+ false -> Def;
+ Str when is_integer(Def) -> list_to_integer(Str);
+ Str when is_atom(Def) -> list_to_atom(Str);
+ Str -> Str
+ end
+ end.
+IPPort = fun(IP, Port) ->
+ IP ++ ":" ++ integer_to_list(Port)
+ end.
+MyPort = Env("RVI_PORT", 9000).
+MyIP = Env("RVI_MYIP", "127.0.0.1").
+MyNodeAddr = Env("RVI_MY_NODE_ADDR", IPPort(MyIP, MyPort)).
+BackendIP = Env("RVI_BACKEND", "38.129.64.31").
+BackendPort = Env("RVI_BACKEND_PORT", 8807).
+LogLevel = Env("RVI_LOGLEVEL", notice).
+
+[
+ %% All erlang apps needed to fire up a node. Do not touch.
+ {include_lib, "rvi_core/priv/config/rvi_common.config"},
+
+ %%
+ %% Custom environment settings
+ %% for all apps running on the node.
+ %%
+ {env,
+ [
+
+ %% All RVI configuration is done here.
+ %%
+ %% Please note that the rvi_node.sh launch script
+ %% can still override the port range and static nodes
+ %% through its command line parameters.
+ %%
+ %% Value substitution:
+ %% All string values under the rvi tuple tree are scanned
+ %% for specific dokens during startup. If a token is
+ %% found, it will be replaced with a value referenced by it.
+ %% Tokens can one of the following:
+ %%
+ %% $rvi_file(FileName,Default) - File content
+ %% When an $rvi_file() token is encountered, the first line of
+ %% the referenced file is read. The line (without the newline)
+ %% replaces the token.
+ %%
+ %% Example:
+ %% { node_service_prefix, "genivi.org/vin/$rvi_file(/etc/vin,default_vin)"},
+ %%
+ %% will be substituted with the first line from the file
+ %% /etc/vin:
+ %%
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
+ %%
+ %% If /etc/vin cannot be opened, the value default_vin
+ %% will be used instead.
+ %%
+ %%
+ %% $rvi_env(EnvironemtnName,Default) - Environment variable
+ %% When an $rvi_env() token is encountered, the value of
+ %% the Linux process environment variable (such as $HOME) is read
+ %% to replace the token.
+ %%
+ %% Example:
+ %% { node_service_prefix, "genivi.org/vin/$rvi_env(VIN,default_vin)"},
+ %%
+ %% will be substituted with the value of the $VIN environment
+ %% variable:
+ %%
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
+ %%
+ %% If VIN is not a defined environment variable, the value
+ %% default_vin will be used instead.
+ %%
+ %%
+ %% $rvi_uuid(Default) - Unique machine identifier
+ %% When an $rvi_uuid() token is encountered, the UUID of the root
+ %% disk used by the system is read to replace the token.
+ %% The UUID of the root disk is retrieved by opening /proc/cmdline
+ %% and extracting the root=UUID=[DiskUUID] value.
+ %% This value is generated at system install time and is reasonably
+ %% world wide unique.
+ %%
+ %% Example:
+ %% { node_service_prefix, "genivi.org/vin/$uuid(default_vin)"},
+ %%
+ %% will be substituted with the value of the root disk UUID:
+ %%
+ %% { node_service_prefix,
+ %% "genivi.org/vin/afc0a6d8-0264-4f8a-bb3e-51ff8655b51c"},
+ %%
+ %% If the root UUID cannot be retrieved, the value default_vin
+ %% will be used instead.
+ %%
+
+ {rvi_core,
+ [
+ %% Specify the node address that data_link uses to listen to
+ %% incoming traffic from other rvi nodes.
+ %%
+ %% This is the address that is announced to
+ %% other rvi nodes during service discovery and should be
+ %% forwarded through firewalls and port forwarding to to the port
+ %% specified by the configuration entry rvi -> components ->
+ %% data_link ->json_rpc_server (see below).
+ %%
+ %% If this node is sitting behind a firewall and cannot
+ %% receive incomign connections on any address, its
+ %% node_address should be set to "0.0.0.0:0" to inform
+ %% the remote node that it should not attempt to
+ %% connect back to self.
+ { node_address, MyNodeAddr },
+
+ %% Specify the prefix of all services that this rvi node is hosting.
+ %%
+ %% All local services regsitering with service edge will be prefixed with
+ %% the string below when they are announced to remote rvi nodes
+ %% that connect to this node (using the address specified
+ %% by node_address above).
+ %%
+ %% If a locally connected service registers itself as
+ %% "hvac/fan_speed", and the node_service_prefix is
+ %% "genivi.org/vin/1234/", this node will announce the service
+ %% "genivi.org/vin/1234/hvac/fan_speed" as being available
+ %% to remotely connected rvi nodes.
+ %%
+ %% Two rvi nodes should never have the same node_service_prefix
+ %% value unless all services add a system-wide unique name
+ %% to it.
+ %%
+ { node_service_prefix, "genivi.org/vin/$rvi_uuid(default_vin)/"},
+
+
+ %% Routing rules determine how to get a message targeting a specific
+ %% service to its destination.
+ %%
+ %% Please note that if a remotely initiated (== client) data link is
+ %% available and has announced that the targeted service is available,
+ %% that data link will be used regardless of what it is.
+ %%
+ %% In other words, if you setup routing rules for how to reach out
+ %% to a vehicle using SMS, and that vehicle happens to have a 3G
+ %% connection up when the message is sent, the 3G connection will be used.
+ %%
+ %% We will add a blacklist feature in the future to optionally block
+ %% such opportunistic routing in the future.
+ %%
+ { routing_rules,
+ [
+ %% Service name prefix that rules are specified for
+ %% The service prefix with the longest match against the service targeted
+ %% by the message will be used.
+ %%
+ %% Example: Targeted service = genivi.org/backend/sota/get_updates
+ %%
+ %% Prefix1: { "genivi.org/backend", [...]}
+ %% Prefix2: { "genivi.org/backend/sota", [...]}
+ %%
+ %% Prefix2 will be used.
+ %%
+ %% This allows you, for example, to setup different servers
+ %% for different types of services (SOTA, remote door unlock,
+ %% HVAC etc).
+ %%
+
+ %% Make sure to have a default if you don't want your message
+ %% to error out immediately. With a default the message will
+ %% be queued until it times out, waiting for a remote node
+ %% to connect and announce that it can handle the targeted service.
+ { "",
+ [
+ { proto_json_rpc, dlink_tcp_rpc}
+ ]
+ },
+
+ { "genivi.org/backend/",
+ %% Which protocol and data link pair to use when transmitting the message
+ %% to the targeted service. If a pair reports a failure, the next pair is tried.
+ [
+ { proto_json_rpc, { dlink_tcp_rpc,
+ % {"38.129.64.13", 8807}
+ [ { target, IPPort(BackendIP, BackendPort) } ]}}
+ ]
+ },
+
+ %% Used to communicate with vehicles
+ { "genivi.org/vin/",
+ [
+ { proto_json_rpc, { dlink_tcp_rpc, [ broadcast, { interface, "wlan0" } ] } },
+ { proto_json_rpc, { server_3g, [ initiate_outbound ]} },
+
+ %% Protocols can have hinting as well.
+ %% In this case JSON-RPC should only be used if the
+ %% resulting message size can fit in an SMS (140 bytes).
+
+ { { proto_json_rpc, [ { max_msg_size, 140 } ] } , server_sms }
+ ]
+ }
+ ]
+ },
+
+ { components,
+ [
+ %% A note about JSON-RPC calls vs gen_server calls:
+ %%
+ %% All locally connected services communicate with Service Edge
+ %% through JSON-RPC.
+ %%
+ %% Communication between the internal RVI components, however,
+ %% can be either JSON-RPC or gen_server calls.
+ %%
+ %% JSON-RPC calls provide compatability with replacement components
+ %% written in languages other than Erlang.
+ %%
+ %% Gen_server calls provide native erlang inter-process calls that
+ %% are about 4x faster than JSON-RPC when transmitting large data volumes.
+ %%
+ %% If one or more of the components below are replaced with external
+ %% components, use JSON-RPC by specifying IP address and port in
+ %% json_rpc_address for all interfaced by the external components.
+ %%
+ %% If you are running an all-native erlang system, use gen_server calls
+ %% by specifying gen_server for all components
+ %%
+ %% Please note that communication between two RVI nodes are
+ %% not affected by this since dlink_tcp will use
+ %% JSON-RPC to communicate ( using the address/port specified
+ %% by proto_json_rpc).
+ %%
+
+ {rvi_common,
+ [
+ {rvi_log, gen_server,
+ [{json_rpc_address, MyPort+9}]
+ }
+ ]},
+ %% Service_edge.
+ %% The service_edge tuple is a top level configuration
+ %% container for everything about service edge.
+ %% In theory, we can support multiple different service edge
+ %% components (written in different languages).
+ %%
+ %% However, until we've sorted out internal routing, we will
+ %% only support the native service_edge_rpc component,
+ %% accessed either as a gen_server or through JSON-RPC.
+ %%
+ {service_edge,
+ [
+ %% Service_edge_rpc component is used as a gen_server
+ { service_edge_rpc, gen_server,
+ [
+ %% JSON-RPC address will be translated to
+ %% an URL looking like this:
+ %% http://127.0.0.1:8801
+ %%
+ %% This URL is used both for communication with
+ %% locally connected services and for intra-component
+ %% communication in case the access method for
+ %% service_edge_rpc is specified as json_rpc.
+ { json_rpc_address, { MyIP, MyPort+1 } }, % {"127.0.0.1",8801}
+ { msgpack_rpc_address, { MyIP, MyPort + 21 } },
+
+ %% Websocket is used for websocket access, preferably
+ %% through the rvi.js package available for Javascript
+ %% apps in browsers and crosswalk who wants to interface
+ %% RVI.
+ { websocket, [ { port, MyPort+8}]} % 9008
+ ]
+ }
+ ]
+ },
+ { service_discovery,
+ [ { service_discovery_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+2 }} % {"127.0.0.1",9002}
+ ]
+ }
+ ]
+ },
+ { schedule,
+ [ { schedule_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+3 }} % {"127.0.0.1",9003}
+ ]
+ }
+ ]
+ },
+ { authorize,
+ [ { authorize_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+4 } } % {"127.0.0.1",9004}
+ ]
+ }
+ ]
+ },
+ { protocol,
+ [ { proto_json_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+5 } } % {"127.0.0.1",9005}
+ ]
+ }
+ ]
+ },
+ { data_link,
+ [ { dlink_tcp_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+6 } }, % 9006
+ %% data link TCP server specifies the port we should
+ %% listen to for incoming connections
+ %% from other rvi nodes.
+ %% A specific NIC address can also be specified
+ %% through the {ip, "192.168.0.1" } tuple.
+ { server_opts, [ { port, MyPort+7 }]},
+ { persistent_connections, [ IPPort(BackendIP, BackendPort) ]}
+ ]
+ },
+ { dlink_tls_rpc, gen_server,
+ [
+ { json_rpc_address, { MyIP, MyPort+11} },
+ { server_opts, [ {port, MyPort+10} ]}
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]}
+ ]}
+].
diff --git a/priv/config/rvi_ubuntu.config b/priv/config/rvi_ubuntu.config
index 57ffd37..65319db 100644
--- a/priv/config/rvi_ubuntu.config
+++ b/priv/config/rvi_ubuntu.config
@@ -1,14 +1,12 @@
%% -*- erlang -*-
-%% Copyright (C) 2014, Jaguar Land Rover
+%% Copyright (C) 2014,2015,2016 Jaguar Land Rover
%%
%% This program is licensed under the terms and conditions of the
%% Mozilla Public License, version 2.0. The full text of the
%% Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
%%
-%% Configuration file for the (in-vehicle) IVI used by the hvac_demo
-%%
-%% See ../hvac_demo/README.md for details on the demo.
+%% Configuration file for RVI deployed on Ubuntu systems.
%%
%% See ../CONFIGURE.md for a details on the configuration process
%% itself.
@@ -62,12 +60,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% replaces the token.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$rvi_file(/etc/vin,default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$rvi_file(/etc/vin,default_vin)"},
%%
%% will be substituted with the first line from the file
%% /etc/vin:
%%
- %% { node_service_prefix, "jlr.com/vin/2GKEG25HXP4093669"},
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
%%
%% If /etc/vin cannot be opened, the value default_vin
%% will be used instead.
@@ -79,12 +77,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% to replace the token.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$rvi_env(VIN,default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$rvi_env(VIN,default_vin)"},
%%
%% will be substituted with the value of the $VIN environment
%% variable:
%%
- %% { node_service_prefix, "jlr.com/vin/2GKEG25HXP4093669"},
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
%%
%% If VIN is not a defined environment variable, the value
%% default_vin will be used instead.
@@ -99,12 +97,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% world wide unique.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$uuid(default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$uuid(default_vin)"},
%%
%% will be substituted with the value of the root disk UUID:
%%
%% { node_service_prefix,
- %% "jlr.com/vin/afc0a6d8-0264-4f8a-bb3e-51ff8655b51c"},
+ %% "genivi.org/vin/afc0a6d8-0264-4f8a-bb3e-51ff8655b51c"},
%%
%% If the root UUID cannot be retrieved, the value default_vin
%% will be used instead.
@@ -137,15 +135,15 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%%
%% If a locally connected service registers itself as
%% "hvac/fan_speed", and the node_service_prefix is
- %% "jlr.com/vin/1234/", this node will announce the service
- %% "jlr.com/vin/1234/hvac/fan_speed" as being available
+ %% "genivi.org/vin/1234/", this node will announce the service
+ %% "genivi.org/vin/1234/hvac/fan_speed" as being available
%% to remotely connected rvi nodes.
%%
%% Two rvi nodes should never have the same node_service_prefix
%% value unless all services add a system-wide unique name
%% to it.
%%
- { node_service_prefix, "jlr.com/vin/$rvi_uuid(default_vin)/"},
+ { node_service_prefix, "genivi.org/vin/$rvi_uuid(default_vin)/"},
%% Routing rules determine how to get a message targeting a specific
@@ -168,10 +166,10 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% The service prefix with the longest match against the service targeted
%% by the message will be used.
%%
- %% Example: Targeted service = jlr.com/backend/sota/get_updates
+ %% Example: Targeted service = genivi.org/backend/sota/get_updates
%%
- %% Prefix1: { "jlr.com/backend", [...]}
- %% Prefix2: { "jlr.com/backend/sota", [...]}
+ %% Prefix1: { "genivi.org/backend", [...]}
+ %% Prefix2: { "genivi.org/backend/sota", [...]}
%%
%% Prefix2 will be used.
%%
@@ -190,7 +188,7 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
]
},
- { "jlr.com/backend/",
+ { "genivi.org/backend/",
%% Which protocol and data link pair to use when transmitting the message
%% to the targeted service. If a pair reports a failure, the next pair is tried.
[
@@ -201,7 +199,7 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
},
%% Used to communicate with vehicles
- { "jlr.com/vin/",
+ { "genivi.org/vin/",
[
{ proto_json_rpc, { dlink_tcp_rpc, [ broadcast, { interface, "wlan0" } ] } },
{ proto_json_rpc, { server_3g, [ initiate_outbound ]} },
diff --git a/priv/config/rvi_yocto.config b/priv/config/rvi_yocto.config
index 6e7863a..76a1064 100644
--- a/priv/config/rvi_yocto.config
+++ b/priv/config/rvi_yocto.config
@@ -1,14 +1,13 @@
%% -*- erlang -*-
-%% Copyright (C) 2014, Jaguar Land Rover
+%% Copyright (C) 2014,2015,2016 Jaguar Land Rover
%%
%% This program is licensed under the terms and conditions of the
%% Mozilla Public License, version 2.0. The full text of the
%% Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
%%
-%% Configuration file for the (in-vehicle) IVI used by the hvac_demo
-%%
-%% See ../hvac_demo/README.md for details on the demo.
+%% Configuration file for RVI built and deployed with the
+%% Yocto Project
%%
%% See ../CONFIGURE.md for a details on the configuration process
%% itself.
@@ -23,14 +22,14 @@ Env = fun(V, Def) ->
Str -> Str
end
end.
+IPPort = fun(IP, Port) ->
+ IP ++ ":" ++ integer_to_list(Port)
+ end.
MyPort = Env("RVI_PORT", 9000).
MyIP = Env("RVI_MYIP", "127.0.0.1").
-MyNodeAddr = Env("RVI_MY_NODE_ADDR", "0.0.0.0:0").
+MyNodeAddr = Env("RVI_MY_NODE_ADDR", IPPort(MyIP, MyPort)).
BackendIP = Env("RVI_BACKEND", "38.129.64.31").
BackendPort = Env("RVI_BACKEND_PORT", 8807).
-IPPort = fun(IP, Port) ->
- IP ++ ":" ++ integer_to_list(Port)
- end.
LogLevel = Env("RVI_LOGLEVEL", notice).
[
@@ -62,12 +61,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% replaces the token.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$rvi_file(/etc/vin,default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$rvi_file(/etc/vin,default_vin)"},
%%
%% will be substituted with the first line from the file
%% /etc/vin:
%%
- %% { node_service_prefix, "jlr.com/vin/2GKEG25HXP4093669"},
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
%%
%% If /etc/vin cannot be opened, the value default_vin
%% will be used instead.
@@ -79,12 +78,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% to replace the token.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$rvi_env(VIN,default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$rvi_env(VIN,default_vin)"},
%%
%% will be substituted with the value of the $VIN environment
%% variable:
%%
- %% { node_service_prefix, "jlr.com/vin/2GKEG25HXP4093669"},
+ %% { node_service_prefix, "genivi.org/vin/2GKEG25HXP4093669"},
%%
%% If VIN is not a defined environment variable, the value
%% default_vin will be used instead.
@@ -99,12 +98,12 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% world wide unique.
%%
%% Example:
- %% { node_service_prefix, "jlr.com/vin/$uuid(default_vin)"},
+ %% { node_service_prefix, "genivi.org/vin/$uuid(default_vin)"},
%%
%% will be substituted with the value of the root disk UUID:
%%
%% { node_service_prefix,
- %% "jlr.com/vin/afc0a6d8-0264-4f8a-bb3e-51ff8655b51c"},
+ %% "genivi.org/vin/afc0a6d8-0264-4f8a-bb3e-51ff8655b51c"},
%%
%% If the root UUID cannot be retrieved, the value default_vin
%% will be used instead.
@@ -112,12 +111,6 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
{rvi_core,
[
-
- {key_pair, {openssl_pem, "rvi_core/priv/sample_keys/insecure_device_bkey_priv.pem"}},
- {provisioning_key, "rvi_core/priv/sample_keys/insecure_root_key_pub.pem"},
- {authorize_jwt, "rvi_core/priv/sample_keys/insecure_device_key_pub_sign.jwt"},
- {cert_dir, "rvi_core/priv/sample_certs"},
-
%% Specify the node address that data_link uses to listen to
%% incoming traffic from other rvi nodes.
%%
@@ -143,15 +136,15 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%%
%% If a locally connected service registers itself as
%% "hvac/fan_speed", and the node_service_prefix is
- %% "jlr.com/vin/1234/", this node will announce the service
- %% "jlr.com/vin/1234/hvac/fan_speed" as being available
+ %% "genivi.org/vin/1234/", this node will announce the service
+ %% "genivi.org/vin/1234/hvac/fan_speed" as being available
%% to remotely connected rvi nodes.
%%
%% Two rvi nodes should never have the same node_service_prefix
%% value unless all services add a system-wide unique name
%% to it.
%%
- { node_service_prefix, "jlr.com/vin/$rvi_uuid(default_vin)/"},
+ { node_service_prefix, "genivi.org/vin/$rvi_uuid(default_vin)/"},
%% Routing rules determine how to get a message targeting a specific
@@ -174,10 +167,10 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% The service prefix with the longest match against the service targeted
%% by the message will be used.
%%
- %% Example: Targeted service = jlr.com/backend/sota/get_updates
+ %% Example: Targeted service = genivi.org/backend/sota/get_updates
%%
- %% Prefix1: { "jlr.com/backend", [...]}
- %% Prefix2: { "jlr.com/backend/sota", [...]}
+ %% Prefix1: { "genivi.org/backend", [...]}
+ %% Prefix2: { "genivi.org/backend/sota", [...]}
%%
%% Prefix2 will be used.
%%
@@ -196,7 +189,7 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
]
},
- { "jlr.com/backend/",
+ { "genivi.org/backend/",
%% Which protocol and data link pair to use when transmitting the message
%% to the targeted service. If a pair reports a failure, the next pair is tried.
[
@@ -207,7 +200,7 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
},
%% Used to communicate with vehicles
- { "jlr.com/vin/",
+ { "genivi.org/vin/",
[
{ proto_json_rpc, { dlink_tcp_rpc, [ broadcast, { interface, "wlan0" } ] } },
{ proto_json_rpc, { server_3g, [ initiate_outbound ]} },
@@ -281,6 +274,7 @@ LogLevel = Env("RVI_LOGLEVEL", notice).
%% communication in case the access method for
%% service_edge_rpc is specified as json_rpc.
{ json_rpc_address, { MyIP, MyPort+1 } }, % {"127.0.0.1",8801}
+ { msgpack_rpc_address, { MyIP, MyPort + 21 } },
%% Websocket is used for websocket access, preferably
%% through the rvi.js package available for Javascript
diff --git a/priv/test_config/backend.config b/priv/test_config/backend.config
index 361b3da..106a1ba 100644
--- a/priv/test_config/backend.config
+++ b/priv/test_config/backend.config
@@ -1,14 +1,14 @@
%% -*- erlang -*-
{ok, CurDir} = file:get_cwd().
[
- {include_lib, "rvi_core/priv/config/rvi_backend.config"},
- {set_env,
- [
- {rvi_core,
- [{device_key, "$HOME/../../basic_backend_keys/device_key.pem"},
- {root_cert, "$HOME/../../root_keys/root_cert.crt"},
- {device_cert, "$HOME/../../basic_backend_keys/device_cert.crt"},
- {cred_dir, "$HOME/../../basic_backend_creds"}
- ]}
- ]}
+ {include_lib, "rvi_core/priv/config/rvi_backend.config"}
+ %% {set_env,
+ %% [
+ %% {rvi_core,
+ %% [{device_key, "$HOME/../../basic_backend_keys/device_key.pem"},
+ %% {root_cert, "$HOME/../../root_keys/root_cert.crt"},
+ %% {device_cert, "$HOME/../../basic_backend_keys/device_cert.crt"},
+ %% {cred_dir, "$HOME/../../basic_backend_creds"}
+ %% ]}
+ %% ]}
].
diff --git a/priv/test_config/basic_backend.config b/priv/test_config/basic_backend.config
index 0c6aaa6..8640d76 100644
--- a/priv/test_config/basic_backend.config
+++ b/priv/test_config/basic_backend.config
@@ -2,7 +2,6 @@
{ok, CurDir} = file:get_cwd().
[
{include_lib, "rvi_core/priv/test_config/backend.config"},
- {remove_apps, [bt, dlink_bt]},
{set_env,
[{rvi_core,
[
diff --git a/priv/test_config/basic_sample.config b/priv/test_config/basic_sample.config
index 56f9a4c..794f3b2 100644
--- a/priv/test_config/basic_sample.config
+++ b/priv/test_config/basic_sample.config
@@ -1,6 +1,5 @@
%% -*- erlang -*-
{ok, CurDir} = file:get_cwd().
[
- {include_lib, "rvi_core/priv/test_config/sample.config"},
- {remove_apps, [bt, dlink_bt]}
+ {include_lib, "rvi_core/priv/test_config/sample.config"}
].
diff --git a/priv/test_config/bt_backend.config b/priv/test_config/bt_backend.config
index 45cc5db..cb665d1 100644
--- a/priv/test_config/bt_backend.config
+++ b/priv/test_config/bt_backend.config
@@ -1,6 +1,7 @@
%% -*- erlang -*-
[
{include_lib, "rvi_core/priv/test_config/backend.config"},
+ {include_lib, "rvi_core/priv/config/add_bt_apps.config"},
{remove_apps, [dlink_tcp, dlink_tls]},
{set_env,
diff --git a/priv/test_config/sample.config b/priv/test_config/sample.config
index ea84a30..3238563 100644
--- a/priv/test_config/sample.config
+++ b/priv/test_config/sample.config
@@ -6,11 +6,11 @@
[
{rvi_core,
[
- {node_service_prefix, "jlr.com/vin/abc"},
- {device_key, "$HOME/../../basic_sample_keys/device_key.pem"},
- {root_cert, "$HOME/../../root_keys/root_cert.crt"},
- {device_cert, "$HOME/../../basic_sample_keys/device_cert.crt"},
- {cred_dir, "$HOME/../../basic_sample_creds"}
+ {node_service_prefix, "jlr.com/vin/abc"}
+ %% {device_key, "$HOME/../../basic_sample_keys/device_key.pem"},
+ %% {root_cert, "$HOME/../../root_keys/root_cert.crt"},
+ %% {device_cert, "$HOME/../../basic_sample_keys/device_cert.crt"},
+ %% {cred_dir, "$HOME/../../basic_sample_creds"}
]}
]}
].
diff --git a/python/rvi_ws.py b/python/rvi_ws.py
new file mode 100644
index 0000000..cb73591
--- /dev/null
+++ b/python/rvi_ws.py
@@ -0,0 +1,141 @@
+#
+# Copyright (C) 2016, Jaguar Land Rover
+#
+# This program is licensed under the terms and conditions of the
+# Mozilla Public License, version 2.0. The full text of the
+# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+#
+# rvi_ws 0.1.0
+#
+# This module is the websocket implementation of for RVI services.
+
+# To use this code you will follow these steps.
+# 1. Import the rvi_ws class using "import rvi_ws"
+# 2. Instantiate a rvi_ws_client class object specifying the bundle_id, debug params, and host
+# ex.
+# rvi_client = rvi_ws.rvi_ws_client(bundle_id = <string bundle name>, host = <string host url>, debug = <True|False>)
+# 3. Create a dictionary of services and their callback functions. The keys of the dictionary should be the string service name
+# name and the value should be the pointer to the callback function.
+# ex.
+# def hello(...):
+# ...
+# def world(...):
+# ...
+#
+# rvi_client.register_services({"hello":hello, "world":world})
+#
+# 4. Register and run the services by invoking the services_run() function in the rvi_ws_client class. This will block all other code
+# execution until the websocket connection closes in which case will return a None value.
+# ex.
+# rvi_client.services_run()
+#
+# Optionally there are a few more utility functions included in the rvi_ws_client class mainly setting properties of the class.
+#
+
+import websocket
+import json
+import threading
+
+try:
+ import thread
+# TODO use Threading instead of _thread in python3
+except ImportError:
+ import _thread as thread
+
+# rvi_ws_client will be in charge of handling all communication via websockets between the service bundle and RVI.
+
+class rvi_ws_client:
+
+ def __init__(self, bundle_id = None, debug = False, host = "ws://localhost:9008"):
+
+ self.DEBUG = debug
+ self.service_bundle_id = bundle_id
+ self.callback_funcs = {}
+ self.host = host
+
+ # set_ws_debug takes in parameter debug_status which is type bool. Will toggle on or off all websocket related debug messages.
+ def set_ws_debug(self):
+
+ if self.DEBUG:
+ websocket.enableTrace(True)
+ else:
+ websocket.enableTrace(False)
+
+ # on_error will print an error if the websocket application encounters any and prints if debug is toggled on
+ def on_error(self,ws, error):
+ pass
+
+ # TODO unregister service for clean close of websocket, for time being will just print out debug
+ def on_close(self,ws):
+ pass
+ # What to do on the open of the application. Note we must register_services for this to do anything.
+ def on_open(self,ws):
+
+ def run(*args):
+
+ payload = {}
+ payload['json-rpc'] = "2.0"
+ payload['id'] = "0"
+ payload['method'] = "register_service"
+
+ for service_name, callback in self.callback_funcs.items():
+ payload['params'] = {"service_name":self.service_bundle_id+"/"+service_name}
+ ws.send(json.dumps(payload))
+
+ opening = threading.Thread(target=run)
+ opening.start()
+
+ # on_message will route the message from the websocket to it's corresponding callback function that registered the service
+ def on_message(self,ws, message):
+
+ message_dict = json.loads(message)
+
+ try:
+ if (message_dict['method'] == 'message') and (message_dict['params']['service_name'][(2+len(self.service_bundle_id)):] in self.callback_funcs):
+ self.callback_funcs[message_dict['params']['service_name'][(2+len(self.service_bundle_id)):]](**message_dict['params']['parameters'])
+ except:
+ pass
+
+
+ # set_host will expect a string parameter that will change the class variable host which will connect to our websocket server
+ def set_host(self,target_host):
+
+ self.host = target_host
+ return True
+
+ # register_services will take in a dictionary of services to register.
+ # The keys of the dictionary will be the service name and the value will be the callback function
+ # will return success on successfully changing the class' callback function dictionary
+ # Please make sure that the service name keys are strings.
+ # For example:
+ # services = {
+ # <service_name>:<callback function>,
+ # <service_name>:<callback function>,
+ # ....
+ # }
+ def register_services(self,services):
+
+ self.callback_funcs = services
+ return True
+ # set_service_bundle expects a string parameter that will change the class variable service_bundle_id as the bundle_id tro register
+ def set_service_bundle(self, service_bundle):
+ self.service_bundle_id = service_bundle
+ return True
+
+ # services_run is a callable function for after everything is set to start the websocket client.
+ # Will block all remaining code until the websocket connection is broken. In which case will return None
+ def services_run(self):
+
+ if self.service_bundle_id == None:
+ raise NameError('No Specified bundle_id')
+
+ self.set_ws_debug()
+
+ ws = websocket.WebSocketApp(self.host,
+ on_message = self.on_message,
+ on_error = self.on_error,
+ on_close = self.on_close)
+ ws.on_open = self.on_open
+
+ return ws.run_forever()
+
diff --git a/raspbian_template/README.Debian b/raspbian_template/README.Debian
new file mode 100644
index 0000000..f80c683
--- /dev/null
+++ b/raspbian_template/README.Debian
@@ -0,0 +1,10 @@
+rvi for Debian
+--------------
+
+Will rely on existing Erlang installation to work.
+
+We will copy out the Erlang VM BEAM files to /opt/rvi and the configuration files to /etc/opt/rvi
+
+/opt/rvi/rvi.sh is the main control program.
+
+ -- Magnus Feuer <mfeuer@jaguarlandrover.com> Fri, 27 Nov 2015 15:34:39 -0800
diff --git a/raspbian_template/README.source b/raspbian_template/README.source
new file mode 100644
index 0000000..9e3c927
--- /dev/null
+++ b/raspbian_template/README.source
@@ -0,0 +1,6 @@
+rvi for Debian
+--------------
+
+
+ -- Magnus Feuer <mfeuer@jaguarlandrover.com> Fri, 27 Nov 2015 15:34:39 -0800
+
diff --git a/raspbian_template/changelog b/raspbian_template/changelog
new file mode 100644
index 0000000..3d774a4
--- /dev/null
+++ b/raspbian_template/changelog
@@ -0,0 +1,5 @@
+rvi (0.5.0-1) jessie; urgency=low
+
+ * Initial release
+
+ -- Magnus Feuer <mfeuer@jaguarlandrover.com> Fri, 27 Nov 2015 15:34:39 -0800
diff --git a/raspbian_template/compat b/raspbian_template/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/raspbian_template/compat
@@ -0,0 +1 @@
+9
diff --git a/raspbian_template/control b/raspbian_template/control
new file mode 100644
index 0000000..f0836a6
--- /dev/null
+++ b/raspbian_template/control
@@ -0,0 +1,13 @@
+Source: rvi
+Section: net
+Priority: optional
+Maintainer: Magnus Feuer <mfeuer@jaguarlandrover.com>
+Build-Depends: debhelper (>= 9), libbluetooth-dev
+Standards-Version: 3.9.6
+Homepage: https://github.com/PDXostc/rvi_core
+
+Package: rvi
+Architecture: any
+Depends: ${shlibs:Depends}, ${misc:Depends}, bluez, python-jsonrpclib (>= 0.1.3-1), python (>= 2.7.9-1)
+Description: Remote Vehicle Interaction
+ GENIVI Remote Vehicle Interaction Core
diff --git a/raspbian_template/copyright b/raspbian_template/copyright
new file mode 100644
index 0000000..89597cf
--- /dev/null
+++ b/raspbian_template/copyright
@@ -0,0 +1,11 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: rvi
+Source: http://github.com/PDXostc/rvi_core
+
+Files: *
+Copyright: Copyright 2014,2015,2016 Jaguar Land Rover
+License: MPL-2.0
+ This program is licensed under the terms and conditions of the
+ Mozilla Public License, version 2.0. The full text of the
+ Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+
diff --git a/raspbian_template/docs b/raspbian_template/docs
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/raspbian_template/docs
diff --git a/raspbian_template/rules b/raspbian_template/rules
new file mode 100755
index 0000000..b6b8c0a
--- /dev/null
+++ b/raspbian_template/rules
@@ -0,0 +1,21 @@
+#!/usr/bin/make -f
+# -*- makefile --*
+
+# Uncomment this to turn on verbose mode.
+export DH_VERBOSE=1
+
+%:
+ dh $@
+
+override_dh_auto_install:
+ ./scripts/rvi_install \
+ -s ./debian/rvi \
+ -k priv/keys/insecure_device_key.pem \
+ -r priv/certificates/insecure_root_cert.crt \
+ -d priv/certificates/insecure_device_cert.crt \
+ -c priv/credentials/insecure_credential.jwt \
+ -l ./debian/rvi/var/log/rvi ./debian/rvi/usr/lib/rvi_core
+# Copy out rvi_ctl to /usr/bin
+ install -D -m 0755 ./debian/rvi/usr/lib/rvi_core/rvi_ctl ./debian/rvi/usr/bin/rvi_ctl
+# Install default config
+ install -D -m 0644 ./priv/config/rvi_ubuntu.config ./debian/rvi/etc/rvi/rvi.config
diff --git a/raspbian_template/rvi.init b/raspbian_template/rvi.init
new file mode 100755
index 0000000..9cd4e59
--- /dev/null
+++ b/raspbian_template/rvi.init
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Copyright (C) 2014, Jaguar Land Rover
+#
+# This program is licensed under the terms and conditions of the
+# Mozilla Public License, version 2.0. The full text of the
+# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+#
+#
+# Init.d script to start and stop an RVI system installed
+# through an RPM.
+#
+### BEGIN INIT INFO
+# Provides: rvi
+# Required-Start: $network $syslog $remote_fs
+# Required-Stop: $network $syslog $remote_fs
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start/Stop RVI node at boot time
+# Description: Manage Remote Vehicle Interaction Node run state.
+### END INIT INFO
+
+export PATH="/bin/:/usr/bin:/sbin:/usr/sbin"
+export HOME=/usr/lib/rvi_core
+. /lib/lsb/init-functions
+
+set -e
+
+case "$1" in
+ start)
+ log_daemon_msg "Starting Remote Vehicle Interaction Node..." "rvi"
+ if /usr/bin/rvi_ctl -c /etc/rvi/rvi.config start; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+ ;;
+ stop)
+ log_daemon_msg "Stopping Remote Vehicle Interaction Node..." "rvi"
+ if /usr/bin/rvi_ctl stop; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+ ;;
+
+ restart)
+ log_daemon_msg "Restarting Remote Vehicle Interaction Node..." "rvi"
+ if /usr/bin/rvi_ctl restart; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+ ;;
+
+ force-reload)
+ log_daemon_msg "Restarting Remote Vehicle Interaction Node..." "rvi"
+ if /usr/bin/rvi_ctl restart; then
+ log_end_msg 0
+ else
+ log_end_msg 1
+ fi
+ ;;
+ *)
+ log_action_msg "Usage: /etc/init.d/rvi {start|stop|restart}"
+ exit 1
+esac
+
+exit 0
+
diff --git a/raspbian_template/rvi.lintian-overrides b/raspbian_template/rvi.lintian-overrides
new file mode 100644
index 0000000..c307106
--- /dev/null
+++ b/raspbian_template/rvi.lintian-overrides
@@ -0,0 +1,3 @@
+executable-not-elf-or-script
+missing-dep-for-interpreter
+binary-without-manpage \ No newline at end of file
diff --git a/raspbian_template/rvi.postinst b/raspbian_template/rvi.postinst
new file mode 100644
index 0000000..10c11fe
--- /dev/null
+++ b/raspbian_template/rvi.postinst
@@ -0,0 +1,45 @@
+#!/bin/sh
+# postinst script for rvi
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postinst> `configure' <most-recently-configured-version>
+# * <old-postinst> `abort-upgrade' <new version>
+# * <conflictor's-postinst> `abort-remove' `in-favour' <package>
+# <new-version>
+# * <postinst> `abort-remove'
+# * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
+# <failed-install-package> <version> `removing'
+# <conflicting-package> <version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+. /usr/share/debconf/confmodule
+
+case "$1" in
+
+ configure)
+ # Set up our config
+ cat /proc/sys/kernel/random/uuid > /etc/rvi/device_id
+ echo "RVI Device ID set to $(cat /etc/rvi/device_id) in /etc/rvi/device_id"
+ #DEBHELPER#
+ ;;
+
+ abort-upgrade|abort-remove|abort-deconfigure)
+ exit 0
+ ;;
+
+ *)
+ echo "postinst called with unknown argument \`$1'" >&2
+ exit 1
+ ;;
+
+esac
+
+db_stop
+
+exit 0
diff --git a/raspbian_template/rvi.postrm b/raspbian_template/rvi.postrm
new file mode 100644
index 0000000..a0c5d5b
--- /dev/null
+++ b/raspbian_template/rvi.postrm
@@ -0,0 +1,40 @@
+#!/bin/sh
+# postrm script for rvi
+#
+# see: dh_installdeb(1)
+
+set -e
+
+# summary of how this script can be called:
+# * <postrm> `remove'
+# * <postrm> `purge'
+# * <old-postrm> `upgrade' <new-version>
+# * <new-postrm> `failed-upgrade' <old-version>
+# * <new-postrm> `abort-install'
+# * <new-postrm> `abort-install' <old-version>
+# * <new-postrm> `abort-upgrade' <old-version>
+# * <disappearer's-postrm> `disappear' <overwriter>
+# <overwriter-version>
+# for details, see http://www.debian.org/doc/debian-policy/ or
+# the debian-policy package
+
+# source debconf library
+. /usr/share/debconf/confmodule
+
+case "$1" in
+
+ remove|purge|upgrde|disappear)
+ rm -f /etc/init.d/rvi
+ #DEBHELPER#
+ ;;
+
+ *)
+ exit 0
+ ;;
+
+
+esac
+
+db_stop
+
+exit 0
diff --git a/raspbian_template/rvi.service b/raspbian_template/rvi.service
new file mode 100644
index 0000000..d9ae979
--- /dev/null
+++ b/raspbian_template/rvi.service
@@ -0,0 +1,18 @@
+# systemd(8) setup for Debian
+
+[Unit]
+Description=Remote Vehicle Interaction Service
+Wants=network-online.target
+
+[Service]
+Environment="HOME=/usr/lib/rvi_core"
+Type=forking
+StandardOutput=journal
+StandardError=journal
+ExecStart=/usr/bin/rvi_ctl -c /etc/rvi/rvi.config start
+ExecStop=/usr/bin/rvi_ctl stop
+GuessMainPID=yes
+RemainAfterExit=yes
+
+[Install]
+WantedBy=graphical.target multi-user.target
diff --git a/raspbian_template/source/format b/raspbian_template/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/raspbian_template/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/raspbian_template/source/lintian-overrides b/raspbian_template/source/lintian-overrides
new file mode 100644
index 0000000..463abe9
--- /dev/null
+++ b/raspbian_template/source/lintian-overrides
@@ -0,0 +1 @@
+source-is-missing
diff --git a/scripts/rvi_ctl.template b/scripts/rvi_ctl.template
index dc8dd9e..c6c8875 100644
--- a/scripts/rvi_ctl.template
+++ b/scripts/rvi_ctl.template
@@ -2,7 +2,7 @@
#
#
-# Mozilla Public License, version 2.0. The full text of the
+# Mozilla Public License, version 2.0. The full text of the
# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
#
#
@@ -20,7 +20,7 @@ echo ${ERL:=erl} > /dev/null
usage() {
- echo "Usage: $0 -d config_dir [-c config_file] -l log_dir \\"
+ echo "Usage: $0 -d config_dir [-c config_file] -l log_dir \\"
echo " start|stop|console|attach|ping"
echo
echo " -c config_file Configuration file to launch rvi node with."
@@ -32,7 +32,7 @@ usage() {
echo " stop Stop an rvi node previously started with 'start'."
echo
echo " console Start an rvi in foreground mode."
- echo
+ echo
echo " attach Attach to an rvi node previously started with 'start'."
echo
echo "Environennt variables. Default value in paranthesis::"
@@ -42,7 +42,7 @@ usage() {
}
CONFIG_FILE=""
-SNAME=rvi
+SNAME="__RVI_NAME__"
COOKIE=rvi_cookie
while getopts "c:" o; do
case "${o}" in
@@ -93,15 +93,21 @@ then
echo "${CONFIG_FILE} cannot be opened for reading."
usage
fi
- #
+ #
# Generate a config file that will end up as
# /tmp/rvi/[cfg]/sys.config
#
(
- rm -rf ${RUNDIR}
+ if [ -z "${RVI_RUNDIR}" ]
+ then
+ RUNDIR="/tmp/rvi_${$}"
+ rm -rf ${RUNDIR}
+ else
+ RUNDIR=${RVI_RUNDIR}
+ fi
install -d --mode=0755 ${RUNDIR}
cd ${RUNDIR}
- ${RVI_BINDIR}/setup_gen rvi ${CONFIG_FILE} rvi
+ RVI_LOGDIR="${RVI_LOGDIR}" ${RVI_BINDIR}/setup_gen rvi ${CONFIG_FILE} rvi
)
# Did we succeed with config generation?
@@ -133,9 +139,8 @@ case "${CMD}" in
exec ${RBI_BINDIR}/nodetool -sname ${SNAME} -setcookie ${COOKIE} ping
;;
- attach)
+ attach)
exec to_erl ${RUNDIR}
;;
-esac
-
+esac
diff --git a/scripts/rvi_install b/scripts/rvi_install
index ac128e5..7f6207e 100755
--- a/scripts/rvi_install
+++ b/scripts/rvi_install
@@ -3,7 +3,7 @@
# Copyright (C) 2014, Jaguar Land Rover
#
# This program is licensed under the terms and conditions of the
-# Mozilla Public License, version 2.0. The full text of the
+# Mozilla Public License, version 2.0. The full text of the
# Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
#
@@ -12,36 +12,77 @@
#
#
-SELF_DIR=$(dirname $(readlink -f "$0"))
+# join two path names (avoid things like //foo or /foo/../bar)
+join()
+{
+ if [ "$1" = "/" ]
+ then
+ echo "/$2"
+ else
+ if [ "$2" = ".." ]
+ then
+ echo $(fqn $(dirname $1))
+ else
+ echo "$1/$2"
+ fi
+ fi
+}
+
+# fqn : fully qualified name
+# (e.g. realpath, but portable & works even if path doesn't exist)
+fqn()
+{
+ if [ "$1" = "." ]
+ then
+ echo $(pwd)
+ else
+ if [ "$1" = "/" ]
+ then
+ echo "/"
+ else
+ if [ -e $1 ]
+ then
+ echo $(join $(cd $(dirname $1); pwd) $(basename $1))
+ else
+ echo $(join $(fqn $(dirname $1)) $(basename $1))
+ fi
+ fi
+ fi
+}
+
+SELF_DIR=$(dirname $(fqn "$0"))
SETUP_GEN=$SELF_DIR/setup_gen # Ulf's kitchen sink setup utility
+TOP_DIR=$(dirname $SELF_DIR)
usage() {
cat <<EOF
Usage:
$0 -r root_cert -d device_cert -c credentials \\
[-l log_dir ] [-s prefix_strip] target_dir
-
+
Install a built RVI system into a target directory
-
+
NOTE: The last component of 'taget_dir' must be named 'rvi_core'
Example: /opt/rvi_core
-
+
-l log_dir - Log directory. Default: ${target_dir}/log.
-s prefix_strip - See below. Default: nil.
-r root_cert - The certificate to validate received X509 device
certificates and credentials.
-
+
-k device_key - The PEM file containing the device key pair used
to sign traff
--d device_cert - Certificate to use when authenticating self toward
+-d device_cert - Certificate to use when authenticating self toward
remote nodes.
-c credentials - Credentials to present to remote nodes. Can be specified
multiple times
-
+
+-n node_name - Erlang node name. Default: rvi
+
The created node can be started with: 'target'/rvi_ctl
The RVI installation will rely on a separate erlang install
to run.
@@ -54,7 +95,7 @@ PREFIX STRIPPING
If, for example, 'target_dir' is './build/root/usr/bin', and
'prefix_strip' is './build/root', all internal paths will
reference '/usr/bin'.
-
+
ROOT CERTIFICATE
The root certificate is used to validate remote TLS connections and
device certificates. It is normally generated once and shared across
@@ -142,14 +183,14 @@ EXAMPLE INSTALLATION
WARNING: This example installation will provide no protection
against unauthenticated nodes, unauthorized calls, or
- eavesdropping. Do not use in any externally facing
+ eavesdropping. Do not use in any externally facing
environment.
EOF
- exit 1
+ exit 1
}
-if [ "${#}" = "0" ]
+if [ "${#}" = "0" ]
then
usage
fi
@@ -160,23 +201,24 @@ ROOT_CERT=""
DEVICE_CERT=""
DEVICE_KEY=""
DEVICE_CRED=""
+NAME="rvi"
-while getopts "r:d:c:k:s:l:" o; do
+while getopts "r:d:c:k:s:l:n:" o; do
case "${o}" in
r)
- ROOT_CERT=${OPTARG}
+ ROOT_CERT=$(fqn ${OPTARG})
;;
d)
- DEVICE_CERT=${OPTARG}
+ DEVICE_CERT=$(fqn ${OPTARG})
;;
c)
- DEVICE_CRED="${DEVICE_CRED} ${OPTARG}"
+ DEVICE_CRED="${DEVICE_CRED} $(fqn ${OPTARG})"
;;
k)
- DEVICE_KEY=${OPTARG}
+ DEVICE_KEY=$(fqn ${OPTARG})
;;
l)
@@ -184,9 +226,11 @@ while getopts "r:d:c:k:s:l:" o; do
;;
s)
- PREFIX_STRIP=${OPTARG}
+ PREFIX_STRIP=$(fqn ${OPTARG})
;;
-
+ n)
+ NAME=${OPTARG}
+ ;;
*)
usage
;;
@@ -213,7 +257,7 @@ then
echo " Example: $(dirname ${TARGET_DIR})/rvi_core"
echo " Run ${0} with no arguments for usage."
exit 255
-fi
+fi
# Check that we can read the root cert
if [ -z "${ROOT_CERT}" -o ! -r "${ROOT_CERT}" ]
@@ -267,19 +311,22 @@ then
fi
# Wipe old target dir.
-rm -rf ${TARGET_DIR} > /dev/null 2>&1
+rm -rf ${TARGET_DIR} > /dev/null 2>&1
# Create log dirs
install -m 0755 -d ${TARGET_DIR}
install -m 0755 -d ${LOG_DIR}
+TARGET_DIR=$(fqn $TARGET_DIR)
+LOG_DIR=$(fqn $LOG_DIR)
+
# Copy over the relevant files to the target
-FILE_SET=$(find ebin components deps -name ebin -o -name priv)
-tar cf - ${FILE_SET} | (cd ${TARGET_DIR} ; tar xf - )
+(cd $TOP_DIR; FILE_SET=$(find priv ebin components deps -name ebin -o -name priv);
+tar cf - ${FILE_SET} | (cd ${TARGET_DIR} ; tar xf - ))
# If we have a prefix strip (for build systems not using
# chroot), apply it to paths.
-if [ -s "${PREFIX_STRIP}" ]
+if [ -s "${PREFIX_STRIP}" ]
then
STRIP_TARGET_DIR=$(echo ${TARGET_DIR} | sed "s|^${PREFIX_STRIP}||")
STRIP_LOG_DIR=$(echo ${LOG_DIR} | sed "s|^${PREFIX_STRIP}||")
@@ -290,7 +337,8 @@ fi
# Patch rvi_ctl.template to set its ERL_LIBS path correctly.
sed -e "s|__RVI_BINDIR__|${STRIP_TARGET_DIR}|g" \
- -e "s|__RVI_LOGDIR__|${STRIP_LOG_DIR}|g" < scripts/rvi_ctl.template > /tmp/rvi_ctl
+ -e "s|__RVI_LOGDIR__|${STRIP_LOG_DIR}|g" \
+ -e "s|__RVI_NAME__|${NAME}|g" < $TOP_DIR/scripts/rvi_ctl.template > /tmp/rvi_ctl
# Install all relevant scripts.
install -m 0755 -d ${TARGET_DIR}/priv/certificates
@@ -302,13 +350,13 @@ install -m 0644 ${DEVICE_KEY} ${TARGET_DIR}/priv/keys/device_key.pem
install -m 0644 ${DEVICE_CRED} ${TARGET_DIR}/priv/credentials
install -m 0755 /tmp/rvi_ctl ${TARGET_DIR}
rm /tmp/rvi_ctl
-install -m 0755 scripts/setup_gen ${TARGET_DIR}
-install -m 0755 rel/files/nodetool ${TARGET_DIR}
-install -m 0755 python/rvi_service.py ${TARGET_DIR}/rvi_service
-install -m 0755 python/rvi_call.py ${TARGET_DIR}/rvi_call
-install -m 0644 python/rvilib.py ${TARGET_DIR}
-install -m 0755 python/rvi_get_services.py ${TARGET_DIR}/rvi_get_services
-install -m 0755 -D priv/config/rvi_common.config ${TARGET_DIR}/priv/config/rvi_common.config
+install -m 0755 $TOP_DIR/scripts/setup_gen ${TARGET_DIR}
+install -m 0755 $TOP_DIR/rel/files/nodetool ${TARGET_DIR}
+install -m 0755 $TOP_DIR/python/rvi_service.py ${TARGET_DIR}/rvi_service
+install -m 0755 $TOP_DIR/python/rvi_call.py ${TARGET_DIR}/rvi_call
+install -m 0644 $TOP_DIR/python/rvilib.py ${TARGET_DIR}
+install -m 0755 $TOP_DIR/python/rvi_get_services.py ${TARGET_DIR}/rvi_get_services
+install -m 0755 -D $TOP_DIR/priv/config/rvi_common.config ${TARGET_DIR}/priv/config/rvi_common.config
echo "RVI binary files installed under ${TARGET_DIR}"
echo "RVI will log to ${LOG_DIR}"
@@ -319,4 +367,3 @@ echo "Stop: ${TARGET_DIR}/rvi_ctl stop"
echo "Start console mode: ${TARGET_DIR}/rvi_ctl -c <config_file> console"
echo
exit 0
-
diff --git a/test/rvi_core_SUITE.erl b/test/rvi_core_SUITE.erl
index c61e8ce..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
]}
].
@@ -219,90 +219,86 @@ t_sample_keys_and_cert(Config) ->
generate_sota_cred(sample, Dir, CredDir, Config).
t_install_backend_node(_Config) ->
- install_rvi_node("basic_backend", env(),
- [root(), "/priv/test_config/basic_backend.config"]).
+ install_backend_node("basic_backend").
t_install_sample_node(_Config) ->
- install_sample_node("basic_sample", "basic_sample.config").
+ install_sample_node("basic_sample").
t_install_sms_backend_node(_Config) ->
- install_rvi_node("sms_backend", env(),
- [root(), "/priv/test_config/sms_backend.config"]).
+ install_backend_node("sms_backend").
t_install_sms_sample_node(_Config) ->
- install_sample_node("sms_sample", "sms_sample.config").
+ install_sample_node("sms_sample").
t_install_tls_backend_node(_Config) ->
- install_rvi_node("tls_backend", env(),
- [root(), "/priv/test_config/tls_backend.config"]).
+ install_backend_node("tls_backend").
t_install_tls_sample_node(_Config) ->
- install_sample_node("tls_sample", "tls_sample.config").
+ install_sample_node("tls_sample").
t_install_tlsj_backend_node(_Config) ->
- install_rvi_node("tlsj_backend", env(),
- [root(), "/priv/test_config/tlsj_backend.config"]).
+ install_backend_node("tlsj_backend").
t_install_tlsj_sample_node(_Config) ->
- install_sample_node("tlsj_sample", "tlsj_sample.config").
+ install_sample_node("tlsj_sample").
t_install_tls_backend_noverify_node(_Config) ->
- install_rvi_node("tls_backend_noverify", env(),
- [root(), "/priv/test_config/tls_backend_noverify.config"]).
+ install_backend_node("tls_backend_noverify").
t_install_tls_sample_noverify_node(_Config) ->
- install_sample_node("tls_sample_noverify", "tls_sample_noverify.config").
+ install_sample_node("tls_sample_noverify").
t_install_bt_backend_node(_Config) ->
- install_rvi_node("bt_backend", env(),
- [root(), "/priv/test_config/bt_backend.config"]).
+ install_backend_node("bt_backend").
t_install_bt_sample_node(_Config) ->
- install_sample_node("bt_sample", "bt_sample.config").
+ install_sample_node("bt_sample").
-generic_start(Name) ->
+start_backend(Name) -> generic_start(backend, Name).
+start_sample (Name) -> generic_start(sample , Name).
+
+generic_start(Type, Name) ->
+ {ok,Cwd} = file:get_cwd(),
F = filename:join([".", Name, "start_me.sh"]),
- Cmd = [env(),
- " ./", Name, "/rvi.sh",
- " -s ", Name,
- " -l ./", Name, "/rvi/log",
- " -d ./", Name,
- " -c ./", Name, "/priv/test_config/", Name, ".config",
- " $1"],
+ Cmd = [env(Type),
+ " RVI_RUNDIR=", filename:join(Cwd, Name),
+ " ./", Name, "/rvi_core/rvi_ctl",
+ " -c ./", Name, "/rvi_core/priv/test_config/", Name, ".config",
+ " $*"],
ok = save_cmd(F, Cmd),
- cmd([F, " start"]),
+ cmd(["sh -x ", F, " start"]),
await_started(Name).
t_start_basic_backend(_Config) ->
- generic_start("basic_backend").
+ start_backend("basic_backend").
t_start_basic_sample(_Config) ->
- generic_start("basic_sample").
+ start_sample("basic_sample").
t_start_bt_backend(_Config) ->
- generic_start("bt_backend").
+ start_backend("bt_backend").
t_start_bt_sample(_Config) ->
- generic_start("bt_sample").
+ start_sample("bt_sample").
t_start_tls_backend(_Config) ->
- generic_start("tls_backend").
+ start_backend("tls_backend").
t_start_tls_sample(_Config) ->
- generic_start("tls_sample").
+ start_sample("tls_sample").
t_start_tlsj_backend(_Config) ->
- generic_start("tlsj_backend").
+ start_backend("tlsj_backend").
t_start_tlsj_sample(_Config) ->
- generic_start("tlsj_sample").
+ start_sample("tlsj_sample").
t_start_tls_backend_noverify(_Config) ->
- generic_start("tls_backend_noverify").
+ start_backend("tls_backend_noverify").
t_start_tls_sample_noverify(_Config) ->
- generic_start("tls_sample_noverify").
+ start_sample("tls_sample_noverify").
t_register_lock_service(_Config) ->
Pid =
@@ -331,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.
@@ -371,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.
@@ -460,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,
@@ -468,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]),
@@ -706,6 +722,15 @@ ensure_dir(Dir) ->
env() ->
"RVI_LOGLEVEL=debug RVI_MYIP=127.0.0.1 RVI_BACKEND=127.0.0.1".
+env(backend) ->
+ env();
+env(sample) ->
+ [env(),
+ " RVI_BACKEND=127.0.0.1 RVI_PORT=9000"
+ " RVI_MY_NODE_ADDR=127.0.0.1:9000"].
+
+
+
root() ->
code:lib_dir(rvi_core).
@@ -724,18 +749,28 @@ service_edge("sample" ) -> "http://localhost:9001".
rvi_log_addr("backend") -> "http://localhost:8809";
rvi_log_addr("sample" ) -> "http://localhost:9009".
-install_rvi_node(Name, Env, _ConfigF) ->
+install_backend_node(Name) ->
+ install_rvi_node(backend, Name).
+
+install_sample_node(Name) ->
+ install_rvi_node(sample, Name).
+
+install_rvi_node(Type, Name) ->
Root = code:lib_dir(rvi_core),
Scripts = filename:join(Root, "scripts"),
ct:log("Root = ~p", [Root]),
Cmd = lists:flatten(
- [Env, " ", Scripts, "/rvi_install.sh ./", Name]),
-
+ ["sh -x ", Scripts, "/rvi_install",
+ " -r ", filename:join(root_keys(), "root_cert.crt"),
+ " -d basic_backend_keys/device_cert.crt",
+ " -k basic_backend_keys/device_key.pem",
+ " -n ", Name,
+ creds(Type),
+ " ", Name, "/rvi_core"]),
ct:log("Cmd = `~s`", [Cmd]),
Res = cmd(Cmd),
ct:log("install_rvi_node/1 -> ~p", [Res]),
-
Res1 = cmd(lists:flatten(["install -d --mode 0755 ./", Name])),
ct:log("install_rvi_node/2 -> ~p", [Res1]),
@@ -744,17 +779,12 @@ install_rvi_node(Name, Env, _ConfigF) ->
Res2.
-install_sample_node(Name, ConfigF) ->
- Env = [env(),
- " RVI_BACKEND=127.0.0.1 RVI_PORT=9000"
- " RVI_MY_NODE_ADDR=127.0.0.1:9000"],
- install_rvi_node(Name, Env,
- [root(), "/priv/test_config/", ConfigF]).
-
-%% in_priv_dir(F, Cfg) ->
-%% %% PrivDir = ?config(priv_dir, Cfg),
-%% %% in_dir(PrivDir, F, Cfg).
-%% F(Cfg).
+creds(backend) ->
+ [" -c basic_backend_creds/backend_cred.jwt"
+ " -c basic_backend_creds/sota_backend_cred.jwt"];
+creds(sample) ->
+ [" -c basic_sample_creds/lock_cred.jwt"
+ " -c basic_sample_creds/sota_cred.jwt"].
cmd(C) ->
cmd(C, []).
@@ -879,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)).
@@ -896,7 +926,8 @@ no_errors(Dirs, PDir) ->
ct:log("Will check errors in ~p", [Dirs]),
true = lists:all(
fun(D) ->
- no_errors_(filename:join([PDir, D, "rvi", "log", "lager"]), D)
+ no_errors_(filename:join([PDir, D, "rvi_core",
+ "log", "lager"]), D)
end, Dirs),
ok.
@@ -913,6 +944,6 @@ log_is_empty(Log, F, Name) ->
ct:log("~s: ~s is not empty:~n~s", [Name, F, Content]),
false;
{error, Reason} ->
- ct:log("~s: Cannot read log ~s (~p)", [Name, F, Reason]),
+ ct:log("~s: Cannot read log ~s (~p)", [Name, Log, Reason]),
false
end.