Skip to content

Commit 0e4b5e0

Browse files
committed
Added IncludeOS websockets sample source code
1 parent 9d6e59c commit 0e4b5e0

File tree

7 files changed

+254
-0
lines changed

7 files changed

+254
-0
lines changed

includeos/CMakeLists.txt

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
cmake_minimum_required(VERSION 2.8.9)
2+
3+
# IncludeOS install location
4+
if (NOT DEFINED ENV{INCLUDEOS_PREFIX})
5+
set(ENV{INCLUDEOS_PREFIX} /usr/local)
6+
endif()
7+
include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake)
8+
9+
project (ws_example)
10+
11+
# Human-readable name of your service
12+
set(SERVICE_NAME "IncludeOS WebSocket Example")
13+
14+
# Name of your service binary
15+
set(BINARY "ws_example")
16+
17+
# Source files to be linked with OS library parts to form bootable image
18+
set(SOURCES
19+
service.cpp # ...add more here
20+
)
21+
22+
#
23+
# Service CMake options
24+
# (uncomment to enable)
25+
#
26+
27+
# MISC:
28+
29+
# To add your own include paths:
30+
# set(LOCAL_INCLUDES ".")
31+
32+
# Adding memdisk (expects my.disk to exist in current dir):
33+
# set(MEMDISK ${CMAKE_SOURCE_DIR}/my.disk)
34+
35+
# DRIVERS / PLUGINS:
36+
37+
if ("$ENV{PLATFORM}" STREQUAL "x86_solo5")
38+
set(DRIVERS
39+
solo5net
40+
)
41+
else()
42+
set(DRIVERS
43+
virtionet # Virtio networking
44+
)
45+
endif()
46+
47+
set(PLUGINS
48+
autoconf
49+
)
50+
51+
# include service build script
52+
include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake)
53+
54+
diskbuilder(disk)

includeos/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# IncludeOS WebSocket Example
2+
3+
Start with `boot . --create-bridge` and visit [http://10.0.0.42](http://10.0.0.42) from a browser that supports WebSocket.
4+
5+
This service demonstrates websocket, and utilizes memdisk, autoconf and http server.

includeos/config.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"net": [
3+
{
4+
"iface": 0,
5+
"config": "static",
6+
"address": "10.0.0.42",
7+
"netmask": "255.255.255.0",
8+
"gateway": "10.0.0.1"
9+
}
10+
]
11+
}
12+
13+

