Implemented event reporting to settings daemon clients.
[profile/ivi/settings-daemon.git] / src / websocket_server.cpp
1 /**
2  * @file websocket_server.cpp
3  *
4  * @brief Settings daemon WebSocket server source.
5  *
6  * @author Ossama Othman @<ossama.othman@@intel.com@>
7  *
8  * @copyright @par
9  * Copyright 2013 Intel Corporation All Rights Reserved.
10  * @par
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation;
14  * version 2.1 of the License.
15  * @par
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  * @par
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
24  * Boston, MA  02110-1301  USA
25  */
26
27 #include "websocket_server.hpp"
28 #include "configurator.hpp"
29 #include "../lib/config.hpp"
30 #include "../lib/manager.hpp"
31
32 #include <stdexcept>
33 #include <thread>
34
35
36 namespace
37 {
38   // --------------------------------------------------------------------
39   // libwebsockets callbacks and related data.
40   // --------------------------------------------------------------------
41
42   int
43   callback_ivi_settings(libwebsocket_context * context,
44                         libwebsocket * wsi,
45                         enum libwebsocket_callback_reasons reason,
46                         void * /* user */,
47                         void * in,
48                         size_t /* len */)
49   {
50     using namespace ivi::settings;
51
52     manager * const mgr = static_cast<manager *>(
53         libwebsocket_context_user(context));
54
55     switch(reason) {
56     case LWS_CALLBACK_ESTABLISHED:
57       // Enable event dispatching to client.
58       mgr->subscribe_client(wsi);
59       break;
60
61     case LWS_CALLBACK_CLOSED:
62       // Disable event dispatching to client.
63       mgr->unsubscribe_client(wsi);
64       break;
65
66     case LWS_CALLBACK_RECEIVE:
67       // Request has come in from Settings app.  Pass it on to the
68       // settings manager.
69       mgr->dispatch(static_cast<char const *>(in), wsi);
70       break;
71
72     default:
73       break;
74     }
75
76     return 0;
77   }
78
79   struct ws_session_data_type
80   {
81   };
82
83   libwebsocket_protocols settings_protocols[] = {
84     {
85       "http-only",//"ivi-settings-protocol",
86       callback_ivi_settings,
87       sizeof(ws_session_data_type),
88       0,
89       nullptr,
90       0
91     },
92     {
93       nullptr,
94       nullptr,
95       0,
96       0,
97       nullptr,
98       0
99     }
100   };
101
102 }
103
104 // ----------------------------------------------------------------------
105
106 ivi::settings::websocket_server::websocket_server(
107   ivi::settings::configurator const & config,
108   ivi::settings::manager & mgr)
109   : context_(nullptr)
110 {
111   lws_context_creation_info info;
112   info.port  = config.websocket_port();
113   info.iface = "lo";  // Only allow communication over the loopback
114                       // interface.
115
116   info.protocols  = settings_protocols;
117   info.extensions = libwebsocket_get_internal_extensions();
118
119   info.ssl_cert_filepath        = config.ssl_cert_file();
120   info.ssl_private_key_filepath = config.ssl_private_key_file();
121   info.ssl_ca_filepath          = config.ssl_ca_file();
122   info.ssl_cipher_list          = nullptr;
123
124   info.gid = -1;
125   info.uid = -1;
126
127   info.options = 0;
128
129   info.user = &mgr;
130
131   info.ka_time     = 0;
132   info.ka_probes   = 0;
133   info.ka_interval = 0;
134
135   lws_set_log_level(LLL_INFO, lwsl_emit_syslog);
136
137   context_ = libwebsocket_create_context(&info);
138   if (context_ == nullptr)
139     throw std::runtime_error("Unable to initialize websocket.\n");
140
141   std::cout << "\n" PACKAGE_NAME " listening for requests on port "
142             << info.port << ".\n";
143 }
144
145 ivi::settings::websocket_server::~websocket_server()
146 {
147   libwebsocket_context_destroy(context_);
148 }
149
150 void
151 ivi::settings::websocket_server::run()
152 {
153   // Run the websocket event loop in its own thread.
154   std::thread(
155     [](libwebsocket_context * context){
156       try {
157         // Run the libwebsockets event loop with an infinite timeout.
158         // The negative timeout causes the underlying call poll() to
159         // block indefinitely until an event occurs.
160         constexpr int const timeout = -1;
161         while (libwebsocket_service(context, timeout) >= 0) {
162         }
163
164         std::cerr << "WebSocket event loop ended.\n";
165       } catch(std::exception & e) {
166         std::cerr << e.what() << std::endl;
167       }
168     },
169     context_).detach();
170 }
171
172
173 /**
174  * @todo Add 'state' event do determine whether technology is
175  *       enabled/disabled.
176  */
177
178 // Local Variables:
179 // mode:c++
180 // c-basic-offset:2
181 // indent-tabs-mode: nil
182 // End: