blob: ce7dafad0b78f21a7ed4e51db52f0fcee25a3415 [file] [log] [blame]
Tomas Cejkad340dbf2013-03-24 20:36:57 +01001/*
2 * libwebsockets-test-server - libwebsockets test implementation
3 *
4 * Copyright (C) 2010-2011 Andy Green <andy@warmcat.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation:
9 * version 2.1 of the License.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21#include <stdio.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <getopt.h>
25#include <string.h>
26#include <sys/time.h>
27#include <sys/stat.h>
Tomas Cejkaba21b382013-04-13 02:37:32 +020028#include <sys/queue.h>
Tomas Cejkad340dbf2013-03-24 20:36:57 +010029#include <fcntl.h>
Tomas Cejkaba21b382013-04-13 02:37:32 +020030#include <pthread.h>
Michal Vaskoc3146782015-11-04 14:46:41 +010031#include <errno.h>
Michal Vaskof35ea502016-02-24 10:44:54 +010032#include <nc_client.h>
Tomas Cejkaba21b382013-04-13 02:37:32 +020033#include <libwebsockets.h>
Michal Vaskoc3146782015-11-04 14:46:41 +010034
Michal Vaskoa53ef882015-11-24 11:02:01 +010035#include "notification_server.h"
36#include "netopeerguid.h"
Michal Vaskoc3146782015-11-04 14:46:41 +010037#include "../config.h"
Tomas Cejkad340dbf2013-03-24 20:36:57 +010038
Michal Vaskoc3146782015-11-04 14:46:41 +010039#ifdef TEST_NOTIFICATION_SERVER
Tomas Cejkaba21b382013-04-13 02:37:32 +020040static int force_exit = 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +010041#endif
42
43#if defined(TEST_NOTIFICATION_SERVER) || defined(WITH_NOTIFICATIONS)
Tomas Cejkad340dbf2013-03-24 20:36:57 +010044static int max_poll_elements;
45
46static struct pollfd *pollfds;
47static int *fd_lookup;
48static int count_pollfds;
Tomas Cejkad340dbf2013-03-24 20:36:57 +010049static struct libwebsocket_context *context = NULL;
Tomas Cejkad340dbf2013-03-24 20:36:57 +010050
Michal Vaskoc3146782015-11-04 14:46:41 +010051extern struct session_with_mutex *netconf_sessions_list;
Tomas Cejkaba21b382013-04-13 02:37:32 +020052static pthread_key_t thread_key;
53
Tomas Cejkad340dbf2013-03-24 20:36:57 +010054/*
55 * This demo server shows how to use libwebsockets for one or more
56 * websocket protocols in the same server
57 *
58 * It defines the following websocket protocols:
59 *
60 * dumb-increment-protocol: once the socket is opened, an incrementing
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020061 * ascii string is sent down it every 50ms.
62 * If you send "reset\n" on the websocket, then
63 * the incrementing number is reset to 0.
Tomas Cejkad340dbf2013-03-24 20:36:57 +010064 *
65 * lws-mirror-protocol: copies any received packet to every connection also
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020066 * using this protocol, including the sender
Tomas Cejkad340dbf2013-03-24 20:36:57 +010067 */
68
69enum demo_protocols {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020070 /* always first */
71 PROTOCOL_HTTP = 0,
Tomas Cejkad340dbf2013-03-24 20:36:57 +010072
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020073 PROTOCOL_NOTIFICATION,
Tomas Cejkad340dbf2013-03-24 20:36:57 +010074
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020075 /* always last */
76 DEMO_PROTOCOL_COUNT
Tomas Cejkad340dbf2013-03-24 20:36:57 +010077};
78
79
80#define LOCAL_RESOURCE_PATH "."
81char *resource_path = LOCAL_RESOURCE_PATH;
82
83/*
84 * We take a strict whitelist approach to stop ../ attacks
85 */
86
87struct serveable {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020088 const char *urlpath;
89 const char *mimetype;
Tomas Cejka15c56302013-05-30 01:11:30 +020090};
Tomas Cejkad340dbf2013-03-24 20:36:57 +010091
92static const struct serveable whitelist[] = {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020093 { "/favicon.ico", "image/x-icon" },
94 { "/libwebsockets.org-logo.png", "image/png" },
Tomas Cejkad340dbf2013-03-24 20:36:57 +010095
Michal Vaskofcc9a9c2016-05-06 11:51:35 +020096 /* last one is the default served if no match */
97 { "/test.html", "text/html" },
Tomas Cejkad340dbf2013-03-24 20:36:57 +010098};
99
100struct per_session_data__http {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200101 int fd;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100102};
103
104/* this protocol server (always the first one) just knows how to do HTTP */
105
106static int callback_http(struct libwebsocket_context *context,
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200107 struct libwebsocket *wsi,
108 enum libwebsocket_callback_reasons reason, void *user,
109 void *in, size_t UNUSED(len))
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100110{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200111 char client_name[128];
112 char client_ip[128];
113 char buf[256];
114 int n, m;
115 static unsigned char buffer[4096];
116 struct per_session_data__http *pss = (struct per_session_data__http *)user;
117 struct libwebsocket_pollargs *pa = (struct libwebsocket_pollargs *) in;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100118
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200119 switch (reason) {
120 case LWS_CALLBACK_HTTP:
121 for (n = 0; n < (signed) (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
122 if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0)
123 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100124
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200125 sprintf(buf, "%s%s", resource_path, whitelist[n].urlpath);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100126
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200127 if (libwebsockets_serve_http_file(context, wsi, buf, whitelist[n].mimetype, NULL, 0))
128 return -1; /* through completion or error, close the socket */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100129
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200130 /*
131 * notice that the sending of the file completes asynchronously,
132 * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
133 * it's done
134 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100135
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200136 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100137
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200138 case LWS_CALLBACK_HTTP_FILE_COMPLETION:
139// lwsl_info("LWS_CALLBACK_HTTP_FILE_COMPLETION seen\n");
140 /* kill the connection after we sent one file */
141 return -1;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100142
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200143 case LWS_CALLBACK_HTTP_WRITEABLE:
144 /*
145 * we can send more of whatever it is we were sending
146 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100147
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200148 do {
149 n = read(pss->fd, buffer, sizeof buffer);
150 /* problem reading, close conn */
151 if (n < 0)
152 goto bail;
153 /* sent it all, close conn */
154 if (n == 0)
155 goto bail;
156 /*
157 * because it's HTTP and not websocket, don't need to take
158 * care about pre and postamble
159 */
160 m = libwebsocket_write(wsi, buffer, n, LWS_WRITE_HTTP);
161 if (m < 0)
162 /* write failed, close conn */
163 goto bail;
164 if (m != n)
165 /* partial write, adjust */
166 lseek(pss->fd, m - n, SEEK_CUR);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100167
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200168 } while (!lws_send_pipe_choked(wsi));
169 libwebsocket_callback_on_writable(context, wsi);
170 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100171
172bail:
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200173 close(pss->fd);
174 return -1;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100175
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200176 case LWS_CALLBACK_LOCK_POLL:
177 /*
178 * lock mutex to protect pollfd state
179 * called before any other POLL related callback
180 */
181 break;
Tomas Cejka11d5d062014-07-15 13:13:52 +0200182
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200183 case LWS_CALLBACK_UNLOCK_POLL:
184 /*
185 * unlock mutex to protect pollfd state when
186 * called after any other POLL related callback
187 */
188 break;
Tomas Cejka11d5d062014-07-15 13:13:52 +0200189
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200190 /*
191 * callback for confirming to continue with client IP appear in
192 * protocol 0 callback since no websocket protocol has been agreed
193 * yet. You can just ignore this if you won't filter on client IP
194 * since the default uhandled callback return is 0 meaning let the
195 * connection continue.
196 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100197
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200198 case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
199 libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name,
200 sizeof(client_name), client_ip, sizeof(client_ip));
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100201
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200202 //fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip);
203 /* if we returned non-zero from here, we kill the connection */
204 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100205
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200206 /*
207 * callbacks for managing the external poll() array appear in
208 * protocol 0 callback
209 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100210
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200211 case LWS_CALLBACK_ADD_POLL_FD:
212 if (count_pollfds >= max_poll_elements) {
213 lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
214 return 1;
215 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100216
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200217 fd_lookup[pa->fd] = count_pollfds;
218 pollfds[count_pollfds].fd = pa->fd;
219 pollfds[count_pollfds].events = pa->events;
220 pollfds[count_pollfds++].revents = 0;
221 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100222
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200223 case LWS_CALLBACK_DEL_POLL_FD:
224 if (!--count_pollfds)
225 break;
226 m = fd_lookup[pa->fd];
227 /* have the last guy take up the vacant slot */
228 pollfds[m] = pollfds[count_pollfds];
229 fd_lookup[pollfds[count_pollfds].fd] = m;
230 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100231
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200232 case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
233 pollfds[fd_lookup[pa->fd]].events = pa->events;
234 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100235
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100236
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200237 default:
238 break;
239 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100240
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200241 return 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100242}
243
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100244
245/* dumb_increment protocol */
246
247/*
248 * one of these is auto-created for each connection and a pointer to the
249 * appropriate instance is passed to the callback in the user parameter
250 *
251 * for this example protocol we use it to individualize the count for each
252 * connection.
253 */
254
Tomas Cejkaba21b382013-04-13 02:37:32 +0200255struct per_session_data__notif_client {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200256 int number;
257 char *session_id;
258 struct nc_session *session;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100259};
260
Michal Vasko3d8681d2015-11-05 10:23:41 +0100261struct session_with_mutex *get_ncsession_from_sid(const char *session_id)
Tomas Cejkaba21b382013-04-13 02:37:32 +0200262{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200263 struct session_with_mutex *locked_session = NULL;
264 if (session_id == NULL) {
265 return (NULL);
266 }
267 for (locked_session = netconf_sessions_list;
Michal Vaskof35ea502016-02-24 10:44:54 +0100268 locked_session && (nc_session_get_id(locked_session->session) == (unsigned)atoi(session_id));
Michal Vaskoc3146782015-11-04 14:46:41 +0100269 locked_session = locked_session->next);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200270 return locked_session;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200271}
272
273/* rpc parameter is freed after the function call */
Michal Vaskof35ea502016-02-24 10:44:54 +0100274static int send_recv_process(struct nc_session *session, const char* UNUSED(operation), struct nc_rpc* rpc)
Tomas Cejkaba21b382013-04-13 02:37:32 +0200275{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200276 struct nc_reply *reply = NULL;
277 char *data = NULL;
278 int ret = EXIT_SUCCESS;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200279
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200280 /* send the request and get the reply */
281 switch (netconf_send_recv_timed(session, rpc, 50000, 0, &reply)) {
282 case NC_MSG_ERROR:
283 if (nc_session_get_status(session) != NC_STATUS_RUNNING) {
284 ERROR("notifications: receiving rpc-reply failed.");
285 //cmd_disconnect(NULL);
286 ret = EXIT_FAILURE;
287 break;
288 }
289 ERROR("notifications: Unknown error occurred.");
290 ret = EXIT_FAILURE;
291 break;
292 case NC_MSG_NONE:
293 /* error occurred, but processed by callback */
294 break;
295 case NC_MSG_REPLY:
296 switch (reply->type) {
297 case NC_RPL_OK:
298 break;
299 case NC_RPL_DATA:
Michal Vaskof35ea502016-02-24 10:44:54 +0100300 lyd_print_mem(&data, ((struct nc_reply_data *)reply)->data, LYD_JSON, 0);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200301 DEBUG("notifications: recv: %s.", data);
Michal Vaskof35ea502016-02-24 10:44:54 +0100302 free(data);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200303 break;
304 case NC_RPL_ERROR:
305 /* wtf, you shouldn't be here !?!? */
306 DEBUG("notifications: operation failed, but rpc-error was not processed.");
307 ret = EXIT_FAILURE;
308 break;
309 default:
310 DEBUG("notifications: unexpected operation result.");
311 ret = EXIT_FAILURE;
312 break;
313 }
314 break;
315 default:
316 DEBUG("notifications: Unknown error occurred.");
317 ret = EXIT_FAILURE;
318 break;
319 }
320 nc_rpc_free(rpc);
321 nc_reply_free(reply);
Tomas Cejkaba21b382013-04-13 02:37:32 +0200322
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200323 return (ret);
Tomas Cejkaba21b382013-04-13 02:37:32 +0200324}
325
326/**
327 * \brief Callback to store incoming notification
328 * \param [in] eventtime - time when notification occured
329 * \param [in] content - content of notification
330 */
Michal Vaskof35ea502016-02-24 10:44:54 +0100331static void notification_fileprint(struct nc_session *session, const struct nc_notif *notif)
Tomas Cejkaba21b382013-04-13 02:37:32 +0200332{
Michal Vaskof35ea502016-02-24 10:44:54 +0100333 time_t eventtime;
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200334 struct session_with_mutex *target_session = NULL;
335 notification_t *ntf = NULL;
336 const char *session_id = NULL;
Michal Vaskof35ea502016-02-24 10:44:54 +0100337 char *content;
338 (void)session;
339
340 eventtime = nc_datetime2time(notif->datetime);
341 lyd_print_mem(&content, notif->tree, LYD_JSON, 0);
Tomas Cejkaba21b382013-04-13 02:37:32 +0200342
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200343 DEBUG("Accepted notif: %lu %s\n", (unsigned long int) eventtime, content);
Tomas Cejka15c56302013-05-30 01:11:30 +0200344
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200345 session_id = pthread_getspecific(thread_key);
346 DEBUG("notification: fileprint getspecific (%s)", session_id);
347 if (pthread_rwlock_wrlock(&session_lock) != 0) {
348 ERROR("notifications: Error while locking rwlock");
Michal Vaskof35ea502016-02-24 10:44:54 +0100349 free(content);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200350 return;
351 }
352 DEBUG("Get session with mutex from key %s.", session_id);
353 target_session = get_ncsession_from_sid(session_id);
354 if (target_session == NULL) {
355 ERROR("notifications: no session found last_session_key (%s)", session_id);
Michal Vaskof35ea502016-02-24 10:44:54 +0100356 free(content);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200357 goto unlock_glob;
358 }
359 if (pthread_mutex_lock(&target_session->lock) != 0) {
360 ERROR("notifications: Error while locking rwlock");
361 }
Tomas Cejka15c56302013-05-30 01:11:30 +0200362
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200363 DEBUG("notification: ready to push to notifications queue");
Michal Vaskoc3146782015-11-04 14:46:41 +0100364 if (target_session->notif_count < NOTIFICATION_QUEUE_SIZE) {
365 ++target_session->notif_count;
366 target_session->notifications = realloc(target_session->notifications,
367 target_session->notif_count * sizeof *target_session->notifications);
368 if (target_session->notifications) {
369 ntf = target_session->notifications + target_session->notif_count - 1;
370 }
371 }
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200372 if (ntf == NULL) {
373 ERROR("notifications: Failed to allocate element ");
Michal Vaskof35ea502016-02-24 10:44:54 +0100374 free(content);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200375 goto unlock_all;
376 }
377 ntf->eventtime = eventtime;
378 ntf->content = content;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200379
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200380 DEBUG("added notif to queue %u (%s)", (unsigned int) ntf->eventtime, "notification");
Tomas Cejkaba21b382013-04-13 02:37:32 +0200381
Tomas Cejka885ec3e2014-06-22 18:01:34 +0200382unlock_all:
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200383 if (pthread_mutex_unlock(&target_session->lock) != 0) {
384 ERROR("notifications: Error while unlocking rwlock");
385 }
Tomas Cejka885ec3e2014-06-22 18:01:34 +0200386unlock_glob:
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200387 if (pthread_rwlock_unlock(&session_lock) != 0) {
388 ERROR("notifications: Error while locking rwlock");
389 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200390}
391
Michal Vaskoc3146782015-11-04 14:46:41 +0100392int notif_subscribe(struct session_with_mutex *locked_session, const char *session_id, time_t start_time, time_t stop_time)
Tomas Cejkaba21b382013-04-13 02:37:32 +0200393{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200394 time_t start = -1;
395 time_t stop = -1;
396 char *stream = NULL;
397 struct nc_rpc *rpc = NULL;
398 struct nc_session *session;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200399
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200400 DEBUG("notif_subscribe");
401 if (locked_session == NULL) {
402 DEBUG("notifications: no locked_session was given.");
403 /* Close notification client */
404 return -1;
405 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200406
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200407 pthread_mutex_lock(&locked_session->lock);
408 session = locked_session->session;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200409
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200410 start = time(NULL) + start_time;
411 stop = time(NULL) + stop_time;
412 start = 0;
413 stop = 0;
414 DEBUG("notifications: history: %u %u", (unsigned int) start, (unsigned int) stop);
Tomas Cejkaba21b382013-04-13 02:37:32 +0200415
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200416 if (session == NULL) {
417 ERROR("notifications: NETCONF session not established.");
418 goto operation_failed;
419 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200420
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200421 /* check times */
422 if (start != -1 && stop != -1 && start > stop) {
423 ERROR("notifications: Subscription start time must be lower than the end time.");
424 goto operation_failed;
425 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200426
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200427 DEBUG("Prepare to execute subscription.");
428 /* create requests */
429 rpc = nc_rpc_subscribe(stream, NULL, (start_time == -1) ? NULL : nc_time2datetime(start, NULL),
Michal Vaskof35ea502016-02-24 10:44:54 +0100430 (stop_time == 0) ? NULL : nc_time2datetime(stop, NULL), NC_PARAMTYPE_CONST);
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200431 if (rpc == NULL) {
432 ERROR("notifications: creating an rpc request failed.");
433 goto operation_failed;
434 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200435
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200436 DEBUG("Send NC subscribe.");
437 create_err_reply_p();
438 if (send_recv_process(session, "subscribe", rpc) != 0) {
439 ERROR("Subscription RPC failed.");
440 goto operation_failed;
441 }
Tomas Cejka442258e2014-04-01 18:17:18 +0200442
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200443 GETSPEC_ERR_REPLY
444 if (err_reply != NULL) {
Tomas Cejka442258e2014-04-01 18:17:18 +0200445 free_err_reply();
Tomas Cejkacf44e522015-04-24 17:29:21 +0200446 ERROR("RPC-Error received and cleaned, because we can't send it anywhere.");
Tomas Cejka442258e2014-04-01 18:17:18 +0200447 goto operation_failed;
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200448 }
Tomas Cejka442258e2014-04-01 18:17:18 +0200449
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200450 rpc = NULL; /* just note that rpc is already freed by send_recv_process() */
451 locked_session->ntfc_subscribed = 1;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200452
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200453 DEBUG("notifications: creating libnetconf notification thread (%s).", session_id);
Tomas Cejka654f84e2013-04-19 11:55:01 +0200454
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200455 pthread_mutex_unlock(&locked_session->lock);
456
457 /* store hash identification of netconf session for notifications printing callback */
458 if (pthread_setspecific(thread_key, session_id) != 0) {
459 ERROR("notifications: cannot set thread-specific hash value.");
460 }
461
462 DEBUG("Create notification_thread.");
463 nc_recv_notif_dispatch(session, notification_fileprint);
464 DEBUG("Subscription finished.");
465 return 0;
Tomas Cejka5ce57b62013-08-29 17:47:39 +0200466
467operation_failed:
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200468 pthread_mutex_unlock(&locked_session->lock);
469 return -1;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200470}
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100471
472static int callback_notification(struct libwebsocket_context *context,
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200473 struct libwebsocket *wsi,
474 enum libwebsocket_callback_reasons reason,
475 void *user, void *in, size_t len)
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100476{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200477 int n = 0, m = 0, i;
478 unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 40960 + LWS_SEND_BUFFER_POST_PADDING];
479 unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
480 struct per_session_data__notif_client *pss = (struct per_session_data__notif_client *)user;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200481
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200482 switch (reason) {
483 case LWS_CALLBACK_ESTABLISHED:
484 DEBUG("ntf_prot clb LWS_CALLBACK_ESTABLISHED");
485 break;
486 case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
487 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_CONNECTION_ERROR");
488 break;
489 case LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH:
490 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH");
491 break;
492 case LWS_CALLBACK_CLIENT_ESTABLISHED:
493 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_ESTABLISHED");
494 break;
495 case LWS_CALLBACK_CLOSED:
496 DEBUG("ntf_prot clb LWS_CALLBACK_CLOSED");
497 break;
498 case LWS_CALLBACK_RECEIVE:
499 DEBUG("ntf_prot clb LWS_CALLBACK_RECEIVE");
500 break;
501 case LWS_CALLBACK_RECEIVE_PONG:
502 DEBUG("ntf_prot clb LWS_CALLBACK_RECEIVE_PONG");
503 break;
504 case LWS_CALLBACK_CLIENT_RECEIVE_PONG:
505 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_RECEIVE_PONG");
506 break;
507 case LWS_CALLBACK_CLIENT_RECEIVE:
508 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_RECEIVE");
509 break;
510 case LWS_CALLBACK_CLIENT_WRITEABLE:
511 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_WRITEABLE");
512 break;
513 case LWS_CALLBACK_HTTP:
514 DEBUG("ntf_prot clb LWS_CALLBACK_HTTP");
515 break;
516 case LWS_CALLBACK_HTTP_BODY:
517 DEBUG("ntf_prot clb LWS_CALLBACK_HTTP_BODY");
518 break;
519 case LWS_CALLBACK_HTTP_BODY_COMPLETION:
520 DEBUG("ntf_prot clb LWS_CALLBACK_HTTP_BODY_COMPLETION");
521 break;
522 case LWS_CALLBACK_FILTER_HTTP_CONNECTION:
523 DEBUG("ntf_prot clb LWS_CALLBACK_FILTER_HTTP_CONNECTION");
524 break;
525 case LWS_CALLBACK_CLOSED_HTTP:
526 DEBUG("ntf_prot clb LWS_CALLBACK_CLOSED_HTTP");
527 break;
528 case LWS_CALLBACK_HTTP_WRITEABLE:
529 DEBUG("ntf_prot clb LWS_CALLBACK_HTTP_WRITEABLE");
530 break;
531 case LWS_CALLBACK_HTTP_FILE_COMPLETION:
532 DEBUG("ntf_prot clb LWS_CALLBACK_HTTP_FILE_COMPLETION");
533 break;
534 case LWS_CALLBACK_SERVER_WRITEABLE:
535 DEBUG("ntf_prot clb LWS_CALLBACK_SERVER_WRITEABLE");
536 break;
537 case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
538 DEBUG("ntf_prot clb LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED");
539 break;
540 case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
541 DEBUG("ntf_prot clb LWS_CALLBACK_FILTER_NETWORK_CONNECTION");
542 break;
543 case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
544 DEBUG("ntf_prot clb LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION");
545 break;
546 case LWS_CALLBACK_WSI_CREATE:
547 DEBUG("ntf_prot clb LWS_CALLBACK_WSI_CREATE");
548 break;
549 case LWS_CALLBACK_WSI_DESTROY:
550 DEBUG("ntf_prot clb LWS_CALLBACK_WSI_DESTROY");
551 break;
552 case LWS_CALLBACK_GET_THREAD_ID:
553 DEBUG("ntf_prot clb LWS_CALLBACK_GET_THREAD_ID");
554 break;
555 case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
556 DEBUG("ntf_prot clb LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS");
557 break;
558 case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS:
559 DEBUG("ntf_prot clb LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS");
560 break;
561 case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION:
562 DEBUG("ntf_prot clb LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION");
563 break;
564 case LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY:
565 DEBUG("ntf_prot clb LWS_CALLBACK_OPENSSL_CONTEXT_REQUIRES_PRIVATE_KEY");
566 break;
567 case LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER:
568 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER");
569 break;
570 case LWS_CALLBACK_CONFIRM_EXTENSION_OKAY:
571 DEBUG("ntf_prot clb LWS_CALLBACK_CONFIRM_EXTENSION_OKAY");
572 break;
573 case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:
574 DEBUG("ntf_prot clb LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED");
575 break;
576 case LWS_CALLBACK_PROTOCOL_INIT:
577 DEBUG("ntf_prot clb LWS_CALLBACK_PROTOCOL_INIT");
578 break;
579 case LWS_CALLBACK_PROTOCOL_DESTROY:
580 DEBUG("ntf_prot clb LWS_CALLBACK_PROTOCOL_DESTROY");
581 break;
582 case LWS_CALLBACK_ADD_POLL_FD:
583 DEBUG("ntf_prot clb LWS_CALLBACK_ADD_POLL_FD");
584 break;
585 case LWS_CALLBACK_DEL_POLL_FD:
586 DEBUG("ntf_prot clb LWS_CALLBACK_DEL_POLL_FD");
587 break;
588 case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
589 DEBUG("ntf_prot clb LWS_CALLBACK_CHANGE_MODE_POLL_FD");
590 break;
591 case LWS_CALLBACK_LOCK_POLL:
592 DEBUG("ntf_prot clb LWS_CALLBACK_LOCK_POLL");
593 break;
594 case LWS_CALLBACK_UNLOCK_POLL:
595 DEBUG("ntf_prot clb LWS_CALLBACK_UNLOCK_POLL");
596 break;
597 case LWS_CALLBACK_USER:
598 DEBUG("ntf_prot clb LWS_CALLBACK_USER");
599 break;
600 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100601
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200602 switch (reason) {
603 case LWS_CALLBACK_ESTABLISHED:
604 DEBUG("notification client connected.");
605 break;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200606
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200607 case LWS_CALLBACK_SERVER_WRITEABLE:
608 if (pss->session_id == NULL) {
609 return 0;
610 }
611 //DEBUG("Callback server writeable.");
612 //DEBUG("lock session lock.");
613 if (pthread_rwlock_wrlock(&session_lock) != 0) {
614 DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
615 return -1;
616 }
617 //DEBUG("get session_with_mutex for %s.", pss->session_id);
618 struct session_with_mutex *ls = get_ncsession_from_sid(pss->session_id);
619 if (ls == NULL) {
620 DEBUG("notification: session not found");
621 if (pthread_rwlock_unlock (&session_lock) != 0) {
622 DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
623 return -1;
624 }
625 return -1;
626 }
627 pthread_mutex_lock(&ls->lock);
628 if (pthread_rwlock_unlock(&session_lock) != 0) {
629 DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
630 }
631
632 //DEBUG("check for closed session.");
633 if (ls->closed == 1) {
634 DEBUG("unlock session key.");
635 if (pthread_rwlock_unlock (&session_lock) != 0) {
636 DEBUG("Error while unlocking unlock: %d (%s)", errno, strerror(errno));
637 return -1;
638 }
639 return -1;
640 }
641 //DEBUG("lock private lock.");
642 notification_t *notif = NULL;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200643
Michal Vasko1ac11282015-11-05 10:28:07 +0100644 if (ls->notif_count) {
645 DEBUG("notification: POP notifications for session");
Michal Vasko43d94a62015-11-05 10:59:32 +0100646 for (i = ls->notif_count; i; --i) {
647 notif = ls->notifications + i - 1;
Tomas Cejka73286932013-05-27 22:54:35 +0200648
Michal Vasko1ac11282015-11-05 10:28:07 +0100649 n = 0;
650 pthread_mutex_lock(&json_lock);
651 json_object *notif_json = json_object_new_object();
652 json_object_object_add(notif_json, "eventtime", json_object_new_int64(notif->eventtime));
653 json_object_object_add(notif_json, "content", json_object_new_string(notif->content));
654 pthread_mutex_unlock(&json_lock);
Tomas Cejka15c56302013-05-30 01:11:30 +0200655
Michal Vasko1ac11282015-11-05 10:28:07 +0100656 const char *msgtext = json_object_to_json_string(notif_json);
Tomas Cejka15c56302013-05-30 01:11:30 +0200657
Michal Vasko1ac11282015-11-05 10:28:07 +0100658 //n = sprintf((char *)p, "{\"eventtime\": \"%s\", \"content\": \"notification\"}", t);
659 n = sprintf((char *)p, "%s", msgtext);
660 DEBUG("ws send %dB in %lu", n, sizeof(buf));
661 m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
662 if (lws_send_pipe_choked(wsi)) {
663 libwebsocket_callback_on_writable(context, wsi);
664 break;
665 }
Michal Vaskoc3146782015-11-04 14:46:41 +0100666
Michal Vasko1ac11282015-11-05 10:28:07 +0100667 pthread_mutex_lock(&json_lock);
668 json_object_put(notif_json);
669 pthread_mutex_unlock(&json_lock);
670 free(notif->content);
Michal Vaskoc3146782015-11-04 14:46:41 +0100671 }
Michal Vasko43d94a62015-11-05 10:59:32 +0100672 ls->notif_count = 0;
673 free(ls->notifications);
674 ls->notifications = NULL;
675
Michal Vasko1ac11282015-11-05 10:28:07 +0100676 DEBUG("notification: POP notifications done");
Michal Vaskoc3146782015-11-04 14:46:41 +0100677 }
Tomas Cejkaba21b382013-04-13 02:37:32 +0200678
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200679 //DEBUG("unlock private lock");
680 if (pthread_mutex_unlock(&ls->lock) != 0) {
681 DEBUG("notification: cannot unlock session");
682 }
683 //DEBUG("unlock session lock");
Tomas Cejkaba21b382013-04-13 02:37:32 +0200684
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200685 if (m < n) {
686 DEBUG("ERROR %d writing to di socket.", n);
Tomas Cejka15c56302013-05-30 01:11:30 +0200687
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200688 return -1;
689 }
690 break;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100691
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200692 case LWS_CALLBACK_RECEIVE:
693 DEBUG("Callback receive.");
694 DEBUG("received: (%s)", (char *)in);
695 if (pss->session_id == NULL) {
696 char *sid_end;
697 int start = -1;
698 time_t stop = time(NULL) + 30;
Tomas Cejkaba21b382013-04-13 02:37:32 +0200699
Michal Vasko2bff5fb2015-11-05 10:23:02 +0100700 sid_end = strchr(in, ' ');
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200701 pss->session_id = strndup(in, sid_end - (char *)in);
Michal Vasko2bff5fb2015-11-05 10:23:02 +0100702
703 ++sid_end;
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200704 sscanf(sid_end, "%d %d", (int *) &start, (int *) &stop);
705 DEBUG("notification: SID (%s) from (%s) (%i,%i)", pss->session_id, (char *) in, (int) start, (int) stop);
Tomas Cejka15c56302013-05-30 01:11:30 +0200706
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200707 DEBUG("lock session lock");
708 if (pthread_rwlock_rdlock (&session_lock) != 0) {
709 DEBUG("Error while locking rwlock: %d (%s)", errno, strerror(errno));
710 return -1;
711 }
712 DEBUG("get session with ID (%s)", pss->session_id);
713 struct session_with_mutex *ls = get_ncsession_from_sid(pss->session_id);
714 if (ls == NULL) {
715 DEBUG("notification: session_id not found (%s)", pss->session_id);
716 DEBUG("unlock session lock");
717 if (pthread_rwlock_unlock (&session_lock) != 0) {
718 DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
719 }
720 DEBUG("Close notification client");
721 return -1;
722 }
723 DEBUG("lock private lock");
724 pthread_mutex_lock(&ls->lock);
Tomas Cejka47387fd2013-06-10 20:37:46 +0200725
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200726 DEBUG("unlock session lock");
727 if (pthread_rwlock_unlock (&session_lock) != 0) {
728 DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
729 }
Tomas Cejka47387fd2013-06-10 20:37:46 +0200730
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200731 DEBUG("Found session to subscribe notif.");
732 if (ls->closed == 1) {
733 DEBUG("session already closed - handle no notification");
734 DEBUG("unlock private lock");
735 pthread_mutex_unlock(&ls->lock);
736 DEBUG("Close notification client");
737 return -1;
738 }
739 if (ls->ntfc_subscribed != 0) {
740 DEBUG("notification: already subscribed");
741 DEBUG("unlock private lock");
742 pthread_mutex_unlock(&ls->lock);
743 /* do not close client, only do not subscribe again */
744 return 0;
745 }
746 DEBUG("notification: prepare to subscribe stream");
747 DEBUG("unlock session lock");
748 pthread_mutex_unlock(&ls->lock);
Tomas Cejka47387fd2013-06-10 20:37:46 +0200749
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200750 /* notif_subscribe locks on its own */
751 return notif_subscribe(ls, pss->session_id, (time_t) start, (time_t) stop);
752 }
753 if (len < 6)
754 break;
755 break;
756 /*
757 * this just demonstrates how to use the protocol filter. If you won't
758 * study and reject connections based on header content, you don't need
759 * to handle this callback
760 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100761
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200762 case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION:
763 //dump_handshake_info(wsi);
764 /* you could return non-zero here and kill the connection */
765 break;
766 //gives segfault :-(
767 //case LWS_CALLBACK_CLOSED:
768 // if (pss->session_key != NULL) {
769 // free(pss->session_key);
770 // }
771 // if (pss != NULL) {
772 // free(pss);
773 // }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100774
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200775 default:
776 break;
777 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100778
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200779 return 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100780}
781
782/* list of supported protocols and callbacks */
783
784static struct libwebsocket_protocols protocols[] = {
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200785 /* first protocol must always be HTTP handler */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100786
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200787 {
788 "http-only", /* name */
789 callback_http, /* callback */
790 sizeof (struct per_session_data__http), /* per_session_data_size */
791 0, /* max frame size / rx buffer */
Michal Vaskoc3146782015-11-04 14:46:41 +0100792 0,
793 NULL,
794 NULL,
795 0
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200796 },
797 {
798 "notification-protocol",
799 callback_notification,
800 sizeof(struct per_session_data__notif_client),
801 4000,
Michal Vaskoc3146782015-11-04 14:46:41 +0100802 0,
803 NULL,
804 NULL,
805 0
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200806 },
807 { NULL, NULL, 0, 0, 0, NULL, NULL, 0 } /* terminator */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100808};
809
Tomas Cejkaba21b382013-04-13 02:37:32 +0200810/**
811 * initialization of notification module
812 */
Michal Vaskoc3146782015-11-04 14:46:41 +0100813int notification_init(void)
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100814{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200815 //char cert_path[1024];
816 //char key_path[1024];
817 //int use_ssl = 0;
818 struct lws_context_creation_info info;
819 int opts = 0;
820 //char interface_name[128] = "";
821 const char *iface = NULL;
822 int debug_level = 7;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100823
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200824 memset(&info, 0, sizeof info);
825 info.port = NOTIFICATION_SERVER_PORT;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100826
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200827 /* tell the library what debug level to emit and to send it to syslog */
828 lws_set_log_level(debug_level, lwsl_emit_syslog);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100829
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200830 DEBUG("Initialization of libwebsocket");
831 //lwsl_notice("libwebsockets test server - "
832 // "(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - "
833 // "licensed under LGPL2.1\n");
834 max_poll_elements = getdtablesize();
835 pollfds = malloc(max_poll_elements * sizeof (struct pollfd));
836 fd_lookup = malloc(max_poll_elements * sizeof (int));
837 if (pollfds == NULL || fd_lookup == NULL) {
838 ERROR("notifications: Out of memory pollfds=%d\n", max_poll_elements);
839 return -1;
840 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100841
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200842 info.iface = iface;
843 info.protocols = protocols;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100844
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200845 //snprintf(cert_path, sizeof(cert_path), "%s/libwebsockets-test-server.pem", resource_path);
846 //snprintf(key_path, sizeof(cert_path), "%s/libwebsockets-test-server.key.pem", resource_path);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100847
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200848 //info.ssl_cert_filepath = cert_path;
849 //info.ssl_private_key_filepath = key_path;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100850
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200851 info.gid = -1;
852 info.uid = -1;
853 info.options = opts;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100854
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200855 /* create server */
856 context = libwebsocket_create_context(&info);
857 if (context == NULL) {
858 DEBUG("libwebsocket init failed.");
859 return -1;
860 }
Tomas Cejka15c56302013-05-30 01:11:30 +0200861
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200862 if (pthread_key_create(&thread_key, NULL) != 0) {
863 ERROR("notifications: pthread_key_create failed");
864 }
865 return 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100866}
867
Michal Vaskoc3146782015-11-04 14:46:41 +0100868void notification_close(void)
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100869{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200870 if (context) {
871 libwebsocket_context_destroy(context);
872 }
873 free(pollfds);
874 free(fd_lookup);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100875
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200876 DEBUG("libwebsockets-test-server exited cleanly\n");
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100877}
878
Tomas Cejkaba21b382013-04-13 02:37:32 +0200879
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100880/**
881 * \brief send notification if any
882 * \return < 0 on error
883 */
884int notification_handle()
885{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200886 static struct timeval tv;
887 static unsigned int olds = 0;
888 int n = 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100889
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200890 gettimeofday(&tv, NULL);
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100891
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200892 /*
893 * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
894 * live websocket connection using the DUMB_INCREMENT protocol,
895 * as soon as it can take more packets (usually immediately)
896 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100897
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200898 if (((unsigned int)tv.tv_sec - olds) > 0) {
899 libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_NOTIFICATION]);
900 olds = tv.tv_sec;
901 }
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100902
903
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200904 /*
905 * this represents an existing server's single poll action
906 * which also includes libwebsocket sockets
907 */
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100908
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200909 n = poll(pollfds, count_pollfds, 50);
910 if (n < 0)
911 return n;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100912
913
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200914 if (n) {
915 for (n = 0; n < count_pollfds; n++) {
916 if (pollfds[n].revents) {
917 /*
918 * returns immediately if the fd does not
919 * match anything under libwebsockets
920 * control
921 */
922 if (libwebsocket_service_fd(context, &pollfds[n]) < 0) {
923 return 1;
924 }
925 }
926 }
927 }
928 return 0;
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100929}
930
931#endif
932
933
934#ifndef WITH_NOTIFICATIONS
935#ifdef TEST_NOTIFICATION_SERVER
936int main(int argc, char **argv)
937{
Michal Vaskofcc9a9c2016-05-06 11:51:35 +0200938 if (notification_init(NULL, NULL) == -1) {
939 fprintf(stderr, "Error during initialization\n");
940 return 1;
941 }
942 while (!force_exit) {
943 notification_handle();
944 }
945 notification_close();
Tomas Cejkad340dbf2013-03-24 20:36:57 +0100946}
947#endif
948#endif