includeos/disk/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The `index.html` is based on the template code found at [https://www.websocket.org/echo.html](https://www.websocket.org/echo.html).

includeos/disk/index.html

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!DOCTYPE html>
2+
<meta charset="utf-8" />
3+
<title>IncludeOS WebSocket Example</title>
4+
<link href="https://fonts.googleapis.com/css?family=Ubuntu:500,300" rel="stylesheet" type="text/css">
5+
<script language="javascript" type="text/javascript">
6+
7+
var wsUri = "ws://10.0.0.42/ws";
8+
var output;
9+
10+
function init()
11+
{
12+
output = document.getElementById("output");
13+
testWebSocket();
14+
}
15+
16+
function testWebSocket()
17+
{
18+
websocket = new WebSocket(wsUri);
19+
websocket.onopen = function(evt) { onOpen(evt) };
20+
websocket.onclose = function(evt) { onClose(evt) };
21+
websocket.onmessage = function(evt) { onMessage(evt) };
22+
websocket.onerror = function(evt) { onError(evt) };
23+
}
24+
25+
function onOpen(evt)
26+
{
27+
writeToScreen("CONNECTED");
28+
}
29+
30+
function onClose(evt)
31+
{
32+
writeToScreen("DISCONNECTED");
33+
}
34+
35+
function onMessage(evt)
36+
{
37+
writeToScreen('&lt; <span style="color: blue;">' + evt.data+'</span>');
38+
}
39+
40+
function onError(evt)
41+
{
42+
writeToScreen('<span style="color: red;">!:</span> ' + evt.data);
43+
}
44+
45+
function doSend(message)
46+
{
47+
writeToScreen('&gt; <span style="color: green;">' + message+'</span>');
48+
websocket.send(message);
49+
}
50+
51+
function sendMessage()
52+
{
53+
doSend(document.getElementById("message").value);
54+
}
55+
56+
function writeToScreen(message)
57+
{
58+
var pre = document.createElement("p");
59+
pre.style.wordWrap = "break-word";
60+
pre.innerHTML = message;
61+
output.appendChild(pre);
62+
}
63+
64+
function closeWs()
65+
{
66+
websocket.close();
67+
}
68+
69+
window.addEventListener("load", init, false);
70+
71+
</script>
72+
73+
<h1 style="font-family: Arial, sans-serif">
74+
Include<span style='font-weight: lighter'>OS</span>
75+
</h1>
76+
<hr />
77+
<h2>WebSocket Echo</h2>
78+
<input type="text" id="message"/>
79+
<button type="submit" onclick="sendMessage()">Send</button>
80+
<button type="submit" onclick="closeWs()">Close</button>
81+
82+
<div id="output"></div>

includeos/service.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// This file is a part of the IncludeOS unikernel - www.includeos.org
2+
//
3+
// Copyright 2017 Oslo and Akershus University College of Applied Sciences
4+
// and Alfred Bratterud
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
18+
#include <net/inet4>
19+
#include <service>
20+
21+
#include <net/ws/websocket.hpp>
22+
void handle_ws(net::WebSocket_ptr ws)
23+
{
24+
static std::map<int, net::WebSocket_ptr> websockets;
25+
static int idx = 0;
26+
27+
// nullptr means the WS attempt failed
28+
if(not ws) {
29+
printf("WS failed\n");
30+
return;
31+
}
32+
printf("WS Connected: %s\n", ws->to_string().c_str());
33+
34+
// Write a welcome message
35+
ws->write("Welcome");
36+
ws->write(ws->to_string());
37+
// Setup echo reply
38+
ws->on_read = [ws = ws.get()](auto msg) {
39+
auto str = msg->as_text();
40+
printf("WS Recv: %s\n", str.c_str());
41+
ws->write(str);
42+
};
43+
44+
websockets[idx] = std::move(ws);
45+
// Notify on close
46+
websockets[idx]->on_close = [key = idx](auto code) {
47+
printf("WS Closing (%u) %s\n", code, websockets[key]->to_string().c_str());
48+
};
49+
idx++;
50+
}
51+
52+
#include <net/http/server.hpp>
53+
#include <memdisk>
54+
std::unique_ptr<http::Server> server;
55+
56+
void Service::start()
57+
{
58+
// Retreive the stack (configured from outside)
59+
auto& inet = net::Inet4::stack<0>();
60+
Expects(inet.is_configured());
61+
62+
// Init the memdisk
63+
auto& disk = fs::memdisk();
64+
disk.init_fs([] (auto err, auto&) {
65+
Expects(not err);
66+
});
67+
// Retreive the HTML page from the disk
68+
auto file = disk.fs().read_file("/index.html");
69+
Expects(file.is_valid());
70+
Chunk html{file.data(), file.size()};
71+
72+
// Create a HTTP Server and setup request handling
73+
server = std::make_unique<http::Server>(inet.tcp());
74+
server->on_request([html] (auto req, auto rw)
75+
{
76+
// We only support get
77+
if(req->method() != http::GET) {
78+
rw->write_header(http::Not_Found);
79+
return;
80+
}
81+
// Serve HTML on /
82+
if(req->uri() == "/") {
83+
rw->write(html);
84+
}
85+
// WebSockets go here
86+
else if(req->uri() == "/ws") {
87+
auto ws = net::WebSocket::upgrade(*req, *rw);
88+
handle_ws(std::move(ws));
89+
}
90+
else {
91+
rw->write_header(http::Not_Found);
92+
}
93+
});
94+
95+
// Start listening on port 80
96+
server->listen(80);
97+
}

stop_and_remove_docker.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
docker stop websockets_benchmark
2+
docker rm websockets_benchmark

0 commit comments

Comments
 (0)