1 A CoAP Server With A Rack Interface For Use of Web Frameworks Such As Ruby On Rails in The Internet of Things
1 A CoAP Server With A Rack Interface For Use of Web Frameworks Such As Ruby On Rails in The Internet of Things
Henning Muller
cbna
This work is licensed under a Creative Commons
Attribution-NonCommercial-ShareAlike 4.0 License.
http://creativecommons.org/licenses/by-nc-sa/4.0/
Henning Muller
[email protected]
Abstract
Wir stellen einen Constrained Application Protocol (CoAP) Server mit einem Rack In-
terface vor, der Anwendungsentwicklung fur das Internet der Dinge (bzw. das Wireless
Embedded Internet) mit Frameworks wie Ruby on Rails ermoglicht. Solche Framworks
verhindern die Notwendigkeits, das Rad neu zu erfinden und vereinfachen die Anwen-
dung testgetriebener Entwicklung (TDD) und anderer agiler Methoden der Softwareen-
twicklung. Sie sind vor allem auf weniger eingeschrankten Geraten wie Infrastruk-
turgeraten und Applikationsservern vorteilhaft. Unsere Losung ermoglicht Applika-
tionsentwicklung nahezu ohne Pradigmenwechsel verglichen mit HyperText Transport
Protocol (HTTP) und bietet performante Handhabung von zahlreichen nebenlaufigen
Clients. Der Server ubersetzt transparent zwischen den Protokollen und unterstutzt
ebenso Besonderheiten von CoAP wie Service und Resource Discovery, Block-wise
i
Transfers und Observing Resources. Er bietet zusatzlich die Moglichkeit, transparent
zwischen JSON und CBOR Payloads zu transkodieren. Den Resource Directory En-
twurf haben wir als Rails Anwendung implementiert, die auf unserer Server Software
lauft.
ii
Contents
1. Introduction 1
1.1. Motivation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2. Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.1. HTTP and REST . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2.2. Ruby on Rails and Rack . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2.3. Internet of Things and CoAP . . . . . . . . . . . . . . . . . . . . . 3
1.3. Research Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Related Work 5
2.1. Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2. Scalability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3. CoAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.4. DTLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3. Background 9
3.1. Concurrency and Celluloid . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2. Rack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.3. CoAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3.1. Existing Implementations . . . . . . . . . . . . . . . . . . . . . . . 14
3.3.2. Server-sent Updates . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3.3. Payload Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4. Objectives 19
4.1. CoAP Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.1.1. Protocol Implementation . . . . . . . . . . . . . . . . . . . . . . . 19
4.1.2. Concurrency and Performance . . . . . . . . . . . . . . . . . . . . 19
4.1.3. Rack Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.1.4. DTLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2. Protocol Translations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.2.1. Headers and Payload Formats . . . . . . . . . . . . . . . . . . . . 21
iii
Contents
5. Design 23
5.1. CoAP Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.1.1. Rack Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.1.2. Protocol Implementation . . . . . . . . . . . . . . . . . . . . . . . 26
5.1.3. Concurrency and Performance . . . . . . . . . . . . . . . . . . . . 29
5.1.4. DTLS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.2. Protocol Translations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.2.1. Block-wise Transfers . . . . . . . . . . . . . . . . . . . . . . . . . . 35
5.2.2. Content Negotiation and Transcoding . . . . . . . . . . . . . . . . 36
5.2.3. Chunked Transfer Coding . . . . . . . . . . . . . . . . . . . . . . . 38
5.2.4. Resource Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
5.2.5. Observe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6. Implementation 45
6.1. External Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
6.2. CoAP Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.3. David . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.3.1. Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.3.2. Rack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.3.3. Protocol Implementation . . . . . . . . . . . . . . . . . . . . . . . 50
6.3.4. Concurrency and Performance . . . . . . . . . . . . . . . . . . . . 52
6.3.5. Protocol Translations . . . . . . . . . . . . . . . . . . . . . . . . . . 53
6.3.6. Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.4. Resource Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
6.5. Resource Directory (RD) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
7. Evaluation 59
7.1. Unit Tests, Code Coverage, and Code Climate . . . . . . . . . . . . . . . . 59
7.2. Benchmarking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
7.2.1. Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
7.2.2. Interoperability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
7.2.3. Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7.3. Developer Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
7.3.1. Public Announcement . . . . . . . . . . . . . . . . . . . . . . . . . 74
iv
Contents
8. Conclusion 77
8.1. Recapitulation of Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
8.2. Perspectives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
A. Guides 81
A.1. Basic Installation and Usage . . . . . . . . . . . . . . . . . . . . . . . . . . 81
A.2. Running the Resource Directory (RD) . . . . . . . . . . . . . . . . . . . . 82
List of Figures 95
List of Tables 97
Acronyms 99
Bibliography 111
Acknowledgements 113
v
Chapter 1
Introduction
1.1. Motivation
The Internet of Things (IoT) is an emerging technology for which a recent market study
predicts a fivefold increase in connected devices in the next five years [36] and for which
the Gartner Plateau of Productivity seems foreseeable [18]. With a growing maturity of
this technology, methodologies and best practices will develop. This work aims to bring
modern web development methods to server application software development for the
IoT.
For the classic web using the HyperText Transport Protocol (HTTP) there are many
web frameworks making the development of web applications more productive. Ruby
on Rails (Rails) is one framework including features that emphasize it against other
frameworks or web development approaches. It promotes the development by REST
criteria, supports Test-driven Development (TDD) and implements many well-known
software engineering design patterns and methods of agile development such as Active
Record, Convention over Configuration (CoC), Dont Repeat Yourself (DRY) and Model-
View-Controller (MVC). Additionally, the Rails community is quite vivid and there is a
huge ecosystem of extensions for many recurrent problems.
Current popular IoT applications (e.g. Nest products) are often designed being unable
to work without proprietary server applications provided by the vendor and jeopardize
customer privacy1 . Providing an Open Source possibility for IoT application develop-
ment in a framework widely known as Rails hopefully promotes decentralization and
the autonomy of users. The Thin Server Architecture proposed by M. Kovatsch et al. fos-
ters application layer interoperability by shifting application logic from embedded de-
vices to application servers [26]. Our solution aims to provide easy development of
application servers.
Compared to other protocols for constrained applications, CoAP is an especially inter-
1 https://nest.com/legal/privacy-statement
1
1.2. Basics
esting playground, because it addresses many shortcomings from which the Transmis-
sion Control Protocol (TCP) and HTTP suffer even in relatively unconstrained contexts.
Design features such as Representational State Transfer (REST) compatibility and usage
of elements like Uniform Resource Identifiers (URIs) as well as Internet Media Types
make it very adaptable to HTTP.
1.2. Basics
In the next subsections we will describe the basics of the technologies that form the
context of this work.
The HyperText Transport Protocol (see [RFC 7230] ff.) is an application protocol based
on TCP. It uses URIs (http://example.com/foo for example) to address certain
resources on different servers (see section 2.7 of [RFC 7230]). For every request of (or on)
a resource, a TCP session is established with a server and a method and resource path
(among other information) are sent (see section 3.1.1 of [RFC 7230]). This session can be
reused for later requests. Several methods are defined in section 4 of [RFC 7231]. The
most important one is probably GET which is used to retrieve a resource representation.
The server synchronously answers with a status code that describes the result of the
requested operation and the representation of the requested resource (see section 3.1.2
of [RFC 7230]). Subsequently, the TCP session is closed if there were no further requests
in a timeout interval. The protocol information in the header is text based as opposed
to binary and extended by numerous other internet standards.
Representational State Transfer (REST) is an architectural style facilitating a set of in-
teraction constraints that can be applied to HTTP but also to other protocols to achieve
scalability of component interactions, generality of interfaces, to reduce interaction
latency, and enforce security (see section 5 of [REST]). It was defined by Roy Thomas
Fielding, one of the original authors of HTTP. One of the constraints is the usage of stan-
dard HTTP methods (e.g. GET, POST, PUT, and DELETE) for interface generality. An-
other important constraint is statelessness which means that each request from client
to server must contain all of the information necessary to understand the request. A
resource (identified by a URI) can be represented in different formats; clients are able to
choose the format most suitable.
2
1.2. Basics
Ruby on Rails is an open-source web framework thats optimized for programmer hap-
piness and sustainable productivity [31]. It is designed in a way that eases web appli-
cation development by REST criteria. Many well-known software engineering design
patterns and methods of agile development such as Active Record, Convention over
Configuration, Dont Repeat Yourself and Model-View-Controller are incorporated into
the framework. Test-driven Development is well supported by Rails and widely adopted
among programmers using Rails. The Rails community is quite vivid and there is a huge
ecosystem of extensions for many recurrent problems.
Since version 2.3, Rails supports the Rack web server interface [Rack]. Many other
Ruby web frameworks specialized on different aspects are also compatible to that inter-
face (e.g. Sinatra [35], Grape [20]). For a more detailed introduction to Rack, refer to an
article written by Christian Neukirchen (the original author) [27].
The Internet of Things (IoT) consists of embedded devices connected to the Internet in
a wired or wireless manner. Software on embedded devices cannot rely on many re-
sources in terms of the Central Processing Unit (CPU), Read-only Memory (ROM), and
Random-access Memory (RAM). We will mostly use the term Internet of Things, because
it is more general than other similar terms like Web of Things and Wireless Embedded In-
ternet.
The Constrained Application Protocol (CoAP) is a protocol based on UDP specifically
designed for use with constrained nodes and networks [RFC 7252] [5]. It incorporates
successful design elements also used in HTTP such as URIs and Internet Media Types
and aims to realize the REST architecture. In contrast to HTTP, CoAP is not neces-
sarily synchronous. There are no long-lasting connections, and responses can be sent
independently of requests. This enables features such as multicast support [RFC 7390]
and server-sent notifications on resource changes (called Observe, see [core-observe-16]).
Because of those and other features such as built-in discovery and the Resource Di-
rectory (RD) draft [core-resource-directory-02], it is particularly suited for Machine-to-
Machine (M2M) communications. The Block extension [core-block-17] allows transfer of
resource representations larger than the maximum payload of a CoAP message (about
1 KiB).
In order to make a Rack compatible application available to CoAP capable clients, it
has to be translated between the HTTP centric Rack interface and CoAP. This translation
has to be applied to headers, payloads, and also to more advanced protocol features.
3
1.3. Research Questions
To which extent is it possible to use web application frameworks for HTTP such as Ruby on
Rails in the Internet of Things utilizing CoAP?
More specific questions implied by the main research question can either be related to
the CoAP server or to Protocol translations.
The CoAP server handles requests from the network, translates between HTTP and
CoAP specifics and interfaces with the web application framework via Rack. More spe-
cific research questions are:
Incoming requests and outgoing responses have to be translated between what the Rack
interface (which is designed for HTTP) expects and the CoAP protocol specifics.
2. How can payload formats be translated between their suitable fields of applica-
tion?
3. Is the CoAP Resource Discovery (see section 7.2 of [RFC 7252]) implementable
transparently for the Rack application?
4
Chapter 2
Related Work
In this chapter we examine which solutions exist that partly answer our research ques-
tions and give an introduction to possible sources in that contexts.
2.1. Frameworks
1 https://github.com/eclipse/californium/tree/master/cf-helloworld-server
2 https://sourceforge.net/p/libcoap/code/ci/master/tree/examples/server.c
5
2.2. Scalability
[PEP 333] as a source of inspiration. Rack is chosen for this work because of its spread
and provision of a solid base.
There are many HTTP web servers written in Ruby that support the Rack inter-
face. Although they are probably designed in a substantially different way than CoAP
servers, they can be analyzed regarding to their Rack implementation and used for com-
parison in the performance evaluation of our work. Notable examples are Reel, Thin, and
Unicorn (see [29], [38], and [39]).
2.2. Scalability
The inability of web servers with concurrent request handling based on processes or
threads to scale up to 100.000 requests per second led to the framing of The C10K problem
[22]. One possibility to solve this problem is event-driven architecture as it is discussed
in the Reactor pattern [32] [33] designed by Douglas C. Schmidt and others. Matthias
Kovatsch provides a detailed overview of web server architectures with regard to scal-
ability in his dissertation thesis Scalable Web Technology for the Internet of Things [24].
For Ruby there are a number of libraries targeting the simplification of the develop-
ment of concurrent programs. For this work especially Celluloid [9] is considered. The
basics of concurrency and Celluloid are also highlighted in section 3.1.
Especially Californium is promising as a source of inspiration for performance and
concurrency oriented design. According to a paper among others written by its original
author Matthias Kovatsch, Californium handles almost 400,000 requests per second [25].
Some observations from the Celluloid source code are collected in section 3.3.1.
2.3. CoAP
6
2.4. DTLS
on the server side, also client implementations are interesting for their way of message
parsing, usage in testing of our server implementation and their transmission layer with
regards to code reuse. However, analyzing every implementation in detail would not
be possible because of the time constraints of this thesis.
Both the Cross-Protocol Proxying between CoAP and HTTP section of [RFC 7252] (see sec-
tion 10) and the Guidelines for HTTP-CoAP Mapping Implementations [core-http-mapping-
06] can be consulted regarding to translations of CoAP headers and protocol features to
HTTP and vice versa. However, simply proxying an ordinary Rails application would
not suffice. An objective for our solution is that it supports a CoAP specific develop-
ment and therefore should be explicit about that protocol. The mapping guidelines also
make some general statements about the transparent conversion of one content format
into another, called Transcoding (see section 6.4 of [core-http-mapping-06]).
We did not find any Open Source client or server implementations supporting the RD
draft [core-resource-directory-02]. The only exception is a server implementation con-
tained as an example in the txThings3 project. However, it implements an older version
of the draft and is missing functionality. The CoAP article in the Wikipedia [14] lists
CoAPSharp as supporting the RD draft but its code contains no indications about that.
2.4. DTLS
CoAP depends on DTLS for security (see section 9 of [RFC 7252]). The DICE Work-
ing Group (WG) of the Internet Engineering Task Force (IETF) works on supporting the
use of DTLS in constrained environments. The main draft that is currently worked on
defines a profile of DTLS 1.2 [RFC 6347] (and Transport Layer Security (TLS) 1.2 [RFC
5246]) that offers communication security for IoT applications [dice-profile-09]. An-
other draft aims to standardize the DTLS handshake on top of CoAP to make use of
block-wise transfers [schmertmann-dice-codtls-01]. There is a Ruby library4 that im-
plements this draft in an alpha state. An early draft [23] considers securing multicast
communications in that context. The integration of DTLS into Californium is discussed
in a masters thesis from 2012 [21].
3 https://github.com/siskin/txThings
4 https://rubygems.org/gems/codtls
7
Chapter 3
Background
For the design of different aspects of the software created during this work, some back-
ground on the servers concurrency architecture, the Rack interface, and the CoAP im-
plementation will be given in this chapter. We will weigh the advantages and disadvan-
tages of different concurrency models in section 3.1. The Rack interface is introduced
in section 3.2. For the CoAP implementation, we analyze different existing projects to
learn about implementation techniques in section 3.3. Some background will be given
about the Observe extension [core-observe-16] and the Concise Binary Object Represen-
tation (CBOR) [RFC 7049].
9
3.2. Rack
3.2. Rack
The basic ideas of Rack are as follows. An application is a Ruby object that responds
to a method named call. This method is invoked for example by a server when an
application response is demanded. The only argument an invocation of call includes
is a Hash2 representing the environment of the request. This includes information such
as the HTTP method (see section 4 of [RFC 7231]), the path, query string and HTTP
headers (see section 5 of [RFC 7231]) of the request. The Rack environment was inspired
by the Common Gateway Interface (CGI), an interface for web servers to retrieve HTTP
1 https://github.com/eventmachine/eventmachine/issues/74
2 http://ruby-doc.org/core-2.2.0/Hash.html
10
3.2. Rack
responses from external programs. It is also extended by Rack specific options such as
the Rack interface version. An invocation of call has to return an Array3 containing
the HTTP status code (see section 6 of [RFC 7231]), a Hash of HTTP headers, and the
response payload4 . An example for a particularly minimal Rack application would be
the Ruby code shown in Listing 3.1; normally headers such as Content-Type and Content-
Length would be included with their respective values.
Rack offers the possibility to wrap the invocation of the call method of an applica-
tion through an intermediary called middleware. A piece of middleware basically works
like an application, also providing a call method with the environment as argument.
The Rack application is passed upon initialization of the middleware class. On call
invocations, the middleware is able to change the environment or the application re-
sponse according to its function. As an example, an authentication mechanism would
be possible to implement as a Rack middleware that returns a forbidden status code
unless the request environment contains valid credentials in the query string. A pop-
ular Rack middleware example included in Rails by default and also interesting in the
context of this work is Rack::ETag which adds entity tag headers to responses (see sec-
tion 2.3 of [RFC 7232]). Rack middleware is usually independent from the framework
or application, so it can be used with different frameworks supporting Rack.
Instance variable access in Rack middleware can lead to concurrency problems when
conducted in a multi-threaded system, because every middleware class is only instan-
tiated once5 . See Listing 3.2 for a possible but rather expensive workaround.
3 http://ruby-doc.org/core-2.2.0/Array.html
4 Which has to respond to each, take a block and yield chunked data as Strings
5 http://stackoverflow.com/q/23028226
11
3.2. Rack
There are numerous different Rack frameworks, some of them with very distinctive
features. We compiled a list of frameworks and their download locations in Table 3.1
for an overview. We will refer to some of them later in other contexts.
Framework Website
Grape http://intridea.github.io/grape
Camping http://camping.io
Cramp https://cramp.in
Cuba https://cuba.is
Brooklyn https://github.com/luislavena/brooklyn
Hobbit https://github.com/patriciomacadden/hobbit
Nancy http://guilleiguaran.github.io/nancy
NYNY http://alisnic.github.io/nyny
Ramaze http://ramaze.net
RESTRack http://restrack.me
Roda http://roda.jeremyevans.net
Scorched http://scorchedrb.com
Sinatra http://www.sinatrarb.com
Rails::API https://github.com/rails-api/rails-api
Ruby on Rails http://rubyonrails.org
As the Rack interface is designed for HTTP requests and responses, some adaption
has to be performed when using it with CoAP. On requests, CoAP options have to be
12
3.3. CoAP
3.3. CoAP
6 Although messages effectively are broadcasted on some physical layers such as [IEEE 802.15.4]
13
3.3. CoAP
extension named Observing Resources specifies a way to register for and subsequently
receive updates about the state of a resource [core-observe-16].
Table 3.2.: CoAP Libraries Possible compatiblity with Ruby and multicast support
7 https://ag-rn.tzi.de
8 We also tested incompatible implementations.
14
3.3. CoAP
In the following paragraphs, we briefly examine the source code of Californium and
libcoap with regards to their architecture, implementations of the CoAP Message Dedu-
plication (see section 4.5 of [RFC 7252]) and concurrency approaches. Table 3.3 lists the
examined versions.
Library Version
Californium 1.0.0-M3 (Core)
1.0.0-M3 (Connector)
libcoap d48ab44
Architecture
Some architectural inspirations will be mentioned but we will not analyze the overall
architecture of every library.
Californium uses an approach similar to the design of Rack to implement different
functional protocol layers (see line 83 of CoAPEndpoint class (Core)). Messages are
passed through a stack of classes each handling a certain transmission layer task. A
ReliabilityLayer, for example, retransmits messages if there was no response; a
BlockwiseLayer handles block-wise transfers.
Message Deduplication
Californium makes use of the Java class ConcurrentHashMap as a hash table for man-
aging data about ongoing transmissions (see line 58 to 61 of Matcher class (Core)).
Three hash tables are used with different keys (message ID, token, and URI). The Java
documentation describes ConcurrentHashMap as a hash table supporting full con-
currency of retrievals and adjustable expected concurrency for updates [13].
Concurrency
15
3.3. CoAP
libcoap itself does not implement a server ready to use but provides the API for pro-
grammers to base their own server implementations on. The source code contains
an example server that is realized as a single threaded event loop (see line 414 of
examples/server.c).
In the HTTP world, some protocols are designed to overcome the strictly synchronous
request model of HTTP/1.1 (see [RFC 7230] ff.) and are therefore in some extent com-
parable to the CoAP Observe extension [core-observe-16]. Their properties differ in
distinct ways from Observe, which is not keeping connections open, is unidirectional
and does not strictly require the server pushing updates only directly after requests of
the client. Long Polling and Streaming are two mechanisms common to achieve server-
initiated communication with HTTP. [RFC 6202] summarizes known issues and lists
best practices regarding to the use of these mechanisms. Popular choices for this pur-
pose in the traditional web are Comet9 and WebSockets [RFC 6455]. Both use long
opened connections, which puts extra load on the servers. Comet just keeps a HTTP
GET request opened, which is used by the server to push updates gradually. WebSocket
specifies bi-directional out-of-band (non-HTTP) communications. Solutions more sim-
ilar to Observe are HTTP/2 Server Push (see section 8.2 of [httpbis-http2-17]) and
HTML5 Server-Sent Events [W3C REC eventsource], which both are unidirectional but
also employ long-running connections. HTTP/2 Server Push is not truly asynchronous,
because the push mechanism is only used to multiplex documents anticipating a direct
request. HTML5 Server-Sent Events are most similar to Observe from an architectural
perspective. The implementation of the mentioned protocols in connection with Rack
and Rails can give valuable input for the design of the Observe integration in the context
of this work. Therefore some existing Ruby gems that implement the mentioned tech-
niques can be a source of inspiration. We further analyze that topic in subsection 5.2.5.
There are a number of different formats for resource representation (serialization) that
are more or less optimized on low resource usage (when transmitted or parsed). In the
world of less constrained web applications especially JavaScript Object Notation (JSON)
and eXtensible Markup Language (XML) are common as resource representations for
APIs. Both are convertible into less resource demanding binary serialization formats.
9 https://en.wikipedia.org/wiki/Comet_(programming)
16
3.3. CoAP
For JSON there are for example Binary JSON (BSON), Universal Binary JSON (UBJSON),
MessagePack and CBOR. XML can be converted into Efficient XML Interchange (EXI) to
save resources. We will concentrate on JSON, because it currently is more widespread
than XML in the context of modern web application development. Especially CBOR is
considered as a binary serialization format due to its closeness to JSON, the compactness
(of code and data), and the possibility to be used without a schema description (see
section 1.1 of [RFC 7049]).
17
Chapter 4
Objectives
Corresponding to the primary research question stated in section 1.3, the higher objec-
tive of our work is to determine the possibility of using Rack based web frameworks
originally designed for HTTP in the IoT utilizing CoAP. We utilize Test-driven Devel-
opment (TDD) for the software components. There are also some general design goals
to the code such as code quality, modularity, and sustainability through readability and
a high test coverage for example.
For the handling of frequent sensor data updates from a huge number of IoT devices,
the concurrency model has to be chosen fittingly. Concurrent handling of requests is
therefore one design goal of the server implementation. We will analyze which models
are viable for applications in the IoT and how possible models integrate with Rails. Nei-
19
4.1. CoAP Server
ther the server itself, nor the CoAP implementation or the application framework may
block the concurrent handling of further requests. For a realistic objective for the con-
currency level and the maximum number of requests per second of the implementation,
benchmarks of other implementations should provide for an overview. It is important to
consider the comparability of different benchmarks, as they differ at least on two levels:
First, the hardware configurations range from ultra-portable, energy-saving developer
notebooks, to several full-fledged, high-end servers. Secondly, the choice of frameworks
for testing is important. A benchmark testing a plain Hello World Rack application is
not comparable with its Rails or Sinatra counterpart, because of the framework over-
head. For this work, only the server performance has to be measured, so benchmarking
different web servers on several Ruby VMs serving a plain Hello World Rack applica-
tion would be of most value. The server implemented during this work does not have to
scale as well as Californium for example, which according to a paper among others writ-
ten by Californiums original author Matthias Kovatsch handles almost 400,000 requests
per second [25] via CoAP on server hardware. For Ruby applications, those values are
reachable over HTTP with server stacks not written in Ruby such as TorqBox on JRuby
or nginx proxying Unicorn on MRI for example1 . With HTTP web servers written in
Ruby running plain Rack applications (no further frameworks like Rails) scale up until
approximately 7.600 requests per second2 , so it is expected that with CoAP this number
could be improved in comparison to HTTP. For a server scaling this well still much opti-
mization work has to be done, which is not the focus of this work. The more conservative
number of 5.000 requests per second shall be aimed at, for now. Implicated objectives by
these performance goals are the portability of the server and the CoAP implementation
to other Ruby Virtual Machines (VMs) than MRI, such as JRuby for example, and the
choice of a server concurrency model which scales well with the provided hardware.
As many other Ruby web frameworks, Rails interacts via the Rack interface with the web
server. The main targeted web application framework will be Rails but the server imple-
mentation shall also be tested against different other Rack middlewares and application
frameworks. It shall be clarified in which extent this interface suffices for the charac-
teristics of the Constrained Application Protocol (CoAP). The translation between the
1 http://www.techempower.com/benchmarks/#section=data-r9&hw=peak&test=json&l=
35s
2 http://www.madebymarket.com/blog/dev/ruby-web-benchmark-report.html
20
4.2. Protocol Translations
Rack interface based on HTTP and CoAP has to function seamlessly and be as complete
as possible.
4.1.4. DTLS
The server has to be designed to allow the integration of DTLS [RFC 6347] as a means
of transport encryption. We do not pursue an actual implementation. The implications
of DTLS in the context of this work shall be examined. Functionality such as observe or
certain Rack middleware might possibly be derogated.
The software implemented during this work shall enable an integrated development of
applications for the traditional, human-readable web and machine-to-machine commu-
nication in the IoT. It will be clarified how the HTTP and CoAP Content Negotiation
protocols (see section 5.3 of [RFC 7231] and 5.5.4 of [RFC 7252]) can be utilized for the
purpose of separating those client groups from a developers perspective in Rails. Other
functionality of HTTP based upon headers applicable to CoAP shall also be preserved
using an appropriate translation of the headers (for example the ETag header which
is defined in section 2.3 of [RFC 7232]). Also the implications of a transparent content
type mapping for responses by the web framework between a data serialization format
of the traditional web and more resource-saving ones for the IoT will be emphasized.
A transcoding of resource representation formats between JSON [RFC 7159] and CBOR
[RFC 7049] will be implemented.
Furthermore, special properties of CoAP such as the Resource Discovery (see section
7.2 of [RFC 7252]) and Observe [core-observe-16] will be considered and integrated ap-
propriately. The Resource Discovery shall be integrated into the web framework (for
example Rails) without any developer interaction for resources for which a interaction
with CoAP is reasonable. The functionality of an RD [core-resource-directory-02] shall
be facilitated by pre-implemented, configurable, and well-tested modules. It will also
serve as application to demonstrate the implementation properties. In order to support
Resource Discovery and the implementation of an RD, Group Communication for the
CoAP [RFC 7390] will be integrated. Additionally, a way to integrate the asynchronous
21
4.3. Evaluation
nature of Observe and the rather synchronous ones of Rack and Rails will be designed
and implemented.
4.3. Evaluation
For the evaluation, it shall be analyzed to which extent the specified goals of functional-
ity are met, how the performance of the implementation compares to related work and
how Rails developers respond to given tasks in connection with the developed software
modules.
Unit tests emerge during the Test-driven Development (TDD) that cover most parts
of the implementation source code and that specify and inspect the functionality of in-
dividual modules, classes and methods of the different components. The coverage of
source code by tests (Code Coverage) will be measured. For the demonstration appli-
cation, unit, functional and integration tests shall be created that besides testing the
application itself also demonstrate TDD on the covered software stack with methods
common in Rails. The CoAP library will be tested for its interoperability with other
implementations in an automated way.
The CoAP server will be compared to other implementations by performance tests. In
doing so we will also measure the consumption of resources. We will also compare the
performance of different Rack based frameworks in connection with the server. For the
applicability of the complete stack for the usage of control nodes in home automation
networks, a test installation will be made on home router hardware. The data gained by
the performance tests will be used to reflect on design decisions as the kind of solution
for the realization of the CoAP server.
To evaluate the developer friendlyness and the seamlessness of the integration in
Rails, experienced Rails developers are going to be interviewed after they solved a given
task. This task shall contain CoAP specifics that the developers do not necessarily know
of.
22
Chapter 5
Design
The main component being developed through this work is a CoAP server able to serve
responses from frameworks compatible to the Rack interface. Section 5.1 discusses in-
terfaces, libraries and the concurrency model, and section 5.2 analyzes translations be-
tween the HTTP and CoAP protocols.
The code will be modularized with mixins (Ruby modules included in classes), because
these need less memory compared to the instantiation of classes. Where tuples of data
are needed (as keys for the message deduplication cache, for example), structs were
considered instead of dynamically growing types like arrays. However, a performance
advantage of structs could not be measured (see experiments/structs.rb of the
david repository). On MRI, both Arrays and Structs are implemented in C.
The stable Rack version used in development is 1.6.01 . As a source of the Rack inter-
face specification the version from the current master branch [Rack] is referenced here,
because it was not possible to find a readably formated version of the specification for
Rack 1.6.0.
From the servers perspective, on the Rack side only the environment has to be pro-
vided correctly and completely and the applications call method has to be invoked
with that environment on incoming requests. The call invocation returns the de-
scribed Array, which contains values specific to HTTP and therefore has to be trans-
lated to CoAP. For details on the translation of incoming CoAP messages and outgoing
Rack responses see Protocol Translations (section 5.2) on page 33. There are Rack
1 https://rubygems.org/gems/rack/versions/1.6.0
23
5.1. CoAP Server
specific environment options which are used to pass in objects for input, errors, or for
hijacking the socket (see Observe (subsection 5.2.5) on page 41) and options for con-
currency for example. An exemplary Rack environment is given in Listing 5.1 as a Ruby
Hash. A more detailed description of the requirements of the Rack environment is given
in its specification [Rack].
Choosing the server when running from Rack configuration files (config.ru) or
when starting the server in a Rails project for example is possible by providing a Rack
handler for the CoAP server and registering it. After registration, the desired handler
can be chosen with a parameter to rackup or rails server. A Ruby code example
of a basic Rack handler prototype is shown in Listing 5.2. The handler from the example
would be started by rackup -s example or rails s example.
The .well-known/core interface (see [RFC 6690] and section 7.2 of [RFC 7252])
could be implemented as a Rack middleware. A default Rails application contains al-
ready numerous Rack middlewares for many possible purposes, some of them not ap-
plicable to CoAP based communications. ActionDispatch::Cookies for example
manages HTTP Cookie handling. For now, we do not provide any CoAP features that
24
5.1. CoAP Server
are translated to HTTP using Cookies. It has to be evaluated if the removal of this mid-
dleware actually breaks code which might be useful in the context of constrained appli-
cation development. ActionDispatch::DebugExceptions renders exceptions as
HyperText Markup Language (HTML), which is way to verbose for development with
a CoAP client. Both these examples and other middleware are not needed. Therefore
a way has to be found to deactivate unessential middleware in a Rails CoAP applica-
tion. With a component called Railtie [28] it is possible to run code from a gem upon
initialization of a Rails application and to provide configuration options which can be
used from inside the applications configuration files. The middleware cleanup can be
configurable through a Rails option. A middleware catching exceptions thrown in a
Rack application and converting them to a description for the programmer (JSON for
example) would support the development process. For Rails, such a middleware exists
with ActionDispatch::ShowExceptions but it does not support including excep-
tion details in the JSON body.
A Rack::Lint class instance can be inserted into the middleware stack to automat-
ically test the Rack environment for conformity to the Rack specification [Rack].
25
5.1. CoAP Server
The Rack interface has to be pure Ruby code in any case, so it is suggested to also use
a protocol implementation integratable into Ruby. Compared to other languages, it is
possible to include C/C++ and Java code easily and without indirections like socket
communications and serialization to connect a non-Ruby component with a Ruby one.
Table 3.2 gives an overview of compatible CoAP libraries in different languages. So
even though the server implementation in another language could promise performance
benefits (see subsection 5.1.3), a Ruby solution is preferred here. Both C/C++ and Java
tie the Ruby VM down to a solution written in the respective language. Using a CoAP
implementation in C/C++ would require to write a wrapper C extension which uses
the Ruby API to expose the functions to Ruby code. This makes the usage in JRuby
impossible, since as of JRuby 1.7 the C extension support is deprecated2 . On the other
hand, a CoAP implementation in Java will not run in any Ruby VM outside of a Java
VM.
A pure Ruby implementation of CoAP can be based upon an existing message parser
written by Carsten Bormann, as it was done in the SAHARA3,4 and GOBI 5 projects of
the communication networks research group (AG Rechnernetze6 ) at the Universitat Bre-
men. The GOBI implementation has been published on github.com7 and features client
functionality, basic block-wise transfer and observe support. But it requires some refac-
toring work to meet the objectives of this work such as code quality and non-existence
of side effects for concurrency support. The Code Climate report8 on the library lists
highly complex classes and much code duplication (both indicating a bad structure), and
many code smells (indicating non-conformance to the basic commonalities of Ruby
style guides [3] for example). As of the current commit (1cd1244) in its git repository,
the code climate scores 0.7 (with 4.0 being the best possible result) and the test coverage
as measured by coveralls.io amounts to 88.19%. Arguments for forking this library and
developing it further under this name are that it is already present on rubygems.org
as coap and that it enables quick prototyping. Although we can not be sure, the code
developed during this thesis can be merged back again into the original project.
2 https://twitter.com/headius/statuses/281091403919003649
3 https://sahara.tzi.org
4 http://www.informatik.uni-bremen.de/cms/detail.php?id=75116
5 http://gobi.tzi.de
6 https://ag-rn.tzi.de
7 https://github.com/SmallLars/coap
8 https://codeclimate.com/github/SmallLars/coap/code?sort=remediation_cost&
sort_direction=desc
26
5.1. CoAP Server
As a CoAP server implementation is needed in the context of this work, one of the im-
plementation goals regarding the fork of this library is making it usable in the context of
a server. Abstraction and modularization to enable code reuse and testability are meth-
ods to accomplish that. The current client behavior is contained in one huge method
that is called recursively in some cases. One case, for example, is the assembly of single
block-wise CoAP messages. There are recursion limits to hinder huge resource con-
sumption that are also preventing more than 10 outgoing and more than 50 incoming
blocks. Sending, receiving, retransmissions, parsing, reassembly of block-wise trans-
fers, and other protocol states or operations can be organized in a transmission layer
(documented for example as finite state machines in the CoAP Implementation Guid-
ance draft [lwig-coap-01]) that is reusable by the server, thus avoiding code duplica-
tion. Same goes for other common functionality such as utilities for handling block-
wise transfer [core-block-17]. A more close implementation of the CoAP protocol is a
further implementation goal that has several advantages. By improving matching and
generation of message IDs and tokens, security and reliability can be enhanced. With
avoidance of computation on bogus messages, application state both on the server and
client side can be minimized. The API of the client is planned to be cleaned up and
simplified. For example, the port argument should be optional for requests; obviously,
the CoAP default port can be used, if the argument was omitted. As the server aims for
portability between Ruby VMs, also the common library and client component have to
support them. Celluloid::IO [11], which is described more detailed in the following sec-
tion, can not only be used for the server, but also for the client to realize non-blocking
socket operations. To further support concurrency, the client and common library code
will be revised regarding to globally shared state and side effects. Tests for the server
component are intended to be implemented utilizing RSpec [30]. New tests for the client
component will also be written in RSpec and some of the old tests will be ported during
the development. For the client, test goals consist of increasing the test coverage (for
example through modularization), decoupling of existing tests from remote hosts, and
increasing testing speed. Only optional integration or protocol implementation compat-
ibility tests should remain dependent on remote hosts. For the Resource Discovery (see
section 7 of [RFC 7252]) both on server and client side, the Constrained RESTful Envi-
ronments (CoRE) Link Format [RFC 6690] which describes (available) CoAP resources
is necessary to be implemented.
27
5.1. CoAP Server
The server will send cached response messages on requests identified as duplicates (see
section 4.5 of [RFC 7252]). Old entries in the response cache have to be garbage col-
lected. The cache used can also be utilized for the correlation of answers to sent mes-
sages. As the message receiving, parsing and dispatching happens in a single threaded
event loop, the cache can be accessed without locking. However, other threads such
as the garbage collector for example need to access the cache concurrently. This can
be accomplished in a thread safe manner by using messaging among actors. A sim-
ple implementation of this cache could utilize a Ruby Hash with endpoint address and
message ID as keys and the message and a timestamp for retransmissions and garbage
collection as values. Optimizations are discussed in subsection 5.1.3. Retransmission
of CON messages that received no ACK or RST answer in a certain time can be handled
by another thread operating on the mentioned cache. Additionally, the cache has to in-
clude a timeout and a retransmission count per entry to keep track of retransmissions
(see section 4.2 of [RFC 7252]). However, if the server does not send any confirmable
messages, it does not have to perform retransmissions.
Separate Responses
If the response to a confirmable request takes longer than the retransmission timeout
of the client, separate responses can be used to prevent a retransmission (see section
5.2.2 of [RFC 7252]). Support for separate responses requires a possibility to run ap-
plication code in the background and to later send the resulting response message.
When using Rack with HTTP, the server has to keep a connection alive and later send
an asynchronous response. Therefore this response has to be passed to the server.
Some methods to pass an asynchronous response to the server have been developed
in the Rack community. Rack hijack (see subsection 5.2.5) is the only one being part of
the Rack specification [Rack]. Providing a Proc-like as value to the Rack environment
key async.callback is another method that was integrated into Thin [38]. Through
throw :async or a special Rack response ([-1, {}, []]) it is signalled that the re-
sponse is obtained via the async.callback. Another method implemented in Thin is
a deferrable body object9 . In each of these cases, the middleware used must be aware
or is otherwise circumvented10 . Rack hijack suffers from the same problem. Reel in-
teresting because also based on Celluloid does not have a solution to this problem that
works with the Rack interface.
9 https://github.com/macournoyer/thin/blob/v1.6.3/example/async_app.ru#L65
10 https://github.com/rkh/async-rack/blob/v0.5.1/README.md
28
5.1. CoAP Server
As CoAP is not constrained to keep a connection alive, there is another way of imple-
menting separate responses that is also mentioned in section 5.2.2 of [RFC 7252]. Before
initiating the generation of a response by the application, the server can start a timeout.
When the timeout finished before a response is available, the server sends an empty ACK
message indicating a separate response. The actual response generated by the applica-
tion then has to be sent as a confirmable or non-confirmable message. A method can
be provided with which an application programmer can immediately signal a separate
response if a long response time is foreseeable.
Listing 5.3 shows an exemplary source code from the application programmers side.
The call of the separate method would send an immediate response to the client by
messaging the server actor. To actually asynchronously run the code, the block and
the controller instance is passed to a separate Celluloid actor. This single actor or actor
from a thread pool would then call the block in the context of the controller instance.
The instance would have to persist until the asynchronous code finished running. The
controller response would have to be translated like it is in a piggybacked case. The
timeout method mentioned in the previous paragraph enables also the separate answer
passing the Rack middleware stack but the generation of the response is happening syn-
chronously. For the seperate method extension it has to also be ensured, the response
is passing the Rack middleware stack.
To meet the performance objectives of this work (as stated in subsection 4.1.2), some
consideration is necessary. As layed down in section 3.1, we will use Celluloid [9] as con-
current object framework and the Celluloid::IO [11] reactors for receiving from sockets.
There are different web server architectures. We choose a Singe-Process Event-Driven
(SPED) architecture [6] for its reasonable performance and scalability as well as its ease
29
5.1. CoAP Server
Observe tick
respond
call
200, Bar
Figure 5.1.: Exemplary actor interaction on Observe tick. The Observe actor receives the
Rack application response from the Server actor and subsequently notifies
the client about a change of the resource representation.
30
5.1. CoAP Server
The Observe actor calls the Rack application to determine if the resource representation
changed. This happens from the Observe actors thread concurrently to the Server thread.
The framework and the application programmer have to ensure that every data access
is thread safe. Rails itself is capable of multiple threads concurrently calling for a frame-
work response. However, version 4.2 uses a Rack middleware called Rack::Lock that
locks out concurrent framework response calls. This can be deactivated with the Rack
environment option rack.multithread set to true. We will deactivate Rack::Lock
and allow concurrent framework response calls by default in the server software.
A GarbageCollector actor removes obsolete entries from the message deduplication
cache and the list of observers (see subsection 5.2.5). The cache is placed as a Hash
instance variable inside the Server actor and can be accessed from other actors through
messages. This ensures thread safe retrieval and update of cache entries. Performance
tests during the development of the concurrency architecture of the server software
showed that accessing the cache through Celluloid actor messaging has to be used thrifty.
Placing the cache in a separate actor and performing the main lookups and cache in-
serts via messaging from the Server actor had a negative performance impact of over
500 requests per second (presumably through the messaging overhead). In JRuby 1.7
this overhead is even bigger since it implements fibers through OS threads12 . In MRI (at
least until 2.3) the standard library Hash class neither is thread safe nor does it support
concurrent retrieval or update [37]. With a GIL assuring only one thread running at a
time at least thread safety is not a problem [2]. JRuby supports several threads running
concurrently and implements updating instance variables in a thread safe manner13 . So
in both MRI and JRuby, the standard library Hash class should suffice when it comes
to conflict free concurrent access. As described in section 3.3.1, Californium uses a Hash
class supporting concurrent retrieval and updates for performance reasons. Adopting
a concurrent Hash class for Ruby may also optimize performance. The thread safe gem14
provides different thread safe data structures that are Ruby VM independent. It in-
cludes a hash-like object called ThreadSafe::Cache which according to the README
file has much better performance characteristics esp. under high concurrency. How-
ever, we could not measure a performance gain compared to the Ruby standard library
Hash (see experiments/thread safe.rb in the servers respository15 ). As struc-
tures, both a Hash with two element Arrays (endpoint and message ID) as keys, and a
nested Hash ({endpoint => {mid => value}}) were considered. Although the lat-
12 https://github.com/celluloid/celluloid/wiki/Gotchas#tasks--jruby
13 https://github.com/jruby/jruby/wiki/Concurrency-in-jruby#thread-safety
14 https://github.com/ruby-concurrency/thread_safe
15 https://github.com/nning/david
31
5.1. CoAP Server
5.1.4. DTLS
32
5.2. Protocol Translations
tificate in Certificate mode. Also the Rack environment can provide a key (for example
coap.dtls) which can be used for the app to determine the DTLS encryption mode.
Transparent authentication based on DTLS would require the authentication relation-
ship to be terminated at the server and translated into a Rails authentication framework
specific (e.g. warden16 ) Rack::Session component. It would also require a mapping
between DTLS identities or certificates and application specific subjects which has to be
provided by the application itself.
To translate between CoAP and the HTTP centric Rack interface, the specifications for
Cross-Protocol Proxying between CoAP and HTTP (see section 10 of [RFC 7252]) and the
Guidelines for HTTP-CoAP Mapping Implementations [core-http-mapping-06] can be used.
However, a CoAP-HTTP proxy in front of an ordinary HTTP Rails application would
not suffice the objectives of this work as the framework shall support a CoAP specific
development and therefore should be explicit about CoAP. The Cross-Protocol Proxy-
ing section states that since HTTP and CoAP share the basic set of request methods,
performing a CoAP request on an HTTP resource is not so different from performing
it on a CoAP resource (section 10.1 of [RFC 7252]) and defines a few departures of
behavior of the methods GET, POST, PUT and DELETE that have to be implemented
accordingly. Section 7 of [core-http-mapping-06] defines a mapping of CoAP to HTTP
response codes (also see section 6 of [RFC 7231]). That, however, can not be applied in
this case, because the frameworks HTTP response code has to be mapped to a CoAP
response code. Tables 5.1 and 5.2 define mappings in the opposite direction (adopting
entries from the CoAP to HTTP mapping table where possible). As a fallback, HTTP
return codes not present in the mapping table are translated via division by 100 (e.g.
HTTP 404 Not Found maps to CoAP 4.04). To enable explicit returns of CoAP response
codes from Rack applications, Float values can be used. In this case, the mapping has
to be skipped.
Informational HTTP response codes (as defined in section 6.2 of [RFC 7231]) do not
result in an immediate answer by the server and are therefore not translated. As CoAP
supports no Redirect HTTP response codes, another way has to be found to pass redi-
rection information to the client. It would be intransparent for the server to follow the
redirects and return the redirection target resource representation to the client as if there
was no redirection. The client would have no way to determine if a resource is actually
16 https://github.com/hassox/warden
33
5.2. Protocol Translations
HTTP CoAP
200 OK 2.05 Content
202 Accepted 2.01 Created
203 Non-Authoritative Information 2.05 Content
206 Partial Content Not applicable
existent. To pass the redirection information to the client, the server can translate the
Rack redirect answer into a JSON document. An Example is given in Listing 5.4. If con-
ditional requests (see section 5.10.8 of [RFC 7252] and 3 of [RFC 7232]) are implemented,
HTTP 304 Not Modified would be mapped to CoAP 2.03 Valid. All Server Error response
codes that are not translated directly via division (505, 506, and 511) map to the generic
CoAP 5.00 Internal Server Error.
To return CoAP codes as accurate as possible, sometimes not only the HTTP return
code but also the request method has to be considered. An example for this case is the
answer to a CoAP DELETE request. Section 4.3.5 of [RFC 7231] states the origin server
SHOULD send a 202 (Accepted) status code if the action will likely succeed but has not
yet been enacted, a 204 (No Content) status code if the action has been enacted and no
further information is to be supplied, or a 200 (OK) status code if the action has been
enacted and the response message includes a representation describing the status. The
CoAP specification (see 5.8.4 of [RFC 7252]) only demands a CoAP 2.02 Deleted status
code independent of the success cases. So for a more correct implementation, response
codes have to be mapped from a tuple of HTTP method and response code to a CoAP
response code.
Where a direct translation is adequate, the basic mapping of headers will be imple-
34
5.2. Protocol Translations
HTTP CoAP
402 Payment Required Not applicable
Table 5.2.: Mapping of HTTP to CoAP return codes (4xx Client Error)
mented as shown in Table 5.3. (This table does not consider all existing HTTP headers,
because of their huge number.)
Some translations could be solved through Rack middleware (see subsection 5.1.1).
Except for the Resource Discovery, translation through methods present directly in the
server code is favored over middleware usage. Using middleware for translating HTTP
to CoAP headers would change the Rack environment to contain CoAP headers. This
would break transparency of that exemplary middleware and it will not be possible to
prepend it by another middleware expecting HTTP headers.
The following subsections describe the translation of more complex protocol features.
The most naive implementation of handling requests for certain blocks of a resource
representation through block-wise transfers [core-block-17] would be requesting a full
framework answer on each request and returning only the requested chunk. However,
if the resource representation changes in between different requests with Block2 Op-
tion in control usage (see section 2.3 of [core-block-17]), the payload possibly can not
be reassembled on the client side. According to section 2.4 of [core-block-17] a server
should include an ETag option with its responses. This way a client can try to obtain
a fully consistent resource representation again if the ETag value suddenly changes. It
is also possible to cache the resource representation initially received from the frame-
work in connection with the endpoint until the last chunk is requested. If the server
implements caching of framework responses (and the application supports it by setting
35
5.2. Protocol Translations
caching headers), the performance can be increased, because the resource representa-
tion could be cached for all endpoints. Another approach would be using HTTP Range
requests [RFC 7233] but that also would have to be supported manually by the applica-
tion17 . For now we intend to use the naive implementation, because it does not require
developing effort on the Rack application side.
For the Content Negotiation to be translated between both protocols (see section 5.3 of
[RFC 7231] for HTTP and section 5.5.4 of [RFC 7252] for CoAP), the accept option of a
CoAP request has to be rewritten into a HTTP media type and a content encoding, which
can be passed in to the Rack application through the HTTP ACCEPT field in the environ-
ment. If possible, the application responds with an appropriate body representation
and the correctly set Content-Type header. Section 6.2 of [core-http-mapping-06] fur-
ther specifies the media type mapping and defines a Loose Media Type Mapping that can
be used to generalize HTTP media types to ones supported by CoAP. In section 6.3 also
an algorithmic conversion from HTTP Internet Media Type to CoAP Content Format is
given.
For constrained nodes, a compact payload serialization format such as CBOR [RFC
7049] is essential. It is possible to transcode between payload content formats to make
use of efficient formats (as mentioned in section 6.4 of [core-http-mapping-06]). JSON
36
5.2. Protocol Translations
18 https://github.com/lucas-clemente/cbor-simple
37
5.2. Protocol Translations
Since version 1.5.0, Rack supports HTTP/1.1 Chunked Transfer Coding (see section
4.1 of [RFC 7230]). In a plain Rack application as seen in Minimal Rack application
(Listing 3.1) on page 11 for example, the response body is chunked transparently if the
Content-Length header is omitted. There is not really a CoAP extension which is compa-
rable, although with [core-coap-streaming-00] there is an expired draft. This, however,
needs the client to explicitly send an observe register (see sections 2.1 of [core-coap-
streaming-00] and 3.1 of [core-observe-16]). The server has to reassemble the chunked
resource representation, possibly cache it and return it to the client.
The CoAP Resource Discovery (section 7 of [RFC 7252]) is especially useful in M2M com-
munication. After nodes are discovered through Service Discovery (see section 7.1), the
.well-known/core interface according to [RFC 6690] (as referenced by section 7.2)
can be used to discover a nodes resources and their attributes such as the content for-
mat or an interface description. An automatic listing of a rack applications resources
is examined in the next subsection. The Multicast subsection describes the require-
ments of multicast enabled resource discovery. The design of a Resource Directory (RD)
[core-resource-directory-02], which maintains CoRE Link collections of different nodes,
is considered in the Resource Directory subsection.
38
5.2. Protocol Translations
The only attribute of a Link that can be determined by just enumerating the routes
is href. A method of annotating resources with information about Resource Type (rt),
Interface Description (if), Maximum Size Estimate (sz), and the other possible attributes
for CoRE Link descriptions has to be developed. One possibility would be providing a
method in the context of a controller defining both default attributes and attributes for
specific resources. Listing 5.5 provides an example of how this could be used. On call of
the discoverable method, these attributes have to be communicated to the instance of
the Resource Discovery Rack middleware, which is instantiated at the start of the server.
Besides dynamically changing a method of the middleware instance to return the right
structure containing any defined link attributes, the middleware instance could also be
a Celluloid actor that can receive messages triggered by the call of discoverable in
the controller context. An overview in the form of a sequence diagram is to be seen in
Figure 5.2. Possible performance impacts of Celluloid actor inclusion in the middleware
stack have to be analyzed.
Rails returns the available resources as URI patterns. Those patterns are known for
example from the output of the command rake routes ran in a Rails project. An
URI pattern like /things/:id could be machine processable, if all involved endpoints
support :id is a variable substitution. But this pattern follows no known standard. The
URI Template standard [RFC 6570] defines ways of variable expansions for URIs. By
this definition, the previously mentioned pattern could be represented by the template
/things/{id}. This substitution can easily be performed by the middleware. How-
ever, URI Templates are not supported in CoRE Link URI-references.
Actors included in the middleware stack should be supervised and therefore restarted
on crash, because otherwise any request fails after one actor in the stack died due to the
impossibility of invoking the call method on a dead actor. This is not trivial, because
the Celluloid API only provides a supervision possibility if the actor is instantiated in a
special way but Rack expects to instanciate middleware objects itself. Probably this can
be solved through a proxy object.
Multicast
39
5.2. Protocol Translations
Link attributes
GET /.well-known/core
call
2.05
Figure 5.2.: Interaction regarding action annotation for Resource Discovery. The Dis-
covery actor receives link attributes of resources from the respective con-
troller. The resource descriptions returned on client request then contain
these attributes.
40
5.2. Protocol Translations
(as it is described by section 8.2 of [RFC 7252] and section 4.1 of [RFC 6690]. Through
a CoAP specific Rack environment entry (coap.multicast), it would be possible for
applications to determine if an incoming request was received on a multicast address.
It has to be evaluated how the synchronous nature of HTTP and therefore Rack and
Rails can be integrated for example with the leisure period requirement mentioned in
section 8.2 of [RFC 7252].
5.2.5. Observe
19 https://github.com/ngauthier/tubesock
41
5.2. Protocol Translations
ister or deregister requests, the server actor(s) message the observe actor. The observe
actor maintains the list of registered observers and periodically determines whether to
send observe notifications (further called Observe tick). The interaction of actors among
each other and with the client and the Rack application in the cases register, deregister
and tick are visualized in Figure 5.1. The most quick and easy implementation for deter-
mining whether an update is necessary, is to clone the original request of a resource, pass
it to the framework (Rack application) and send a notification if the resource changed.
With the framework answers validator header fields Last-Modified and ETag (see
sections 2.2 and 2.3 of [RFC 7232]) (or, if they are missing, a hash sum of the body) it
can be determined if the framework returned a changed body and thus a client has to
be notified about the updated resource. An optimization for frameworks supporting
validator header fields is to facilitate conditional requests. This way it is possible, the
overhead of regenerating the resource representation can be stinted. For an exemplary
interaction in this case, refer to Figure 5.3. Rails uses Rack::ETag for entity tags which is a
middleware that can also be used to provide plain Rack applications or other Rack based
frameworks with ETag support. In Rails, the decision whether the resource represen-
tation has to be rendered is made from controller code and thereby explicitly necessary.
The notification can be omitted if the entity tag did not change and the max-age time of
the last notification is not expired. If this max-age time is expired and the entity tag did
not change, a notification with CoAP 2.03 Valid response code is sent.
For the observer list management, besides adding observers to resources and delet-
ing them, the observe actor has to implement a garbage collection for obsolete observe
relationships (as described in section 3.6 of [core-observe-16]). If observe notifications
are always sent as non-confirmable messages and the server does not send any other
confirmable messages, the retransmission logic can be omitted. This saves some mem-
ory and CPU resources. The specification explicitly states, A notification can be con-
firmable or non-confirmable, i.e., it can be sent in a confirmable or a non-confirmable
message. The message type used for a notification is independent of the type used for
the request and of any previous notification. (see section 3.5 of [core-observe-16]).
For the application code it would be possible to utilize the HTTP/1.1 caching headers
like Expires or Cache-Control max-age (see sections 5.3 and 5.2 of [RFC 7234]) to
communicate when a resource should be polled again and in which interval a resource
change should be polled for. Polling for resource updates wastes resources, so for a
more performant solution, the framework or application code would have to message
the observe actor about a resource update. If the resource is a representation of a list
of saved entities for example, the framework would have to notify the observe actor on
42
5.2. Protocol Translations
Observe register
GET /example, observe: 0
call
Observe tick
respond
call(If-None-Match: 0x91)
304 Not Modified
respond
call(If-None-Match: 0x91)
Figure 5.3.: Observe interaction with conditional requests. On Observe register the ETag
value of the Rack response is saved and later used to determine if the re-
source representation changed and an update is necessary.
43
5.2. Protocol Translations
each creation or deletion of an entity. However, this problem can not generally be solved
by callbacks triggered on database changes. Explicitly signalling a resource update with
a certain method call from the Rails controller is not possible, since the controller code is
only called upon request from the server or observe actors and not running as an actor
itself.
In Listing 5.6 a Rails controller code example is shown that both manipulates the
polling frequency of the observe actor for this resource and only renders the re-
source representation if a conditional request by the observe actor indicates a change.
Rails::Observers20 can be used to further control cache invalidation.
20 https://github.com/rails/rails-observers
44
Chapter 6
Implementation
This chapter documents the implementation drafted in the previous chapter. Each com-
ponent realized as an independent module is explained in detail in the following sec-
tions. Table 6.1 gives an overview of the components we worked on, their respective
licenses, and the sections covering their implementation.
For all implemented components, we make use of several external libraries. The most
important ones are listed in Table 6.2. A more exhaustive list can be obtained from the
Gemfile.lock files inside the project repositories.
45
6.2. CoAP Library
A small change was integrated into the Celluloid::IO project. Through inclusion of
Celluloid::IO, socket classes are wrapped in a way that prevents blocking usage. Methods
which do not block are directly delegated to the wrapped standard library socket class.
A delegation for the addr instance method was added in the course of this work1 .
The CoAP library based on the message parser by Carsten Bormann published by the
GOBI project2 was forked on GitHub3 . The original project is released under the terms
of the MIT license4 , and so is the fork we developed. One of the original authors, Simon
Frerichs, gave us access to the coap gem on rubygems.org and the first version of our
fork we released was 0.1.05 . The current release version is 0.1.1. Initial objectives were:
Restructurization, modularization (for code reuse in the server component), removal of
code duplication, freeing of tests from external services, and bug fixes. Another impor-
tant objective was to make any socket communications non-blocking and shared data
structures compatible with concurrent access. The following lists extracted from the
commit log summarize the individual changes to the CoAP library6 by category. The
whole commit log in comparison to the original source code can be found on GitHub7 .
46
6.3. David
6.3. David
The core of this work the CoAP server component with a Rack interface is called
David in reference to Goliath (an asynchronous HTTP server with a Rack interface). It is
realized as a Ruby gem8 and can be used as a drop-in replacement for HTTP servers in
a Rails application. It is released under the terms of the General Public License (GPL)
8 https://rubygems.org/gems/david
47
6.3. David
[GPLv3] and downloadable on GitHub9 . James Fairbairn originally held david as a name
on rubygems.org but kindly gave it to us. The first public release was version 0.3.0.pre.
The current stable release is 0.4.3 and all code descriptions in this section refer to that
version.
The code was developed mostly on MRI versions between 2.1.4 and 2.2.0 but it was
also optimized for and tested on MRI 1.9.3-p551 and 2.3.0-dev, JRuby 1.7.18 and 9.0.0.0-
pre, and Rubinius from 2.4.0 till 2.5.2. In JRuby and Rubinius, the detection of multicast
messages does not work because of the platforms Socket APIs (for further details, see
subsection 6.3.3). The message handling of David running on Rubinius suffers from a
deadlock problem that could not been solved yet. Some of the servers features such as
application Resource Discovery (see section 6.4) are specific or at least tied to Rails and
do not work with every Rack based framework.
The following subsections handle specific aspects of the implementation.
6.3.1. Options
9 https://github.com/nning/david
48
6.3. David
6.3.2. Rack
David adds some application specific entries to the Rack environment which are listed
in Table 6.4.
We monkey-patched the Rack code to use David as the default Rack han-
dler unless Rails is loaded and config.coap.only is set to false (see
lib/david/guerilla/rack/handler.rb). This way executing rackup or
rails s starts the CoAP server, and does not try the original Rack han-
49
6.3. David
dler order (thin, puma, webrick). The actual Rack handler is defined in
lib/david/rack/handler/david.rb and performs the startup of the different
server actors (Server, GarbageCollector, and Observe) in a Celluloid supervision
group.
Automatic provision of Resource Discovery trough a .well-known/core resource
and return of exceptions caused by the application in a human readable format are cre-
ated as Rack middleware classes David::ResourceDiscovery (see section 6.4) and
David::ShowExceptions (see lib/david/show exceptions.rb). They are in-
serted into the middleware stack by the David::Railties::Middleware railtie (see
lib/david/railties/middleware.rb). Other middleware shipped with Rails is
removed if it (currently) provides no features in connection with CoAP (see line 8 ff.). It
is possible to keep it included in the middleware stack by setting coap.only to false
in the Rails application config.
Parsing incoming transmissions does not utilize other shared functionality from the
CoAP library than the CoAP::Message.parse method, which was provided by
Carsten Bormann and only changed minimally. For answering or initiating transmis-
sions, the CoAP::Transmission class (see lib/core/coap/transmission.rb in
version 0.1.1 of the coap gem source) was used first to avoid code duplication. It ab-
stracts timeouts, retransmissions, ACK answering, separate answers and checking of
message identifiers and tokens. For more information, refer to section 6.2. However,
when optimizing the server for throughput performance it became obvious that this
shared functionality also introduced overhead. Most features were too client centric
anyway: Retransmissions, incoming separate transmissions and message token man-
agement are not necessarily useful for a server. These shared code parts are also not
modular enough to allow a single place for incoming message dispatching. So after
a redesign of the architecture, messages are sent by direct invocation of send on the
server socket. References to that socket are passed between actors. The first version
with the revised architecture is 0.4.0. A cache for message correlation and deduplica-
tion of confirmable requests is currently solved through a Ruby hash with endpoint and
message identifier as key and the cached response and a timestamp for cache invalida-
tion as values (see lib/david/server/mid cache.rb). The GarbageCollector
actor (see lib/david/garbage collector.rb) periodically cleans the cache from
obsolete messages. Using the reimplemented block support of the coap gem, block-wise
transfers [core-block-17] were integrated into the server. However, the current state only
50
6.3. David
supports block-wise responses; block-wise transfers for assembling requests are not sup-
ported. Separate responses as designed in section 5.1.2 were not implemented yet as
they make a bigger change to the current request/response cycle necessary.
Observe support is accomplished through a Celluloid actor handling the no-
tifications. The Server actor adds or removes listeners via #add or #delete
messages to the Observe actor (as depicted in Figure 5.3; also see line 133 of
lib/david/server/respond.rb). Listeners are saved in a Ruby hash with end-
point and message token as key and observe number (initially 0), original request,
rack environment, originally returned ETag, and a timestamp for cache invalidation as
values (see lib/david/observe.rb). In a static interval of 3 seconds by default, the
Observe actor checks every target resource of the observe relationships on changes and
sends updates to the endpoint if necessary. The update check is solved by requesting
a full framework answer for the original request from the Server actor. If the ETag
differs between the original request and response, an observe notification is sent to
the endpoint. The observe relationship persists unless the endpoint answers with a
reset message to a notification, explicitly deregisters or the update check is answered
with an error response code by the framework or application. There is potential for
performance improvements in the current implementation, because the Observe actor
neither refreshes every individual resource only once per tick nor makes effective use of
HTTP caching as drafted in subsection 5.2.5. A correctly set ETag header is mandatory
for the Observe actor to decide if an observe notification has to be sent. Rails automat-
ically includes Rack::ETag, which is a Rack middleware that transparently adds an
ETag header. This middleware can be included manually when using more minimal
frameworks. As an example, see line 6 of config.ru, a Rack configuration that starts
a plain Rack application for testing purposes.
Listing 6.1 shows the implementation of the event loop. Inside a class includ-
ing Celluloid::IO, recvfrom automatically uses the Celluloid::IO event
loop. There were some changes necessary to the original message handling to de-
termine if a request has been received on a multicast address. The non-blocking
#recvfrom method exposed by Celluloid::IO::UDPSocket class instances does
not return sufficient information. Therefore #recvmsg nonblock of the wrapped
UDPSocket class instance was used to receive data and information on the tar-
get address from the socket. The event loop was implemented as in #recvfrom
of Celluloid::IO::UDPSocket (see the Celluloid::IO::UDPSocket im-
plementation and line 45 of lib/david/server.rb for reference) using
Celluloid::IO.wait readable which is based on the OS independent I/O se-
51
6.3. David
lector API of nio4r10 . In JRuby and Rubinius we use the non-blocking recvfrom
method provided by Celluloid::IO. This change was not proposed to the Celluloid::IO
project, because we could not get a Ruby VM independent implementation working
due to the absence of a recvmsg nonblock method in JRuby and Rubinius. Since
Celluloid::IO aims on VM independence, this effort was canceled for now.
52
6.3. David
programmer, because the generation of the Rack applications response happens inside
the event loop and it stops other incoming messages from being processed. Non block-
ing database adapters have to be used in the Rack application. Support for separate
answers would especially be useful in this context.
The CoAP methods are mapped directly to their HTTP counterparts and passed to the
Rack compatible framework via the REQUEST METHOD Rack environment entry. Mes-
sages with CoAP codes that are undefined method codes (see section 12.1.1 of [RFC
7252]) are dropped directly after parsing the message.
Most direct mappings of HTTP response codes and headers to CoAP response
codes and options are performed as specified in section 5.2 through the methods
defined in lib/david/server/mapping.rb. The methods are included into
the David::Server class and used especially in its respond method defined in
lib/david/server/respond.rb. The HTTP response codes returned in Rack re-
sponses are mapped according to the procedures described in section 5.2. In the Ruby
code the map is represented through the constant HTTP TO COAP CODES. With the
Rack option MinimalMapping, the default mapping of HTTP to CoAP response codes
can be deactivated in case application programmers want to explicitly return a certain
code but can not use a Float (see section 7.2.2). Currently the implementation does not
map HTTP return code and methods to CoAP codes. Also the translation of HTTP
redirects to JSON redirect descriptions is not implemented. Both were queued up
because of the time constraints of this work.
The Mapping module also contains methods to convert certain headers from HTTP
to CoAP or the other way round. etag to coap converts the HTTP ETag header value
string (containing a hash of the body) by interpreting its first bytes (defaulting to four)
as an integer. location to coap splits the Location header string value into CoAP
Location-Path segments. max age to coap returns the Cache-Control headers max-
age value as an integer. The method accept to http is used to translate the Accept
header from CoAP to HTTP and is therefore enabling Content Negotiation (as specified
in subsection 5.2.2). The options Content-Format, Max-Age, Location-Path, and Size2
are mapped without individual methods of the Mapping module. The other direct
header mappings drafted in Table 5.3 (Proxy-Uri, Proxy-Scheme, Location-Query, If-
Match, If-None-Match, and Size1) are not implemented, yet.
Content transcoding of CBOR to JSON and vice versa is activated if the Rack envi-
ronment option CBOR or the Rails option config.coap.cbor are set to true. It is
53
6.4. Resource Discovery
6.3.6. Architecture
We made especially use of Celluloid actors and the inclusion of modules into classes for
modularization. Figure 6.1 and 6.2 show the object relations. The former concentrates
on the actors mainly involved in request handling and response processing, whereas the
latter shows Rack middleware and Rails extensions. In both graphs names are suffixed
with a letter in square brackets that indicates the type. C stands for a Ruby class, M for
a model, and A for a Celluloid actor.
54
6.4. Resource Discovery
55
Figure 6.1.: Object Relations (Server)
messages
David::GarbageCollector [A]
starts messages David::Multicast [M]
instanciates starts includes
Rails Rack::Handler::David [C] David::Observe [A]
starts messages
includes David::Options [M]
David::Server [A] instantiates
messages includes includes instantiates
David::Request [C] CoAP::Block [C]
wraps
David::MidCache [M]
David::Mapping [M]
includes instantiates
CoAP::Message [C]
includes
David::Respond [M] David::Utility [M]
instantiates
includes
includes CoAP::Coding [M]
David::Constants [M]
6.4. Resource Discovery
Rails
instanciates instantiates
David::Railties::Middleware [C]
starts
David::ResourceDiscovery [A]
56
6.5. Resource Directory (RD)
and supervised named by calling supervise as instead of new (in lines 7-12 of
lib/rack/handler/david.rb). However, when a middleware is inserted into the
stack with a Railtie, not an instance of the class but the class itself is passed. This
way a discovery actor could not be supervised by Celluloid and communicated with
by name. Therefore, it has to register manually on initialization. This unfortunately
does not mean it is also supervised. In this case, the solution is to proxy the actual
Resource Discovery actor with a class behaving like an ordinary Rack middleware
(as seen in lib/david/resource discovery proxy.rb). On initialization of this
class, the Resource Discovery actor is instantiated and supervised named. When the
call method is invoked, it is passed on to the actor.
12 https://github.com/nning/core-rd
57
Chapter 7
Evaluation
To support the development process and to measure code quality and sustainability,
unit tests were written. The test code coverage and the code climate are also recorded.
Our considerations of the research question How to handle a huge amount of IoT de-
vices? are evaluated with performance benchmarks. The interoperability of the differ-
ent interfaces of the server were benchmarked to analyze our considerations regarding
to the research questions covering the CoAP implementation, the Rack interface, and
translations of headers and payloads between HTTP and CoAP.
The CoAP library and client, the server (David), and the RD implementation (core-rd)
were developed mostly test-driven with RSpec [30]. For the former some essential tests
were ported to and new ones were written with RSpec. For the other two components
RSpec was used exclusively. Although it offers some features supporting Behavior-
Driven Development (BDD), we used RSpec only to write DRY specifications of the
codes functionality. The Test-driven Development of the RD showed that RSpec can
seamlessly be used for the development of CoAP applications with Rails.
The test coverage is determined by Coveralls, a web service that gets coverage mea-
surement values from test runs in the Continuous Integration (CI) system using the
simplecov gem1 . The results are prepared for easy analyzing by developers and dis-
played publicly. We used CodeClimate another similar service for measuring for ex-
ample the complexity of methods by counting conditional branches and method calls.
Classes and modules are classified by their complexity into categories from A (best) until
F (worst). A code climate score (between 0.0 and 4.0) is computed from that information
that indicates code quality.
For the fork of the coap library gem, the code climate score was raised from 0.74 to
1 https://rubygems.org/gems/simplecov
59
7.2. Benchmarking
2.662 and the test coverage from 88.19% to 93.06%3 (although the total count of code
lines increased from about 1270 to 1900). The test coverage for core-rd the RD draft
[core-resource-directory-02] implemented in Rails is about 90.01%4 , the CodeClimate
score is 3.375 . The source code of David scores 3.576 on CodeClimate and has a test
coverage of 92.94%7 .
7.2. Benchmarking
7.2.1. Performance
We tested the requests David handles (receives, parses, processes, and answers) per sec-
ond with Rack and Rails applications simply returning a plain Hello World! string.
This requests per second value is measured with a number of concurrent clients that in-
creases from 10 to 10,000 (by 10 below 100, 100 below 1,000 and 1,000 below 10,000)
simulated with Cf-CoAPBench 1.0.0-M38 . We use a server running on loopback in-
stead of a physical network and the different Ruby VMs mentioned below. The exact
versions are noted as output from the ruby -v command. Benchmarking for each
concurrency value is performed for 30 seconds. The average value of three subse-
quent runs is recorded. After each benchmark, we wait 15 seconds. At the begin-
ning of the testing of each VM or framework, a 60 seconds warmup is done. The
benchmark system is a notebook with a Core i7-3520M CPU and 16 GiB of RAM
running Arch Linux. Benchmarks were conducted on the core repository linux ker-
nel version 3.18.6-1 without further tuning. We only increased the maximum num-
ber of open file descriptors to enable 100,000 open UDP sockets. The CPU supports
Hyper-Threading and regularly runs at 2.9 GHz and 3.9 GHz with only one active core.
Server processes are started with rackup and a framework specific rackup configu-
2 https://codeclimate.com/github/nning/coap
3 https://coveralls.io/r/nning/coap
4 https://coveralls.io/r/nning/core-rd
5 https://codeclimate.com/github/nning/core-rd
6 https://codeclimate.com/github/nning/david
7 https://coveralls.io/r/nning/david
8 https://github.com/eclipse/californium.tools/tree/1.0.0-M3/cf-coapbench
60
7.2. Benchmarking
1. MRI 2.2.0p0
(2014-12-25 revision 49005)
2. MRI 2.3.0dev
(2015-02-12 trunk 49574)
3. JRuby 1.7.19
(1.9.3p551) 2015-01-29 20786bd on OpenJDK 64-Bit Server VM 1.7.0 75-b13 +jit
4. JRuby 9.0.0.0-pre1
(2.2.0p0) 2015-01-20 d537cab OpenJDK 64-Bit Server VM 24.75-b04 on 1.7.0 75-b13
+jit
The garbage collection of both MRI versions was tuned by setting environment vari-
ables to increase the memory allocation maximum (128M) and to prepare a certain
amount of free slots after starting the VM (200000). JRuby has been configured to use
the Server Java Virtual Machine (JVM). Listing 7.1 shows the environment variables and
their values.
We benchmarked Reel [29] on the same hardware with 1,000 and 10,000 concurrent
clients to get a reference value to a HTTP server based on a very similar concurrency
model and also on Celluloid and Celluloid::IO. It achieved 3,391.6 requests per second
(RPS) at 1,000 and 3,414.4 RPS at 10,000 concurrent connections running in MRI 2.2.0p0.
We also tried to perform a performance benchmark with David running on an Ubiquiti
EdgeMAX Lite router, as it is quite customizable and comparable to common customer
router hardware. However, we could not get the performance benchmark running even
after extensive experiments. See section B.2 for installation instructions on that hard-
ware and a documentation of the steps taken by us.
61
7.2. Benchmarking
14000
13000
12000
Requests per second
Ruby VM
mri22
11000
mri23
jruby17
jruby9
10000
9000
8000
7000
10 50 100 500 1000 5000 10000
Concurrent clients (log.)
62
7.2. Benchmarking
11000
10000
9000
8000
Requests per second
Ruby VM
7000 mri22
mri23
jruby17
6000
jruby9
5000
4000
3000
2000
63
7.2. Benchmarking
6
Percentage of lost messages
Ruby VM
mri22
mri23
4 jruby17
jruby9
64
7.2. Benchmarking
13000
12000
11000
10000
Requests per second
Framework
9000 Rack
Rails
8000
7000
6000
5000
65
7.2. Benchmarking
14000
13000
12000
11000
10000
Requests per second
9000 Framework
Rack
8000
Rails
7000
6000
5000
4000
3000
2000
66
7.2. Benchmarking
The rate of requests per second stays quite stable with rising numbers of concurrent
clients in any Ruby VM (see Figure 7.1 and 7.2). In JRuby 1.7.19 throughput rates of about
14,000 requests per second are possible. MRI 2.3.0dev handles about 12,500 requests per
second. In MRI with Rack, the peak throughput is reached with quite a low number of
concurrent clients compared to Rails. Until 200 concurrent clients, the Rails framework
overhead in the event loop seems to be the bottleneck. A decrease in throughput with
high numbers of concurrent clients does not occur. In JRuby the throughput with Rack
and Rails in relation to concurrent clients runs quite comparable with between 6,500 and
3,500 requests per second deviation. With Rails JRuby 1.7.19 does not perform as good
as MRI 2.3.0dev especially with lower numbers of concurrent clients (see Figure 7.4 and
7.5). In JRuby 9.0.0.0-pre1 the server has a surprisingly low throughput especially with
Rails and mainly with low numbers of concurrent clients.
Figure 7.3 shows the message loss through timeouts waiting for responses by Ruby
VM with Rack. With 300 concurrent clients stressing the server, timeouts when wait-
ing for responses start to occur. This happens throughout different VMs and with dif-
ferent numbers of total messages received during a 30 seconds stressing period. The
timeout rates rise with the number of concurrent clients to a maximum of about 9%
at 100,000 concurrent clients (MRI 2.2.0p0 serving a Rails application). We tried in-
creasing the UDP receive buffer up to 1 MiB (default was 208 KiB) via the sysctl flag
net.core.rmem max but could not observe a descrease in message loss. It raises the
question if Cf-CoAPBench includes the exponential back-off mechanism for retransmis-
sions of confirmable messages to achieve congestion control (see section 4.2 of [RFC
7252]). We could not find any indication for this (see line 113 of VirtualClient).
Plots showing the message timeouts by Ruby VM with Rails and the throughput by
framework in MRI 2.2.0p0 and JRuby 9.0.0.0-pre1 are included in the appendix (see sec-
tion B.1).
7.2.2. Interoperability
The interoperability of the server has to be evaluated especially regarding to the two
interfaces with other software. It interfaces via CoAP with other nodes and via Rack
with web frameworks. So test cases are needed for both interfaces that let us specify the
interoperability capabilities of the implemented software. The European Telecommuni-
cations Standards Institute (ETSI) CoAP Plugtests [17] are specifications for interoper-
ability tests previously conducted within the community of CoAP developers. They are
both valuable for testing the CoAP and Rack interoperability. It is possible to analyze
the following questions utilizing implementations of this test specifications. However,
67
7.2. Benchmarking
some of the test cases are not compatible to the specifications of the latest CoAP version
[RFC 7252]. TD COAP CORE 11 for example demands a missing token option on a re-
sponse. Others are not specified detailed enough. TD COAP CORE 13 for example does
not require the server to actually handle the URI-Query options.
Data for answering these questions is gained by means of implementing the Plugtests
as RSpec tests. Most Plugtests have been implemented, but not all. We had to concen-
trate on the tests for the most important aspects regarding to the research questions.
Currently, only the CoAP protocol tests 1-13 (without 9) are implemented (see section
7.1 of [17]). TD COAP CORE 09 is not implemented, because the server does not sup-
port separate responses. From the optional test case set we implemented the block-wise
transfers tests TD COAP BLOCK 01 and TD COAP BLOCK 02 as well as the first three ob-
serve tests. Block-wise transfers with PUT and POST are not supported by the server and
therefore also not tested (ETSI Plugtests TD COAP BLOCK 03 and TD COAP BLOCK 04).
The same applies to server observe deregistration detection (tests TD COAP OBS 04 and
TD COAP OBS 05).
The automatic provisioning of the Resource Discovery only works with Rails.
Therefore the Plugtests regarding to the CoRE Link Format were omited for this
test series. Tests similar to the CoRE Link Format test cases have been imple-
mented before the evaluation phase as unit and integration tests (see for example
spec/resource discovery spec.rb in the david repository). We tested different
Rails applications enabling the automatic provisioning of Resource Discovery with the
CoAP crawler client on http://coap.me and there was no indication of problems in
the RD middleware implementation. Tested applications were the dummy used for
automatic testing of David (see spec/dummy), the core-rd application, and a prototype
Rails application used for the development of David. The interoperability of the RD
application is not tested as we could not find any RD client implementation or test cases.
68
7.2. Benchmarking
Features
During the implementation of the Plugtests, test cases occured that are impossible to
be realized because of lacking server support for certain features. All of those short-
comings were already known. Separate responses (see section 5.2.2 of [RFC 7252] and
test TD COAP CORE 09 of [17]) are one example. Another one is the lack of support
for block-wise transfers for incoming messages (see ETSI Plugtests TD COAP BLOCK 03
and TD COAP BLOCK 04). The token generation of the client library has been revised
during the implementation of the test TD COAP CORE 11. We also found regressions
in the server implementation regarding to the support for block-wise transfers and ob-
serve. As the Rails application is used solely as an API, we removed all stylesheet or
JavaScript asset related gems and paths from the source tree.
Rack
We implemented the Client side of the Plugtests as RSpec tests and the server side with
means of different Rack based web frameworks. A list of the tested frameworks and
their versions is shown in Table 7.1. Table 3.1 contains an exhaustive list of frameworks
and their download locations. The framework specific applications are to be found in
the lib/david/etsi folder of the david repository.
Framework Version
Grape 0.10.1
Hobbit 0.6.0
NYNY 2.2.1
Pure Rack
Sinatra 1.4.5
Ruby on Rails 4.2.0
When designing the HTTP status code mappings and explicitly returning a CoAP
response code by using a Float, #to i was not called on the status. At the time of Rack
interface interoperability testing, it became obvious that returning Float status codes
does not work anymore from any framework. So two changes were made to the server
code. First it is possible that CoAP response codes are used in the style of HTTP response
codes (for example 205 meaning CoAP 2.05. However, with the designed mapping in
place, 204 for example would be interpreted as HTTP 204 No Content and mapped to
69
7.2. Benchmarking
CoAP 2.05 Content. Therefore, a possibility to configure the status code mapping as
minimal as possible was implemented. Currently only HTTP 200 OK maps to CoAP 2.05
Content in this mode. The Rack environment option MinimalMapping can be set to true
to activate the minimal mapping. The second change affects the method in Rack code
that calls #to i on the status returned by the framework. This method was monkey-
patched to omit calling #to i on the status if it is an instance of the Float class. Grape
and Sinatra call #to i on the status by themselves. Grape uses Rack::Request, which
calls #to i on initialization and in the Sinatra code it is called in different places. With
these frameworks CoAP response codes as Integers have to be used for now. Wrapping
the status in a CoAP status object instance is not a trivial solution. The response code 205
for example in HTTP means Reset Content and results in clearing the body and headers
in Grape. The wrapper object would have to actually return an Integer on call of #to i.
Code like status = status.to i (like in Rack::Response) would erase the CoAP
response code information. Out of the tested frameworks, only Hobbit, Pure Rack and
Rails support the CoAP response codes as Floats.
CoAP
We conduct the Plugtests with different client implementations in connection with the
David server hosting the Rack Plugtests applications (see mandatory/rack.rb and
optional/rack.rb in the lib/david/etsi directory). Table 7.2 shows the differ-
ent clients tested, their respective versions and websites. Californium and jcoap already
provide a Plugtests client. libcoap ships with a flexible Command Line Interface (CLI)
utility that can be used from within scripts. The Ruby coap gem is not listed here, be-
cause it is already tested on protocol interoperability in connection with the Rack inter-
face interoperability tests (see section 7.2.2).
For an extensive summary of the test results, see Table 7.3. All chosen Plugtests pass
with the cf-plugtest-checker component of Californium except two observe tests. A manual
test series with Copper yielded in positive results for all tests. libcoap was also tested man-
70
7.2. Benchmarking
ually with the coap-client utility (see examples/client.c). In some test cases options
had to be passed on the command line manually with the -O switch. TD COAP OBS 02
(which tests observe deregistration) is an example. The interoperability of the transpar-
ent Resource Discovery was manually tested with Copper without strictly following the
Plugtests.
71
72
7.2. Benchmarking
7.2.3. Reflection
Performance
The throughput of JRuby is not much higher than of MRI. This can be explained by
the handling of messages in a single threaded event loop. To use the full potential of
JRuby, probably a thread pool for message handling could be beneficial. With Celluloid,
the supervision of one actor or a pool of actors is quite similar. It should be possible to
change the source code of David so that it can better utilize the multithreading capabil-
ities of JRuby. In general, the message loss is higher with Rails than with Rack. This is
probably due to the bigger framework overhead inside the event loop. In a Ruby VMs
such as JRuby, the performance could possibly be increased by using a thread pool for
framework answers or even message parsing.
As we expected, the throughput of David lags behind the throughput of Californium.
We did not verify the measurements by running the bechmarks for Californium on our
own hardware, because Matthias Kovatsch conducted performance tests for his disser-
tation on quite a similar CPU (see section 4.4.2 of [24]). Californium handles a throughput
of about 40,000 RPS on a single core and up until 135,000 RPS on four cores. Comparing
the single core throughput, our Ruby solution reaches about one third of the throughput
of Californium (2.86 times slower).
Interoperability
There were no tested features not possible to be implemented in the Rack applications.
The Rack interface therefore seems to suffice the characteristics of CoAP and its exten-
sions. All tested Rack compatible web frameworks pass the interoperability tests. The
usage of Floats to explicitly return CoAP status is as beforehand mentioned the only
problem to be respected in this context. Although the implemented server lacks some
features and the respective interoperability tests with external clients had to be omited,
the majority of the actually conducted tests were positive.
The feedback of developers taking an interest in a CoAP server with a Rack interface
would provide valuable information for example on usability and bugs of the software
created during this work. We tried getting feedback by announcing it publicly on related
mailing lists and by conducting an observation of a developer trying to solve a task
chosen by himself.
73
7.3. Developer Feedback
We wrote a basic development centric README file for David (see README.md for the
0.4.0 release9 ) as a central pragmatic documentation. The text covers the most important
aspects of usage and information like configuration options. Afterwards we posted an
announcement of David with a short description to [email protected]
and [email protected] as well as a link to the GitHub repository in the
ruby subreddit (see subsection B.3.1). There were neither direct answers to the mail
posted on the mailing lists nor to the reddit posting. However, GitHub shows a slightly
increased traffic to the repository on the days after posting10 . At the time of the work
the only explicit response to this announcement is a bug report11 and five GitHub users
marking the repository as a favorite. The coap repository also has five stargazers. One
user reported a bug regarding to the initialization of multicast communications on OS
X. The bug could not be reproduced in a VM running Mac OS X 10.9.5 but was fairly
straight forward to fix, anyway.
To gain data regarding to the usability of David for Ruby programmers and to find bugs,
an observation of a programmer familiar with Rails and the basics of CoAP developing
a self-chosen prototype application has been conducted. We only intervened with spe-
cific directions when the process got stuck. The projects README file was the main
documentation source. A detailed log of the experiment resides in subsection B.3.2. We
will concentrate on the results here. As we only observed a single developer once and
without a reproducable task, we do not claim a statistically significant statement by the
experiment but an approach to get feedback.
The test subject started with reading the David README and decided on implement-
ing a basic Rails application returning JSON data possibly transcoded into CBOR. Dur-
ing the process of realization, some issues with the documentation and usage arose and
some bugs in the server software occured. The documentation at the point of the experi-
ment lacked especially introductory passages for users without advanced knowledge of
Rack and CoAP. The most important issues with the code arosen during the observation
are as follows.
1. At the time of the experiment, David does not cache a framework answer even
9 https://github.com/nning/david/blob/0.4.0/README.md
10 https://github.com/nning/david/graphs/traffic
11 https://github.com/nning/david/issues/1
74
7.3. Developer Feedback
3. Outgoing JSON/CBOR transcoding did not work at the time of the experiment,
because it broke earlier in a way not covered by the unit tests. This was fixed right
away.
4. With activated transcoding and the Accept option of a request set to applica-
tion/cbor (60), a CoAP 4.06 Not Acceptable is responded by the framework, because
it the transcoding is transparent. I case of an activated transcoding also headers
like the Accept header have to be rewritten.
The test subject explicitly stated that the server works well as a drop-in replacement
even without advanced knowledge of CoAP specifics.
75
Chapter 8
Conclusion
The following subsection lists our accomplishments and the deficiencies of our imple-
mentation for each research question.
We iteratively designed and developed the protocol handling for a CoAP server. Op-
posed to our previous estimations, we did not depend on larger parts of a shared li-
brary for the CoAP transmission layer but only for message parsing and assembly. The
implementation makes use of Message Deduplication to lower the waste of server re-
sources through retransmitted confirmable messages. Resource representations are re-
questable utilizing Block-wise transfers. Our client interoperability evaluation showed
a very good protocol interoperability, although we would favor a more polished CoAP
transmission implementation that supports separate responses, confirmable messages
initiated by the server, and incoming Block-wise Transfers. A structure comparable to
Racks middleware stack for different protocol layers would probably have improved
code modularity and quality.
Message handling was implemented utilizing a single threaded, non blocking event
loop as a model providing a good balance between performance and Ruby VM inter-
operability. In the performance evaluations, our realization of this model yielded a
message throughput almost three times higher than previously anticipated. Also, our
server has almost twice the throughput as Ruby HTTP servers running on MRI. How-
ever, further performance optimizations that make closer use of the different Ruby VM
characteristics would be desirable.
77
8.1. Recapitulation of Results
How can a later integration of transport encryption with DTLS [RFC 6347] be
supported?
We provide a basic interface for a DTLS integration and means to pass details of the
encrypted connection to the Rack middleware stack and the application.
According to our design, the server transparently translates CoAP requests into Rack
environments and Rack application responses into CoAP responses. The framework
and client interoperability tests showed that this translation works well. Only the ex-
plicit returning of CoAP response codes, while a status code mapping from HTTP to
CoAP is activated, keeps to be somewhat cumbersome. We also did not implement all
possible translations as Conditional Request Options for example (see section 5.10.8 of
[RFC 7252]).
78
8.2. Perspectives
The RD and Lookup Funtion Sets of the RD draft [core-resource-directory-02] have been
implemented as a Rails application by us. The development process showed that our
solution is compatible to the specifications of that draft and that TDD with RSpec works
for CoAP application development with Rails. However, the Group Function Set is not
supported yet. The Lookup Function Set was only implemented for resource lookup.
8.2. Perspectives
79
8.2. Perspectives
dent of CoAP. The possibility to activate transcodings for single controllers or actions
would be a useful feature. As the autodetection of resources for the Resource Discov-
ery currently only works with Rails, compatiblity to other Rack compatible frameworks
would be an improvement. As mentioned before, the RD application and the observe
implementation are also providing some possibilities to be further improved. We will
further develop and maintain the open source projects started during this work and
probably try to get other people involved. That includes the Ruby CoAP library for
which also numerous improvements are possible.
Beyond the concrete implementation created during this work, there are some possi-
ble applications of parts of our design in the context of other CoAP servers. We would
like to see solutions for hosting IoT web applications developed in Ruby comparable
to nginx1 and Phusion Passenger2 for example as well as CoAP servers compatible to
web frameworks written in programming languages optimized for concurrency such as
elixir3 for example.
1 http://nginx.org
2 https://www.phusionpassenger.com
3 http://elixir-lang.org
80
Appendix A
Guides
It is assumed that a recent version of Ruby is installed. At the time of writing, Ruby
2.2.0 is the latest stable version released. Documentation about how to install Ruby on
different OSs can be obtained from the official Ruby website1 .
In case a new Rails application is to be used, it is created with the following command.
1 rails new example
David will automatically hook into Rails to make itself the default Rack handler so that
rails s starts David by default. If the application has to be used via HTTP, WEBrick
can be started by executing rails s webrick. After the server is started, the Rails
application is available at coap://[::1]:3000/ by default.
Copper is a CoAP client for Firefox and can be used for development. The Ruby coap
gem is used by David for example for message parsing and also includes a command
line utility (named coap) that can also be used for development.
As CoAP is a protocol for constrained environments and machine to machine commu-
nications, returning HTML from controllers will not be of much use. JSON for example
is more suitable in that context. David works well with the default ways to handle JSON
responses from controllers such as render json:. You can also utilize Jbuilder tem-
plates for easy generation of more complex JSON structures.
CBOR [RFC 7049] can be used to compress JSON documents. Automatic transcoding
between JSON and CBOR is activated by setting the Rack environment option CBOR or
config.coap.cbor in your Rails application config to true.
1 https://www.ruby-lang.org/en/documentation/installation/
81
A.2. Running the Resource Directory (RD)
Generate a secret token for the production environment. It has to be pasted in the
production section of config/secrets.yml.
1 rake secret
82
Appendix B
Figure B.1, B.2, and B.3 were kept out of subsection 7.2.1, because they do not add sig-
nificant information to the analysis. They are included in the appendix for the sake of
completeness.
83
B.1. Additional Performance Benchmark Plots
Percentage of lost messages
Ruby VM
6
mri22
mri23
jruby17
jruby9
84
B.1. Additional Performance Benchmark Plots
11000
10000
Requests per second
9000
Framework
Rack
8000 Rails
7000
6000
5000
85
B.2. Performance Benchmark on Ubiquiti EdgeMAX Lite
12000
11000
10000
9000
Requests per second
8000
Framework
7000 Rack
Rails
6000
5000
4000
3000
2000
Firmware Update
Reset
86
B.2. Performance Benchmark on Ubiquiti EdgeMAX Lite
Web Interface
After the reset the router has the IP address 192.168.1.1 on the first ethernet inter-
face. Both login and password for the webinterface is ubnt. The performed configura-
tion steps are:
Software Repositories
Install Packages
The installation of git and essential tools to compile gems written in C is accomplished
with the following command. We install gcc 4.9.1 from testing, because version 1.8.2 of
the the json gem needs the fstack-protector-strong option and it is not supported
in gcc 4.6.3. Also we could not get the cbor gem compiling in gcc 4.6.3 on mips.
87
B.2. Performance Benchmark on Ubiquiti EdgeMAX Lite
Ruby has to be installed from testing (Ruby 2.1.5p273 and rubygems 2.2.2). Although
it would be possible to use Ruby 1.9.3p194 from stable, the VM segfaulted (only on MIPS)
in connection to Celluloid. We could not get newer versions of Ruby building with rbenv
on this platform.
1 apt-get -y -t testing install ruby ruby2.1 ruby2.1-dev
To clone the code, issue the following commands. This guide was tested at commit
529c73c.
1 cd /srv
2 git clone https://github.com/nning/david.git
3 cd david
Generating documentation for each installed gem can be turned of with some config-
uration in /.gemrc.
1 cat > /.gemrc <<EOF
2 install: --no-rdoc --no-ri
3 update: --no-rdoc --no-ri
4 EOF
The dependencies minimally necessary for production use are installed with bundler.
1 gem install bundler
2 cd benchmarks/rackup
3 bundle --without grape rails
88
B.3. Developer Feedback
The server is started with the performance benchmark Rack application as follows.
1 rackup rack.ru
At this stage, the Ruby VM unfortunately segfaulted in connection with the timers
gem used by Celluloid.
JRuby as an Alternative
We tried to get the performance benchmark setup running in JRuby. JRuby 1.5.6 is avail-
able in the package repositories of Debian wheezy. That version is from 2010 and was
previously untested with David. In theory the following shell commands should install
JRuby and its dependencies, and start the Rack performance benchmark application af-
ter installing its dependencies. As with MRI, we could not get the application running.
The command installing the bundler gem (see line 2 of the shell commands below) uti-
lizes the CPU at 100% and seemed to be hanging without ever finishing only to result
in a java.lang.ArrayIndexOutOfBoundsException.
1 apt-get install -y default-jre-headless jruby
2 jruby -S gem install bundler
3 cd /srv/david/benchmarks/rackup
4 jruby -S bundle --without grape rails
5 jruby -S rackup rack.ru
On the 5th of February 2015, we announced David to the Rack development mail-
ing list [email protected] and posted a link to the GitHub reposi-
tory to the ruby subreddit2 . Listing B.3 depicts the original mail posted to that list.
On the next day, we also posted this text to the public Rails discussion mailing list
[email protected] .
1 https://groups.google.com/forum/#!topic/rack-devel/vKy9eaoiLxI
2 https://www.reddit.com/r/ruby/comments/2uvk6n/a_coap_server_with_a_rack_
interface_for_use_of/
3 https://groups.google.com/forum/#!topic/rubyonrails-talk/5m8ex-oGQvs
89
B.3. Developer Feedback
90
B.3. Developer Feedback
We asked Ingo Becker, a programmer with a background in web application and mi-
crocontroller development to try realizing a prototype CoAP application with Rails and
David. He is familiar with the former and knows the basics of CoAP. He was working
on his own notebook and we tried to only intervene minimally, taking notes about the
procedure and problems. When the process got stuck, we helped with specific direc-
tions. As quite usual in the Rails world, he mostly relied on the README file from the
GitHub repository4 for documentation. The following list contains the raw notes from
the observation. Sentences in square brackets are annotations and associations of the
observer. Serious issues are in bold font.
[Rails 4.1.6 pre-installed. rails new foo created Rails 4.1.6 application.
Adding gem david and executing bundle update (without --without
test) also installs Rails 4.2.0.]
Include hint to render json: and the responders gem before the notes on
Jbuilder.
Introduction how to use Rack options with rails s (or maybe also rackup.
Output of CoAP URI for copy and pasting after David startup.
91
B.3. Developer Feedback
README should include hints for starting server in a way, the actual messages
can be examined [with debug log level].
[Maybe include a generator that patches for example config.ru to start on port
5683/udp.]
If David calls the Rack application for every block of a response representation,
what happens if payload changes in between a block-wise transaction? [The
ETag option is changed and the client can try to obtain the full representation,
again.]
[Adds route to index action of exemplary controller and renders minimal static
JSON document with a Jbuilder template.]
[Starts rails s webrick to test routing, because log output with block-wise
transfers of an exception message is confusing. Examines HTTP headers. Starts
CoAP server.]
[Talking about debug log level. Starts server with rackup to specify log level.]
Known bug: With rackup in development mode, Rails answers chunked but
David does not reassemble the chunks before responding via CoAP.
Bug: Outgoing transcoding does not work; JSON is responded. [Fixed directly
and switched from David 0.4.0 to master.]
README should state that choosing a bigger block size in client creates less noise
in server log when debugging.
92
B.3. Developer Feedback
States, the server is working well as a drop-in replacement even without advanced
knowledge of CoAP.
93
List of Figures
95
List of Tables
97
Acronyms
CI Continuous Integration
99
GIL Global Interpreter Lock
M2M Machine-to-Machine
MVC Model-View-Controller
OS Operating System
RD Resource Directory
100
TCP Transmission Control Protocol
VM Virtual Machine
WG Working Group
101
Bibliography
103
Bibliography
104
Bibliography
105
Bibliography
106
Bibliography
107
Bibliography
108
Bibliography
109
Bibliography
110
Bibliography
111
Acknowledgements
First of all, I would like to thank my supervisors Prof. Dr.-Ing. Carsten Bormann, Dr.-
Ing. Olaf Bergmann, and Dipl.-Inf. Florian Junge for their support during the work on
this document. Especially Carsten Bormann helped me with numerous suggestions and
ideas.
Furthermore, I thank my parents who allowed me to conduct my studies and my
girlfriend Ann-Kathrin Seiz for her endless support. Special thanks go to Jorin for being
quite a motivation! Ingo Becker helped me with early reviews, discussions and the devel-
oper evaluation. Heiko Westermann and Ruben Schuller reviewed this document. Thanks
guys! Special appreciation is also advisable towards foo@ which was always there for
weird leisure time.
113