Skip to content
Snippets Groups Projects
Commit d0b73727 authored by clohr's avatar clohr
Browse files

Préparation de la v0.5r2

git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/C/trunk@1589 b32b6428-25c9-4566-ad07-03861ab6144f
parent f8b52763
Branches
No related tags found
No related merge requests found
......@@ -68,8 +68,7 @@ ajax jqueries &co. (Usable also as RESTful compliant gateway? ;-) )
. Check values linked to an ad-hoc attribute and try to re-link them to the
right attribute of the right schema (following sechmas that are extended by
the schema of the device of the corresponding value)
- xaagent offers several threads to answers to fastcgi requests.
The (RESTful) API is:
- The REST API:
. http://localhost:8888/json/devices[?key=<name>]
Returns an array of devices (just {address, devType, timeout}) having
the given metadata key if provided, or all devices.
......@@ -89,8 +88,8 @@ ajax jqueries &co. (Usable also as RESTful compliant gateway? ;-) )
. http://localhost:8888/json/send
A POST request. The content is a json object having:
{ "header": { "targets": [<array of device addresses (uuid)>]
"action": <name of the method to those devices> }
, "body": <parameters and values for the mehod, if needed> }
"action": <name of the method to those devices> },
"body": <parameters and values for the mehod, if needed> }
. http://localhost:8888/json/dump
An Event Stream API to recieve a dump of xAAL messages
. http://localhost:8888/json/attributesChange
......
......@@ -5,13 +5,14 @@ OBJS = $(SRC:.c=.o)
CFLAGS = -Wall -g -I.
LDFLAGS = -lwebsockets -ljson-c -luuid -lsodium -L. -lxaal
SHELL = /bin/bash
all: $(PROG)
$(PROG): $(OBJS)
test: $(PROG)
env LD_LIBRARY_PATH+=:. ./$(PROG) -a 224.0.29.200 -p 1234 -s my_secret
LD_LIBRARY_PATH+=:. ./$(PROG) -a 224.0.29.200 -p 1234 -s my_secret
clean:
-rm -f $(OBJS) *~
......
# xaaws - xAAL with WebSockets
A generic HMI for xAAL devices able to handle dynamicity of xAAL
following everyone's approaches: web technologies, including ajax
and web sockets...
## Architecture
- A core sever based on libwebosckets <https://libwebsockets.org/>
with 3 "protocols": http-only, xaal, xaal-dump
And an agent which monitors the xAAL bus, store interesting information
into an internal ad-hoc db
- The "http-only" protocol
. Serves static files (html, css, js, ...)
. Implements a json REST API (see bellow) to give information about what
was learned about xAAL devices
. Implements a POST API to pass requests to the xAAL bus
Note: The html and javascript parts are static files. The only dynamic part
are answers in the form of json data provided REST and WebSockets API.
## Dependencies
- the libwebosckets library (2.0.3)
- the xAAL library
- packages: uuid-dev libjson-c-dev libfcgi-dev liburiparser-dev
libsodium-dev libwebsockets-dev
## To Test It
- Type `make test`
- Go to `http://localhost:8888/` with your favorite web browser (with javascript)
- Have some xAAL devices on the xAAL bus 224.0.29.200:1234 (see xaaws.conf)
(optional but recommended: have a schema repository, a metadata database,
a cache)
## How it works
- xaaws sends an isAlive request on the xAAL bus at startup.
- It listens to alive notifications and store those devices on its DB.
(Well, just the address; one has to wait to get a full description)
It also stores the devType as an incomplete schema. (One just have the
name; one has to wait to get a full specification.)
- It listens to interesting xAAL replies (not requests! guess why)
. getAttributes: It stores those values of attributes on its DB, and try to
link this to known schemas. (Issue: the corresponding schema may not be
fully present in DB at this time, nor the schema it extends... Therefore,
one has to wait to link the value to the right attribute of the right
schema.)
. getDescription: It updates the device in its DB with this info.
. Messages from metadatadb.any devices (getKeysValues replies and
keysValuesChanged notifications).
It updates its DB (map of keys-values on devices) according to this.
. Replies from cache.any devices (getDeviceAttribute, getDeviceAttributes)
It updates its DB (values of attributes of devices) according to this.
. Replies from schemarepository.any devices (getSchema)
It update its DB (specification of schema) according to this.
- Periodically, it looks at incomplete information in DB:
. Devices without description (one just know the address): xaagent sends
getDescription requests to then.
. Devices without metadata: xaagent sends a getKeysValues to known metadatadb
about those devices.
. Schemas without a complete specification (one just known its name): xaagent
sends getSchema requests to known schemarepository devices.
. Devices with attributes without a known value: sends a getAttribute request
to those devices and a getDeviceAttribute request to known caches.
. Devices having reached theire timeout (plus a grace delay): remove them.
. Check values linked to an ad-hoc attribute and try to re-link them to the
right attribute of the right schema (following sechmas that are extended by
the schema of the device of the corresponding value)
- The REST API:
. http://localhost:8888/json/devices[?key=<name>]
Returns an array of devices (just {address, devType, timeout}) having
the given metadata key if provided, or all devices.
. http://localhost:8888/json/description?device=<uuid>
Returns an object with the known description of the requested device.
. http://localhost:8888/json/attributes?device=<uuid>
Returns an array of known values of attributes of the requested device.
. http://localhost:8888/json/methods?device=<uuid>
Returns an array of known methods of the requested device including
those of inherited schemas.
. http://localhost:8888/json/map?device=<uuid>
Returns the map of metadata keys-values of the requested device.
. http://localhost:8888/json/schema?devType=<name>
Returns an object with the specification of the requested devType.
Note that lists of attributes methods and notifications include those of
schemas that are extended by the requested one (if they are known).
. http://localhost:8888/json/send
A POST request. The content is a json object having:
{ "header": { "targets": [<array of device addresses (uuid)>]
"action": <name of the method to those devices> },
"body": <parameters and values for the method, if needed> }
- The WebSockets API:
. The "xaal" WebSockets protocol:
Sends: pass requests to the xAAL bus like the POST API
Receive: get attributesChange from the xAAL bus
. The "xaal-dump" WebSockets protocol:
Sends: void
Receive: get a dump of xAAL messages
- Disclamer: Returned information may be partial. Since xAAL is a distributed
system, there can't be any warranty about the completeness of the knowledge
of the global system state. Clients of this REST/WS API should not make any
assumption on this.
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "options.h"
......
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _OPTIONS_
#define _OPTIONS_
......
/*
* libwebsockets-test-server - libwebsockets test implementation
* Copyright (C) 2010-2016 Andy Green <andy@warmcat.com>
* available under the Creative Commons CC0 1.0
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Acknowledgement: Andy Green <andy@warmcat.com>
* libwebsockets-test-server (c) 2010-2016 - CC0 1.0
*/
#include <stdlib.h>
......@@ -15,38 +29,6 @@
#include "db.h"
#include "xaagent.h"
extern int debug_level;
/*
* this is just an example of parsing handshake headers, you don't need this
* in your code unless you will filter allowing connections by the header
* content
*/
void dump_handshake_info(struct lws *wsi) {
int n = 0, len;
char buf[256];
const unsigned char *c;
do {
c = lws_token_to_string(n);
if (!c) {
n++;
continue;
}
len = lws_hdr_total_length(wsi, n);
if (!len || len > sizeof(buf) - 1) {
n++;
continue;
}
lws_hdr_copy(wsi, buf, sizeof buf, n);
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, " %s = %s\n", (char *)c, buf);
n++;
} while (c);
}
const char *get_mimetype(const char *file) {
int n = strlen(file);
......@@ -79,14 +61,6 @@ const char *get_mimetype(const char *file) {
}
void print_poll(){
int i;
fprintf(stderr, "count_pollfds:%d\n", count_pollfds);
for (i=0; i<count_pollfds; i++)
fprintf(stderr, "pollfds[%d] { fd:%d events:%d revents:%d }\n", i, pollfds[i].fd, pollfds[i].events, pollfds[i].revents);
}
/* My own implementation of lws_get_urlarg_by_name() provided by more recent lib */
char* get_urlarg_by_name(struct lws *wsi, const char *name) {
......@@ -113,66 +87,24 @@ char* get_urlarg_by_name(struct lws *wsi, const char *name) {
* here on the first protocol server.
*/
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
void *in, size_t len) {
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
struct per_session_data__http *pss = (struct per_session_data__http *)user;
unsigned char buffer[4096 + LWS_PRE];
struct lws_pollargs *pa = (struct lws_pollargs *)in;
const char *mimetype;
unsigned char *end, *start;
unsigned char *p;
char buf[256];
int n, m;
struct lws_pollargs *pa = (struct lws_pollargs *)in;
switch (reason) {
case LWS_CALLBACK_HTTP:
lwsl_notice("LWS_CALLBACK_HTTP\n");
lwsl_notice("lws_http_serve: %s\n", in);
pss->post_uri = NULL;
pss->post_msg = NULL;
pss->post_len = 0;
// if (debug_level & LLL_INFO)
{
dump_handshake_info(wsi);
/* dump the individual URI Arg parameters */
n = 0;
while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf),
WSI_TOKEN_HTTP_URI_ARGS, n) > 0) {
lwsl_notice("URI Arg %d: %s\n", ++n, buf);
}
}
//fprintf(stderr, "key: %s\n", get_urlarg_by_name(wsi, "key=", buf, sizeof(buf)));
fprintf(stderr, "A\n");
{
char name[100], rip[50];
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name,
sizeof(name), rip, sizeof(rip));
sprintf(buf, "%s (%s)", name, rip);
lwsl_notice("HTTP connect from %s\n", buf);
}
fprintf(stderr, "B\n");
if (len < 1) {
lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL);
return -1;
// goto try_to_reuse;
}
fprintf(stderr, "C\n");
/* this example server has no concept of directories */
/*
if (strchr((const char *)in + 1, '/')) {
lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL);
goto try_to_reuse;
}
*/
/* Our pseudo-REST API */
{
pss->janswer = NULL;
......@@ -220,62 +152,17 @@ fprintf(stderr, "C\n");
}
if (pss->janswer) {
// if ( serve_http_json(wsi, janswer) ) {
fprintf(stderr, "build answer\n");
// json_object_put(janswer);
lws_callback_on_writable(wsi);
break;
// } else {
// lwsl_err("Unknown REST request '%s'\n", in);
// lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
// return -1;
// }
return 0;
}
}
fprintf(stderr, "D\n");
/*
if (!strncmp(in, "/postresults", 12)) {
m = sprintf(buf, "<html><body>Form results: '%s'<br>"
"</body></html>", pss->post_string);
p = buffer + LWS_PRE;
start = p;
end = p + sizeof(buffer) - LWS_PRE;
if (lws_add_http_header_status(wsi, 200, &p, end))
return 1;
if (lws_add_http_header_by_token(wsi,
WSI_TOKEN_HTTP_CONTENT_TYPE,
(unsigned char *)"text/html",
9, &p, end))
return 1;
if (lws_add_http_header_content_length(wsi, m, &p, end))
return 1;
if (lws_finalize_http_header(wsi, &p, end))
return 1;
n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
if (n < 0)
return 1;
n = lws_write(wsi, (unsigned char *)buf, m, LWS_WRITE_HTTP);
if (n < 0)
return 1;
goto try_to_reuse;
}
*/
fprintf(stderr, "E\n");
/* if a legal POST URL, let it continue and accept data */
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
fprintf(stderr, "POST: %s\n", in);
pss->post_uri = strdup(in);
break;
return 0;
}
fprintf(stderr, "F\n");
/* send a file the easy way */
strcpy(buf, resource_path);
......@@ -287,7 +174,6 @@ fprintf(stderr, "F\n");
strcat(buf, "/index.html");
buf[sizeof(buf) - 1] = '\0';
fprintf(stderr, "G\n");
/* refuse to serve files we don't understand */
mimetype = get_mimetype(buf);
if (!mimetype) {
......@@ -296,44 +182,22 @@ fprintf(stderr, "G\n");
return -1;
}
fprintf(stderr, "get_mimetype(%s): %s\n", buf, mimetype);
n = lws_serve_http_file(wsi, buf, mimetype, NULL, 0);
if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi)))
return -1; /* error or can't reuse connection: close the socket */
/*
* notice that the sending of the file completes asynchronously,
* we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when
* it's done
*/
break;
return 0;
case LWS_CALLBACK_HTTP_BODY:
lwsl_notice("LWS_CALLBACK_HTTP_BODY: len %d\n", (int)len);
pss->post_msg = realloc(pss->post_msg, pss->post_len+=len);
fprintf(stderr, "pss->post_msg:%p pss->post_len:%d\n", pss->post_msg, pss->post_len);
memcpy(pss->post_msg, in, pss->post_len);
fprintf(stderr, "\nBODY: '%.*s'\n\n", pss->post_len, pss->post_msg);
break;
return 0;
case LWS_CALLBACK_HTTP_BODY_COMPLETION:
lwsl_notice("LWS_CALLBACK_HTTP_BODY_COMPLETION\n");
/*
* the whole of the sent body arrived,
* respond to the client with a redirect to show the
* results
*/
fprintf(stderr, "COMPLETION\n POST URI: '%s'\n POST MSG: '%*s'\n", pss->post_uri, pss->post_len, pss->post_msg);
// p = (unsigned char *)buf + LWS_PRE;
// n = lws_http_redirect(wsi, HTTP_STATUS_SEE_OTHER, /* 303 */
// (unsigned char *)"/postresults", 12, /* location + len */
// &p, /* temp buffer to use */
// p + sizeof(buf) - 1 - LWS_PRE /* buffer len */
// );
// goto try_to_reuse;
if (!pss->post_uri || !pss->post_msg) {
break;
free(pss->post_uri);
free(pss->post_msg);
return 1;
}
if ( strcmp(pss->post_uri, REST_PREFIX "send") == 0 )
......@@ -349,115 +213,56 @@ fprintf(stderr, "COMPLETION\n POST URI: '%s'\n POST MSG: '%*s'\n", pss->post_uri
if (pss->janswer) {
lws_callback_on_writable(wsi);
break;
return 0;
} else {
lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL);
return -1;
}
case LWS_CALLBACK_HTTP_FILE_COMPLETION:
// goto try_to_reuse;
break;
case LWS_CALLBACK_HTTP_WRITEABLE:
lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n");
if (pss->janswer) {
if ( serve_http_json(wsi, pss->janswer) ) {
fprintf(stderr, "sends answer\n");
json_object_put(pss->janswer);
//lws_client_http_body_pending(wsi, 0);
pss->janswer = NULL;
break;
return 1;
} else {
lwsl_err("Bad REST\n");
lws_return_http_status(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, NULL);
json_object_put(pss->janswer);
pss->janswer = NULL;
return -1;
}
}
break;
/*
* callback for confirming to continue with client IP appear in
* protocol 0 callback since no websocket protocol has been agreed
* yet. You can just ignore this if you won't filter on client IP
* since the default unhandled callback return is 0 meaning let the
* connection continue.
*/
case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
/* if we returned non-zero from here, we kill the connection */
break;
return 0;
case LWS_CALLBACK_ADD_POLL_FD:
/*
fprintf(stderr, "\nADD_POLL_FD\n");
fprintf(stderr, "pa { fd:%d events:%d prev_events:%d }\n", pa->fd, pa->events, pa->prev_events);
fprintf(stderr, "before:\n");
print_poll();
*/
if (count_pollfds >= max_poll_elements) {
lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n");
return 1;
}
fd_lookup[pa->fd] = count_pollfds;
pollfds[count_pollfds].fd = pa->fd;
pollfds[count_pollfds].events = pa->events;
pollfds[count_pollfds++].revents = 0;
/*
fprintf(stderr, "after:\n");
print_poll();
fprintf(stderr, "\n");
*/
break;
return 0;
case LWS_CALLBACK_DEL_POLL_FD:
/*
fprintf(stderr, "\nDEL_POLL_FD\n");
fprintf(stderr, "pa { fd:%d events:%d prev_events:%d }\n", pa->fd, pa->events, pa->prev_events);
fprintf(stderr, "before:\n");
print_poll();
*/
if (!--count_pollfds)
break;
return 0;
m = fd_lookup[pa->fd];
/* have the last guy take up the vacant slot */
pollfds[m] = pollfds[count_pollfds];
fd_lookup[pollfds[count_pollfds].fd] = m;
/*
fprintf(stderr, "after:\n");
print_poll();
fprintf(stderr, "\n");
*/
break;
return 0;
case LWS_CALLBACK_CHANGE_MODE_POLL_FD:
pollfds[fd_lookup[pa->fd]].events = pa->events;
break;
return 0;
default:
break;
}
return 0;
/* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */
try_to_reuse:
if (lws_http_transaction_completed(wsi))
{
fprintf(stderr, "http transaction not completed\n");
return -1;
}
fprintf(stderr, "http transaction completed\n");
return 0;
}
......
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PROTOHTTP_
#define _PROTOHTTP_
......
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "proto-xaal.h"
......
/* xaaws - xAAL web interface
* Part of the 'majordom' software
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _PROTOXAAL_
#define _PROTOXAAL_
......
......@@ -26,13 +26,11 @@
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/timerfd.h>
#include <sys/queue.h>
#include <json-c/json.h>
#include <uuid/uuid.h>
#include <sys/queue.h>
//#include <uriparser/Uri.h> //??
#include <libwebsockets.h>
#include <xaal.h>
......@@ -697,7 +695,6 @@ struct json_object *post_xAALrequest(const xAAL_businfo_t *bus, const xAAL_devin
json_tokener_free(tok);
if (jerr != json_tokener_success) {
fprintf(stderr, "bad json_tokener_success\n");
return NULL;
}
......@@ -708,14 +705,12 @@ fprintf(stderr, "bad json_tokener_success\n");
|| !json_object_object_get_ex(jheader, "targets", &jtargets)
|| !json_object_is_type(jtargets, json_type_array) ) {
json_object_put(jinput);
fprintf(stderr, "bad header / action / targets\n");
return NULL;
}
action = json_object_get_string(jaction);
if (!validate_method(action)) {
json_object_put(jinput);
fprintf(stderr, "malformed action\n");
return NULL;
}
......@@ -725,15 +720,12 @@ fprintf(stderr, "malformed action\n");
if ( !json_object_is_type(jtarget, json_type_string)
|| !validate_addr(json_object_get_string(jtarget)) ) {
json_object_put(jinput);
fprintf(stderr, "malformed targets\n");
return NULL;
}
}
json_object_object_get_ex(jinput, "body", &jbody);
janswer = json_object_new_object();
bool ok;
json_object_object_add(janswer, "success", json_object_new_boolean( ok = xAAL_write_bus(bus, me, "request", action, jbody, jtargets) ) );
fprintf(stderr, "send %d\n", ok);
json_object_object_add(janswer, "success", json_object_new_boolean(xAAL_write_bus(bus, me, "request", action, jbody, jtargets)));
return janswer;
}
/* xaaws - xAAL web interface
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Acknowledgement: Andy Green <andy@warmcat.com>
* libwebsockets-test-server (c) 2010-2016 - CC0 1.0
*/
......
#ifndef _XAAWS_
#define _XAAWS_
/* xaaws - xAAL web interface
* (c) 2017 Christophe Lohr <christophe.lohr@imt-atlantique.fr>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Acknowledgement: Andy Green <andy@warmcat.com>
* libwebsockets-test-server (c) 2010-2016 - CC0 1.0
*/
#ifndef _XAAWS_
#define _XAAWS_
#include <libwebsockets.h>
#include <xaal.h>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment