diff --git a/server/dial_options.h b/server/dial_options.h index 6f6b970..d2fe4e9 100644 --- a/server/dial_options.h +++ b/server/dial_options.h @@ -50,6 +50,10 @@ #define WAKE_OPTION_LONG "--wake-on-wifi-len" #define WAKE_DESCRIPTION "Enable wake on wifi/len. Value: on/off. Default (on)" +#define SLEEP_PASSWORD "-S" +#define SLEEP_PASSWORD_LONG "--sleep-password" +#define SLEEP_PASSWORD_DESCRIPTION "Password required to put the device to deep sleep" + struct dial_options { const char * pOption; @@ -88,6 +92,11 @@ struct dial_options gDialOptions[] = WAKE_OPTION, WAKE_OPTION_LONG, WAKE_DESCRIPTION + }, + { + SLEEP_PASSWORD, + SLEEP_PASSWORD_LONG, + SLEEP_PASSWORD_DESCRIPTION } }; diff --git a/server/dial_server.c b/server/dial_server.c index 4e64748..8007c3d 100644 --- a/server/dial_server.c +++ b/server/dial_server.c @@ -151,6 +151,7 @@ static void handle_app_start(struct mg_connection *conn, } fprintf(stderr, "Starting the app with params %s\n", body); app->state = app->callbacks.start_cb(ds, app_name, body, + request_info->query_string, additional_data_param, &app->run_id, app->callback_data); @@ -166,6 +167,10 @@ static void handle_app_start(struct mg_connection *conn, // copy the payload into the application struct memset(app->payload, 0, DIAL_MAX_PAYLOAD); memcpy(app->payload, body, body_size); + } else if (app->state == kDIALStatusErrorForbidden) { + mg_send_http_error(conn, 403, "Forbidden", "Forbidden"); + } else if (app->state == kDIALStatusErrorUnauth) { + mg_send_http_error(conn, 401, "Unauthorized", "Unauthorized"); } else { mg_send_http_error(conn, 503, "Service Unavailable", "Service Unavailable"); @@ -281,24 +286,30 @@ static void handle_app_stop(struct mg_connection *conn, int canStop = 0; ds_lock(ds); - app = *find_app(ds, app_name); - // update the application state - if (app) { - app->state = app->callbacks.status_cb(ds, app_name, app->run_id, - &canStop, app->callback_data); - } - - if (!app || app->state == kDIALStatusStopped) { - mg_send_http_error(conn, 404, "Not Found", "Not Found"); + // Special handling for system app + if (strcmp(app_name, "system") == 0) { + mg_send_http_error(conn, 403, "Forbidden", "Forbidden"); // Can't stop system app. } else { - app->callbacks.stop_cb(ds, app_name, app->run_id, app->callback_data); - app->state = kDIALStatusStopped; - mg_printf(conn, "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Access-Control-Allow-Origin: %s\r\n" - "\r\n", - origin_header); + app = *find_app(ds, app_name); + + // update the application state + if (app) { + app->state = app->callbacks.status_cb(ds, app_name, app->run_id, + &canStop, app->callback_data); + } + + if (!app || app->state == kDIALStatusStopped) { + mg_send_http_error(conn, 404, "Not Found", "Not Found"); + } else { + app->callbacks.stop_cb(ds, app_name, app->run_id, app->callback_data); + app->state = kDIALStatusStopped; + mg_printf(conn, "HTTP/1.1 200 OK\r\n" + "Content-Type: text/plain\r\n" + "Access-Control-Allow-Origin: %s\r\n" + "\r\n", + origin_header); + } } ds_unlock(ds); } diff --git a/server/dial_server.h b/server/dial_server.h index f8f97c0..7890dcf 100644 --- a/server/dial_server.h +++ b/server/dial_server.h @@ -41,13 +41,17 @@ typedef enum { kDIALStatusStopped, kDIALStatusHide, - kDIALStatusRunning + kDIALStatusRunning, + kDIALStatusErrorNotImplemented, + kDIALStatusErrorForbidden, + kDIALStatusErrorUnauth, + kDIALStatusError } DIALStatus; /* * DIAL version that is reported via in the status response. */ -#define DIAL_VERSION ("\"2.1\"") +#define DIAL_VERSION ("\"2.2\"") /* * The maximum DIAL payload accepted per the DIAL 1.6.1 specification. @@ -75,7 +79,8 @@ typedef void * DIAL_run_t; * DIAL start callback */ typedef DIALStatus (*DIAL_app_start_cb)(DIALServer *ds, const char *app_name, - const char *payload, const char *additionalDataUrl, + const char *payload, const char *query_string, + const char *additionalDataUrl, DIAL_run_t *run_id, void *callback_data); /* diff --git a/server/main.c b/server/main.c index 7712642..fcc64c2 100644 --- a/server/main.c +++ b/server/main.c @@ -42,6 +42,7 @@ #include "url_lib.h" #include "nf_callbacks.h" +#include "system_callbacks.h" #define BUFSIZE 256 @@ -60,6 +61,8 @@ static char spUuid[BUFSIZE]; extern bool wakeOnWifiLan; static int gDialPort; +char spSleepPassword[BUFSIZE]; + static char *spAppYouTube = "chrome"; static char *spAppYouTubeMatch = "chrome.*google-chrome-dial"; static char *spAppYouTubeExecutable = "/opt/google/chrome/google-chrome"; @@ -193,7 +196,8 @@ int shouldRelaunch( } static DIALStatus youtube_start(DIALServer *ds, const char *appname, - const char *payload, const char *additionalDataUrl, + const char *payload, const char* query_string, + const char *additionalDataUrl, DIAL_run_t *run_id, void *callback_data) { printf("\n\n ** LAUNCH YouTube ** with payload %s\n\n", payload); @@ -277,9 +281,11 @@ void runDial(void) cb_nf.stop_cb = netflix_stop; cb_nf.status_cb = netflix_status; struct DIALAppCallbacks cb_yt = {youtube_start, youtube_hide, youtube_stop, youtube_status}; + struct DIALAppCallbacks cb_system = {system_start, system_hide, NULL, system_status}; DIAL_register_app(ds, "Netflix", &cb_nf, NULL, 1, ".netflix.com"); DIAL_register_app(ds, "YouTube", &cb_yt, NULL, 1, ".youtube.com"); + DIAL_register_app(ds, "system", &cb_system, NULL, 1, ""); DIAL_start(ds); gDialPort = DIAL_get_port(ds); @@ -321,6 +327,9 @@ static void processOption( int index, char * pOption ) exit(1); } break; + case 6: + setValue( pOption, spSleepPassword ); + break; default: // Should not get here fprintf( stderr, "Option %d not valid\n", index); diff --git a/server/makefile b/server/makefile index fd21ae4..1866e7d 100644 --- a/server/makefile +++ b/server/makefile @@ -3,7 +3,7 @@ CC=$(TARGET)gcc .PHONY: clean .DEFAULT_GOAL=all -OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o +OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o system_callbacks.o HEADERS := $(wildcard *.h) %.c: $(HEADERS) @@ -20,7 +20,7 @@ nf_callbacks_lib: nf_callbacks.o dialserver: nf_callbacks_lib $(OBJS) - $(CC) -Wall -Werror -Wl,-rpath,. -g $(OBJS) -ldl -lpthread -L. -lnfCallbacks -o dialserver + $(CC) -Wall -Werror -Wl,-rpath,. -g $(OBJS) -ldl -lpthread -lrt -L. -lnfCallbacks -o dialserver test: make -C tests diff --git a/server/nf_callbacks.c b/server/nf_callbacks.c index fa702a9..ce85b5a 100644 --- a/server/nf_callbacks.c +++ b/server/nf_callbacks.c @@ -22,7 +22,8 @@ int shouldRelaunch(DIALServer *pServer, const char *pAppName, const char *args ) pid_t runApplication( const char * const args[], DIAL_run_t *run_id ); DIALStatus netflix_start(DIALServer *ds, const char *appname, - const char *payload, const char *additionalDataUrl, + const char *payload, const char* query_string, + const char *additionalDataUrl, DIAL_run_t *run_id, void *callback_data) { int shouldRelaunchApp = 0; int appPid = 0; diff --git a/server/nf_callbacks.h b/server/nf_callbacks.h index 3159046..95b0648 100644 --- a/server/nf_callbacks.h +++ b/server/nf_callbacks.h @@ -29,7 +29,8 @@ #include "dial_server.h" DIALStatus netflix_start(DIALServer *ds, const char *appname, - const char *payload, const char *additionalDataUrl, + const char *payload, const char* query_string, + const char *additionalDataUrl, DIAL_run_t *run_id, void *callback_data); diff --git a/server/system_callbacks.c b/server/system_callbacks.c new file mode 100644 index 0000000..cf03f72 --- /dev/null +++ b/server/system_callbacks.c @@ -0,0 +1,53 @@ +#include +#include +#include "system_callbacks.h" + +extern char spSleepPassword[]; + +DIALStatus system_start(DIALServer *ds, const char *appname, const char *payload, const char* query_string, + const char *additionalDataUrl, DIAL_run_t *run_id, void *callback_data) { + + /* Can't launch system app */ + if (0 == query_string) { + return kDIALStatusErrorForbidden; + } + + /* Only sleep is supported action */ + if (0 != strncmp( query_string, "action=sleep", sizeof("action=sleep") - 1)) { + return kDIALStatusErrorNotImplemented; // Only "sleep" is valid action + } + + if (strlen(spSleepPassword) != 0) { + + /* Look for key */ + char *key_value; + if ( (key_value = strchr(query_string, '&')) == '\0' ) { + return kDIALStatusErrorForbidden; // No key specified. + } + + /* Look for sleep password */ + *key_value++ = '\0'; + char str[512]; + snprintf(str, 512, "key=%s", spSleepPassword); + printf(" str: %s \n", str); + if (0 != strncmp( key_value, "key=TEST", sizeof("key=TEST") - 1)) { + return kDIALStatusErrorUnauth; // Invalid key + } + } + /* Sleep not implemented in reference implementation */ + return kDIALStatusErrorNotImplemented; +} + +DIALStatus system_hide(DIALServer *ds, const char *app_name, + DIAL_run_t *run_id, void *callback_data) { + // Always hidden + return kDIALStatusHide; +} + +DIALStatus system_status(DIALServer *ds, const char *appname, + DIAL_run_t run_id, int* pCanStop, void *callback_data) { + // Always hidden + return kDIALStatusHide; +} + + diff --git a/server/system_callbacks.h b/server/system_callbacks.h new file mode 100644 index 0000000..db3f369 --- /dev/null +++ b/server/system_callbacks.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018 Netflix, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY NETFLIX, INC. AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NETFLIX OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSTEM_CALLBACKS_H_ +#define SYSTEM_CALLBACKS_H_ + +#include "dial_server.h" + +DIALStatus system_start(DIALServer *ds, const char *appname, + const char *payload, const char* query_string, + const char *additionalDataUrl, + DIAL_run_t *run_id, void *callback_data); + + +DIALStatus system_hide(DIALServer *ds, const char *app_name, + DIAL_run_t *run_id, void *callback_data); + +DIALStatus system_status(DIALServer *ds, const char *appname, + DIAL_run_t run_id, int* pCanStop, void *callback_data); + + + + + + +#endif /* SYSTEM_CALLBACKS_H_ */