mirror of
https://github.com/Netflix/dial-reference.git
synced 2026-06-08 10:59:59 +00:00
turned netflix callbacks into shared library
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,4 +1,6 @@
|
|||||||
|
*.so
|
||||||
*.o
|
*.o
|
||||||
client/dialclient
|
client/dialclient
|
||||||
server/dialserver
|
server/dialserver
|
||||||
server/tests/run_tests
|
server/tests/run_tests
|
||||||
|
client/report.html
|
||||||
|
|||||||
@@ -50,10 +50,6 @@
|
|||||||
#define WAKE_OPTION_LONG "--wake-on-wifi-len"
|
#define WAKE_OPTION_LONG "--wake-on-wifi-len"
|
||||||
#define WAKE_DESCRIPTION "Enable wake on wifi/len. Value: on/off. Default (on)"
|
#define WAKE_DESCRIPTION "Enable wake on wifi/len. Value: on/off. Default (on)"
|
||||||
|
|
||||||
#define NFMANAGER_OPTION "-A"
|
|
||||||
#define NFMANAGER_OPTION_LONG "--netflix-app-manager"
|
|
||||||
#define NFMANAGER_DESCRIPTION "Enable interface to netflix app manager."
|
|
||||||
|
|
||||||
struct dial_options
|
struct dial_options
|
||||||
{
|
{
|
||||||
const char * pOption;
|
const char * pOption;
|
||||||
@@ -92,11 +88,6 @@ struct dial_options gDialOptions[] =
|
|||||||
WAKE_OPTION,
|
WAKE_OPTION,
|
||||||
WAKE_OPTION_LONG,
|
WAKE_OPTION_LONG,
|
||||||
WAKE_DESCRIPTION
|
WAKE_DESCRIPTION
|
||||||
},
|
|
||||||
{
|
|
||||||
NFMANAGER_OPTION,
|
|
||||||
NFMANAGER_OPTION_LONG,
|
|
||||||
NFMANAGER_DESCRIPTION
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
311
server/jsmn.c
311
server/jsmn.c
@@ -1,311 +0,0 @@
|
|||||||
#include "jsmn.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allocates a fresh unused token from the token pull.
|
|
||||||
*/
|
|
||||||
static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser,
|
|
||||||
jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *tok;
|
|
||||||
if (parser->toknext >= num_tokens) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
tok = &tokens[parser->toknext++];
|
|
||||||
tok->start = tok->end = -1;
|
|
||||||
tok->size = 0;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
tok->parent = -1;
|
|
||||||
#endif
|
|
||||||
return tok;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills token type and boundaries.
|
|
||||||
*/
|
|
||||||
static void jsmn_fill_token(jsmntok_t *token, jsmntype_t type,
|
|
||||||
int start, int end) {
|
|
||||||
token->type = type;
|
|
||||||
token->start = start;
|
|
||||||
token->end = end;
|
|
||||||
token->size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next available token with JSON primitive.
|
|
||||||
*/
|
|
||||||
static int jsmn_parse_primitive(jsmn_parser *parser, const char *js,
|
|
||||||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *token;
|
|
||||||
int start;
|
|
||||||
|
|
||||||
start = parser->pos;
|
|
||||||
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
switch (js[parser->pos]) {
|
|
||||||
#ifndef JSMN_STRICT
|
|
||||||
/* In strict mode primitive must be followed by "," or "}" or "]" */
|
|
||||||
case ':':
|
|
||||||
#endif
|
|
||||||
case '\t' : case '\r' : case '\n' : case ' ' :
|
|
||||||
case ',' : case ']' : case '}' :
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* In strict mode primitive must be followed by a comma/object/array */
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
found:
|
|
||||||
if (tokens == NULL) {
|
|
||||||
parser->pos--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
parser->pos--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fills next token with JSON string.
|
|
||||||
*/
|
|
||||||
static int jsmn_parse_string(jsmn_parser *parser, const char *js,
|
|
||||||
size_t len, jsmntok_t *tokens, size_t num_tokens) {
|
|
||||||
jsmntok_t *token;
|
|
||||||
|
|
||||||
int start = parser->pos;
|
|
||||||
|
|
||||||
parser->pos++;
|
|
||||||
|
|
||||||
/* Skip starting quote */
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
char c = js[parser->pos];
|
|
||||||
|
|
||||||
/* Quote: end of string */
|
|
||||||
if (c == '\"') {
|
|
||||||
if (tokens == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL) {
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
}
|
|
||||||
jsmn_fill_token(token, JSMN_STRING, start+1, parser->pos);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Backslash: Quoted symbol expected */
|
|
||||||
if (c == '\\' && parser->pos + 1 < len) {
|
|
||||||
int i;
|
|
||||||
parser->pos++;
|
|
||||||
switch (js[parser->pos]) {
|
|
||||||
/* Allowed escaped symbols */
|
|
||||||
case '\"': case '/' : case '\\' : case 'b' :
|
|
||||||
case 'f' : case 'r' : case 'n' : case 't' :
|
|
||||||
break;
|
|
||||||
/* Allows escaped symbol \uXXXX */
|
|
||||||
case 'u':
|
|
||||||
parser->pos++;
|
|
||||||
for(i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; i++) {
|
|
||||||
/* If it isn't a hex character we have an error */
|
|
||||||
if(!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */
|
|
||||||
(js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */
|
|
||||||
(js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
parser->pos++;
|
|
||||||
}
|
|
||||||
parser->pos--;
|
|
||||||
break;
|
|
||||||
/* Unexpected symbol */
|
|
||||||
default:
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parser->pos = start;
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse JSON string and fill tokens.
|
|
||||||
*/
|
|
||||||
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
|
||||||
jsmntok_t *tokens, unsigned int num_tokens) {
|
|
||||||
int r;
|
|
||||||
int i;
|
|
||||||
jsmntok_t *token;
|
|
||||||
int count = parser->toknext;
|
|
||||||
|
|
||||||
for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) {
|
|
||||||
char c;
|
|
||||||
jsmntype_t type;
|
|
||||||
|
|
||||||
c = js[parser->pos];
|
|
||||||
switch (c) {
|
|
||||||
case '{': case '[':
|
|
||||||
count++;
|
|
||||||
if (tokens == NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token = jsmn_alloc_token(parser, tokens, num_tokens);
|
|
||||||
if (token == NULL)
|
|
||||||
return JSMN_ERROR_NOMEM;
|
|
||||||
if (parser->toksuper != -1) {
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
token->parent = parser->toksuper;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
token->start = parser->pos;
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
break;
|
|
||||||
case '}': case ']':
|
|
||||||
if (tokens == NULL)
|
|
||||||
break;
|
|
||||||
type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
if (parser->toknext < 1) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
token = &tokens[parser->toknext - 1];
|
|
||||||
for (;;) {
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
if (token->type != type) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
token->end = parser->pos + 1;
|
|
||||||
parser->toksuper = token->parent;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (token->parent == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
token = &tokens[token->parent];
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
token = &tokens[i];
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
if (token->type != type) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
parser->toksuper = -1;
|
|
||||||
token->end = parser->pos + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Error if unmatched closing bracket */
|
|
||||||
if (i == -1) return JSMN_ERROR_INVAL;
|
|
||||||
for (; i >= 0; i--) {
|
|
||||||
token = &tokens[i];
|
|
||||||
if (token->start != -1 && token->end == -1) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
case '\"':
|
|
||||||
r = jsmn_parse_string(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r < 0) return r;
|
|
||||||
count++;
|
|
||||||
if (parser->toksuper != -1 && tokens != NULL)
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
break;
|
|
||||||
case '\t' : case '\r' : case '\n' : case ' ':
|
|
||||||
break;
|
|
||||||
case ':':
|
|
||||||
parser->toksuper = parser->toknext - 1;
|
|
||||||
break;
|
|
||||||
case ',':
|
|
||||||
if (tokens != NULL && parser->toksuper != -1 &&
|
|
||||||
tokens[parser->toksuper].type != JSMN_ARRAY &&
|
|
||||||
tokens[parser->toksuper].type != JSMN_OBJECT) {
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
parser->toksuper = tokens[parser->toksuper].parent;
|
|
||||||
#else
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) {
|
|
||||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
|
||||||
parser->toksuper = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* In strict mode primitives are: numbers and booleans */
|
|
||||||
case '-': case '0': case '1' : case '2': case '3' : case '4':
|
|
||||||
case '5': case '6': case '7' : case '8': case '9':
|
|
||||||
case 't': case 'f': case 'n' :
|
|
||||||
/* And they must not be keys of the object */
|
|
||||||
if (tokens != NULL && parser->toksuper != -1) {
|
|
||||||
jsmntok_t *t = &tokens[parser->toksuper];
|
|
||||||
if (t->type == JSMN_OBJECT ||
|
|
||||||
(t->type == JSMN_STRING && t->size != 0)) {
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* In non-strict mode every unquoted value is a primitive */
|
|
||||||
default:
|
|
||||||
#endif
|
|
||||||
r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens);
|
|
||||||
if (r < 0) return r;
|
|
||||||
count++;
|
|
||||||
if (parser->toksuper != -1 && tokens != NULL)
|
|
||||||
tokens[parser->toksuper].size++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
#ifdef JSMN_STRICT
|
|
||||||
/* Unexpected char in strict mode */
|
|
||||||
default:
|
|
||||||
return JSMN_ERROR_INVAL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokens != NULL) {
|
|
||||||
for (i = parser->toknext - 1; i >= 0; i--) {
|
|
||||||
/* Unmatched opened object or array */
|
|
||||||
if (tokens[i].start != -1 && tokens[i].end == -1) {
|
|
||||||
return JSMN_ERROR_PART;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new parser based over a given buffer with an array of tokens
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
void jsmn_init(jsmn_parser *parser) {
|
|
||||||
parser->pos = 0;
|
|
||||||
parser->toknext = 0;
|
|
||||||
parser->toksuper = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#ifndef __JSMN_H_
|
|
||||||
#define __JSMN_H_
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON type identifier. Basic types are:
|
|
||||||
* o Object
|
|
||||||
* o Array
|
|
||||||
* o String
|
|
||||||
* o Other primitive: number, boolean (true/false) or null
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
JSMN_UNDEFINED = 0,
|
|
||||||
JSMN_OBJECT = 1,
|
|
||||||
JSMN_ARRAY = 2,
|
|
||||||
JSMN_STRING = 3,
|
|
||||||
JSMN_PRIMITIVE = 4
|
|
||||||
} jsmntype_t;
|
|
||||||
|
|
||||||
enum jsmnerr {
|
|
||||||
/* Not enough tokens were provided */
|
|
||||||
JSMN_ERROR_NOMEM = -1,
|
|
||||||
/* Invalid character inside JSON string */
|
|
||||||
JSMN_ERROR_INVAL = -2,
|
|
||||||
/* The string is not a full JSON packet, more bytes expected */
|
|
||||||
JSMN_ERROR_PART = -3
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON token description.
|
|
||||||
* @param type type (object, array, string etc.)
|
|
||||||
* @param start start position in JSON data string
|
|
||||||
* @param end end position in JSON data string
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
jsmntype_t type;
|
|
||||||
int start;
|
|
||||||
int end;
|
|
||||||
int size;
|
|
||||||
#ifdef JSMN_PARENT_LINKS
|
|
||||||
int parent;
|
|
||||||
#endif
|
|
||||||
} jsmntok_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON parser. Contains an array of token blocks available. Also stores
|
|
||||||
* the string being parsed now and current position in that string
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int pos; /* offset in the JSON string */
|
|
||||||
unsigned int toknext; /* next token to allocate */
|
|
||||||
int toksuper; /* superior token node, e.g parent object or array */
|
|
||||||
} jsmn_parser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create JSON parser over an array of tokens
|
|
||||||
*/
|
|
||||||
void jsmn_init(jsmn_parser *parser);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run JSON parser. It parses a JSON data string into and array of tokens, each describing
|
|
||||||
* a single JSON object.
|
|
||||||
*/
|
|
||||||
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
|
|
||||||
jsmntok_t *tokens, unsigned int num_tokens);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __JSMN_H_ */
|
|
||||||
115
server/main.c
115
server/main.c
@@ -41,28 +41,25 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "url_lib.h"
|
#include "url_lib.h"
|
||||||
#include "nf_appmanager.h"
|
#include "nf_callbacks.h"
|
||||||
|
|
||||||
#define BUFSIZE 256
|
#define BUFSIZE 256
|
||||||
|
|
||||||
static char *spAppNetflix = "netflix"; // name of the netflix executable
|
char *spAppNetflix = "netflix"; // name of the netflix executable
|
||||||
static char *spDefaultNetflix = "../../../src/platform/qt/netflix";
|
static char *spDefaultNetflix = "../../../src/platform/qt/netflix";
|
||||||
static char *spDefaultData="../../../src/platform/qt/data";
|
static char *spDefaultData="../../../src/platform/qt/data";
|
||||||
static char *spNfDataDir = "NF_DATA_DIR=";
|
static char *spNfDataDir = "NF_DATA_DIR=";
|
||||||
static char *defaultLaunchParam = "source_type=12";
|
|
||||||
static char *spDefaultFriendlyName = "DIAL server sample";
|
static char *spDefaultFriendlyName = "DIAL server sample";
|
||||||
static char *spDefaultModelName = "NOT A VALID MODEL NAME";
|
static char *spDefaultModelName = "NOT A VALID MODEL NAME";
|
||||||
static char *spDefaultUuid = "deadbeef-dead-beef-dead-beefdeadbeef";
|
static char *spDefaultUuid = "deadbeef-dead-beef-dead-beefdeadbeef";
|
||||||
static char spDataDir[BUFSIZE];
|
static char spDataDir[BUFSIZE];
|
||||||
static char spNetflix[BUFSIZE];
|
char spNetflix[BUFSIZE];
|
||||||
static char spFriendlyName[BUFSIZE];
|
static char spFriendlyName[BUFSIZE];
|
||||||
static char spModelName[BUFSIZE];
|
static char spModelName[BUFSIZE];
|
||||||
static char spUuid[BUFSIZE];
|
static char spUuid[BUFSIZE];
|
||||||
extern bool wakeOnWifiLan;
|
extern bool wakeOnWifiLan;
|
||||||
static int gDialPort;
|
static int gDialPort;
|
||||||
|
|
||||||
static bool sUseNFAppManager=false;
|
|
||||||
|
|
||||||
static char *spAppYouTube = "chrome";
|
static char *spAppYouTube = "chrome";
|
||||||
static char *spAppYouTubeMatch = "chrome.*google-chrome-dial";
|
static char *spAppYouTubeMatch = "chrome.*google-chrome-dial";
|
||||||
static char *spAppYouTubeExecutable = "/opt/google/chrome/google-chrome";
|
static char *spAppYouTubeExecutable = "/opt/google/chrome/google-chrome";
|
||||||
@@ -71,10 +68,7 @@ static char *spYouTubePS3UserAgent = "--user-agent="
|
|||||||
"Chrome/19.0.1048.0 LeanbackShell/01.00.01.73 QA Safari/535.22 Sony PS3/ "
|
"Chrome/19.0.1048.0 LeanbackShell/01.00.01.73 QA Safari/535.22 Sony PS3/ "
|
||||||
"(PS3, , no, CH)";
|
"(PS3, , no, CH)";
|
||||||
|
|
||||||
// Adding 20 bytes for prepended source_type for Netflix
|
int doesMatch( char* pzExp, char* pzStr)
|
||||||
static char sQueryParam[DIAL_MAX_PAYLOAD+DIAL_MAX_ADDITIONALURL+40];
|
|
||||||
|
|
||||||
static int doesMatch( char* pzExp, char* pzStr)
|
|
||||||
{
|
{
|
||||||
regex_t exp;
|
regex_t exp;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -109,7 +103,7 @@ void signalHandler(int signal)
|
|||||||
* name) and command line (if needed).
|
* name) and command line (if needed).
|
||||||
* Implementors can override this function with an equivalent.
|
* Implementors can override this function with an equivalent.
|
||||||
*/
|
*/
|
||||||
static int isAppRunning( char *pzName, char *pzCommandPattern ) {
|
int isAppRunning( char *pzName, char *pzCommandPattern ) {
|
||||||
DIR* proc_fd = opendir("/proc");
|
DIR* proc_fd = opendir("/proc");
|
||||||
if( proc_fd != NULL ) {
|
if( proc_fd != NULL ) {
|
||||||
struct dirent* procEntry;
|
struct dirent* procEntry;
|
||||||
@@ -163,7 +157,7 @@ static int isAppRunning( char *pzName, char *pzCommandPattern ) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static pid_t runApplication( const char * const args[], DIAL_run_t *run_id ) {
|
pid_t runApplication( const char * const args[], DIAL_run_t *run_id ) {
|
||||||
pid_t pid = fork();
|
pid_t pid = fork();
|
||||||
if (pid != -1) {
|
if (pid != -1) {
|
||||||
if (!pid) { // child
|
if (!pid) { // child
|
||||||
@@ -190,7 +184,7 @@ static pid_t runApplication( const char * const args[], DIAL_run_t *run_id ) {
|
|||||||
* If they match, return false
|
* If they match, return false
|
||||||
* If they don't match, return true
|
* If they don't match, return true
|
||||||
*/
|
*/
|
||||||
static int shouldRelaunch(
|
int shouldRelaunch(
|
||||||
DIALServer *pServer,
|
DIALServer *pServer,
|
||||||
const char *pAppName,
|
const char *pAppName,
|
||||||
const char *args )
|
const char *args )
|
||||||
@@ -244,79 +238,6 @@ static void youtube_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static DIALStatus netflix_start(DIALServer *ds, const char *appname,
|
|
||||||
const char *payload, const char *additionalDataUrl,
|
|
||||||
DIAL_run_t *run_id, void *callback_data) {
|
|
||||||
int shouldRelaunchApp = 0;
|
|
||||||
int appPid = 0;
|
|
||||||
|
|
||||||
// only launch Netflix if it isn't running
|
|
||||||
appPid = isAppRunning( spAppNetflix, NULL );
|
|
||||||
shouldRelaunchApp = shouldRelaunch( ds, appname, payload );
|
|
||||||
|
|
||||||
// construct the payload to determine if it has changed from the previous launch
|
|
||||||
memset( sQueryParam, 0, sizeof(sQueryParam) );
|
|
||||||
strcat( sQueryParam, defaultLaunchParam );
|
|
||||||
if(strlen(payload))
|
|
||||||
{
|
|
||||||
char * pUrlEncodedParams;
|
|
||||||
pUrlEncodedParams = url_encode( payload );
|
|
||||||
if( pUrlEncodedParams )
|
|
||||||
{
|
|
||||||
strcat( sQueryParam, "&dial=");
|
|
||||||
strcat( sQueryParam, pUrlEncodedParams );
|
|
||||||
free( pUrlEncodedParams );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strlen(additionalDataUrl)){
|
|
||||||
strcat(sQueryParam, "&");
|
|
||||||
strcat(sQueryParam, additionalDataUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("appPid = %s, shouldRelaunch = %s queryParams = %s\n",
|
|
||||||
appPid?"TRUE":"FALSE",
|
|
||||||
shouldRelaunchApp?"TRUE":"FALSE",
|
|
||||||
sQueryParam );
|
|
||||||
|
|
||||||
// if its not running, launch it. The Netflix application should
|
|
||||||
// never be relaunched
|
|
||||||
if( !appPid )
|
|
||||||
{
|
|
||||||
const char * const netflix_args[] = {spNetflix, "-Q", sQueryParam, 0};
|
|
||||||
return runApplication( netflix_args, run_id );
|
|
||||||
}
|
|
||||||
else return kDIALStatusRunning;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DIALStatus netflix_hide(DIALServer *ds, const char *app_name,
|
|
||||||
DIAL_run_t *run_id, void *callback_data)
|
|
||||||
{
|
|
||||||
return (isAppRunning( spAppNetflix, NULL )) ? kDIALStatusRunning : kDIALStatusStopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DIALStatus netflix_status(DIALServer *ds, const char *appname,
|
|
||||||
DIAL_run_t run_id, int* pCanStop, void *callback_data) {
|
|
||||||
// Netflix application can stop
|
|
||||||
*pCanStop = 1;
|
|
||||||
|
|
||||||
waitpid((pid_t)(long)run_id, NULL, WNOHANG); // reap child
|
|
||||||
|
|
||||||
return isAppRunning( spAppNetflix, NULL ) ? kDIALStatusRunning : kDIALStatusStopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void netflix_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
|
||||||
void *callback_data) {
|
|
||||||
int pid;
|
|
||||||
pid = isAppRunning( spAppNetflix, NULL );
|
|
||||||
if( pid )
|
|
||||||
{
|
|
||||||
printf("Killing pid %d\n", pid);
|
|
||||||
kill((pid_t)pid, SIGTERM);
|
|
||||||
waitpid((pid_t)pid, NULL, 0); // reap child
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_ssdp(int port, const char *pFriendlyName, const char * pModelName, const char *pUuid);
|
void run_ssdp(int port, const char *pFriendlyName, const char * pModelName, const char *pUuid);
|
||||||
|
|
||||||
static void printUsage()
|
static void printUsage()
|
||||||
@@ -351,17 +272,10 @@ void runDial(void)
|
|||||||
DIALServer *ds;
|
DIALServer *ds;
|
||||||
ds = DIAL_create();
|
ds = DIAL_create();
|
||||||
struct DIALAppCallbacks cb_nf;
|
struct DIALAppCallbacks cb_nf;
|
||||||
if (sUseNFAppManager){
|
cb_nf.start_cb = netflix_start;
|
||||||
cb_nf.start_cb = am_netflix_start;
|
cb_nf.hide_cb = netflix_hide;
|
||||||
cb_nf.hide_cb = am_netflix_hide;
|
cb_nf.stop_cb = netflix_stop;
|
||||||
cb_nf.stop_cb = am_netflix_stop;
|
cb_nf.status_cb = netflix_status;
|
||||||
cb_nf.status_cb = am_netflix_status;
|
|
||||||
}else{
|
|
||||||
cb_nf.start_cb = netflix_start;
|
|
||||||
cb_nf.hide_cb = netflix_hide;
|
|
||||||
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_yt = {youtube_start, youtube_hide, youtube_stop, youtube_status};
|
||||||
|
|
||||||
DIAL_register_app(ds, "Netflix", &cb_nf, NULL, 1, ".netflix.com");
|
DIAL_register_app(ds, "Netflix", &cb_nf, NULL, 1, ".netflix.com");
|
||||||
@@ -407,13 +321,6 @@ static void processOption( int index, char * pOption )
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6:
|
|
||||||
if (strcmp(pOption, "true")==0){
|
|
||||||
sUseNFAppManager=true;
|
|
||||||
}else{
|
|
||||||
sUseNFAppManager=false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// Should not get here
|
// Should not get here
|
||||||
fprintf( stderr, "Option %d not valid\n", index);
|
fprintf( stderr, "Option %d not valid\n", index);
|
||||||
|
|||||||
@@ -3,23 +3,27 @@ CC=$(TARGET)gcc
|
|||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
.DEFAULT_GOAL=all
|
.DEFAULT_GOAL=all
|
||||||
|
|
||||||
OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o LinuxInterfaces.o nf_appmanager.o mq_ipc.o jsmn.o
|
OBJS := main.o dial_server.o mongoose.o quick_ssdp.o url_lib.o dial_data.o LinuxInterfaces.o
|
||||||
HEADERS := $(wildcard *.h)
|
HEADERS := $(wildcard *.h)
|
||||||
|
|
||||||
%.c: $(HEADERS)
|
%.c: $(HEADERS)
|
||||||
|
|
||||||
%.o: %.c $(HEADERS)
|
%.o: %.c $(HEADERS)
|
||||||
$(CC) -Wall -Werror -g -std=gnu99 $(CFLAGS) -c $*.c -o $*.o
|
# $(CC) -Wall -Werror -g -std=gnu99 $(CFLAGS) -c $*.c -o $*.o
|
||||||
|
$(CC) -Wall -g -std=gnu99 $(CFLAGS) -c $*.c -o $*.o
|
||||||
|
|
||||||
all: dialserver test
|
all: dialserver test
|
||||||
|
|
||||||
dialserver: $(OBJS)
|
nf_callbacks_lib: nf_callbacks.o
|
||||||
$(CC) -Wall -Werror -g $(OBJS) -ldl -lpthread -lrt -o dialserver
|
$(CC) -Wall -Werror -g nf_callbacks.o -o libnfCallbacks.so --shared
|
||||||
|
|
||||||
|
dialserver: nf_callbacks_lib $(OBJS)
|
||||||
|
$(CC) -Wall -Werror -Wl,-rpath,. -g $(OBJS) -ldl -lpthread -lrt -L. -lnfCallbacks -o dialserver
|
||||||
|
|
||||||
test:
|
test:
|
||||||
make -C tests
|
make -C tests
|
||||||
./tests/run_tests
|
./tests/run_tests
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o dialserver
|
rm -f *.o dialserver *.so
|
||||||
make -C tests clean
|
make -C tests clean
|
||||||
|
|||||||
132
server/mq_ipc.c
132
server/mq_ipc.c
@@ -1,132 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "mq_ipc.h"
|
|
||||||
|
|
||||||
#define PMODE 0655
|
|
||||||
#define IPC_MAX_MSG_SIZE 5*1024 // Account for 4kb DIAL payload
|
|
||||||
#define IPC_MAX_MSG_COUNT 1
|
|
||||||
|
|
||||||
static mqd_t mClientServer=-1;
|
|
||||||
static mqd_t mServerClient=-1;
|
|
||||||
|
|
||||||
int createMessageQ(const char* fd, int flags)
|
|
||||||
{
|
|
||||||
struct mq_attr attr;
|
|
||||||
attr.mq_maxmsg = IPC_MAX_MSG_SIZE;
|
|
||||||
attr.mq_msgsize = IPC_MAX_MSG_COUNT;
|
|
||||||
|
|
||||||
mqd_t handle = mq_open(fd, flags, PMODE, &attr);
|
|
||||||
if (handle == -1) {
|
|
||||||
printf("Failed to open Q at %s: %s \n", fd, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sendInternal(const char* payload, int timeoutInSec, bool block)
|
|
||||||
{
|
|
||||||
if (mClientServer == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block) {
|
|
||||||
if (mq_send(mClientServer, payload, strlen(payload)+1, 0) == -1) {
|
|
||||||
printf("Failed to send message: %s \n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
printf("mq message sent.\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct timespec tm;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &tm);
|
|
||||||
tm.tv_sec += timeoutInSec;
|
|
||||||
|
|
||||||
if (mq_timedsend(mClientServer, payload, strlen(payload)+1, 0, &tm) == -1) {
|
|
||||||
printf("Failed to send message: %s \n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int receiveInternal(char* buffer, int bufferSize, int timeoutInSec, bool block)
|
|
||||||
{
|
|
||||||
/* mqd_t qFd = getMessageQ(fd); */
|
|
||||||
|
|
||||||
if (mServerClient == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (block) {
|
|
||||||
if (mq_receive(mServerClient, buffer, bufferSize, 0) == -1) {
|
|
||||||
printf("Failed to receive message: %s \n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct timespec tm;
|
|
||||||
clock_gettime(CLOCK_REALTIME, &tm);
|
|
||||||
tm.tv_sec += timeoutInSec;
|
|
||||||
|
|
||||||
if (mq_timedreceive(mServerClient, buffer, bufferSize, 0, &tm) == -1) {
|
|
||||||
printf("Failed to receive message: %s \n", strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//============== public APIs ===================
|
|
||||||
|
|
||||||
int mq_ipc_connect(const char* clientServer, const char* serverClient)
|
|
||||||
{
|
|
||||||
// Write-only to send message to server
|
|
||||||
mClientServer = createMessageQ(clientServer, O_WRONLY);
|
|
||||||
|
|
||||||
// Read-only to receive messages from server.
|
|
||||||
mServerClient = createMessageQ(serverClient, O_RDONLY);
|
|
||||||
|
|
||||||
if ((mServerClient == -1 ) || (mClientServer == -1)) {
|
|
||||||
printf(" failed to conncet to server \n");
|
|
||||||
return -1;
|
|
||||||
}else{
|
|
||||||
printf("mq connected.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mq_ipc_disconnect()
|
|
||||||
{
|
|
||||||
mq_close(mClientServer);
|
|
||||||
mq_close(mServerClient);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mq_ipc_send(const char* payload)
|
|
||||||
{
|
|
||||||
return sendInternal(payload, 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mq_ipc_receive(char* buffer, int bufferSize)
|
|
||||||
{
|
|
||||||
return receiveInternal(buffer, bufferSize, 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mq_ipc_send_timed(const char* payload, int timeoutInSec)
|
|
||||||
{
|
|
||||||
return sendInternal(payload, timeoutInSec, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mq_ipc_receive_timed(char* buffer, int bufferSize, int timeoutInSec)
|
|
||||||
{
|
|
||||||
return receiveInternal(buffer, bufferSize, timeoutInSec, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
#ifndef _MQ_IPC_H_
|
|
||||||
#define _MQ_IPC_H_
|
|
||||||
|
|
||||||
#include <fcntl.h> /* For O_* constants */
|
|
||||||
#include <sys/stat.h> /* For mode constants */
|
|
||||||
#include <mqueue.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
int mq_ipc_connect(const char* clientServer, const char* serverClient);
|
|
||||||
int mq_ipc_disconnect();
|
|
||||||
|
|
||||||
int mq_ipc_send(const char* payload);
|
|
||||||
int mq_ipc_receive(char* buffer, int bufferSize);
|
|
||||||
|
|
||||||
int mq_ipc_send_timed(const char* payload, int timeoutInSec);
|
|
||||||
int mq_ipc_receive_timed(char* buffer, int bufferSize, int timeoutInSec);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "nf_appmanager.h"
|
|
||||||
#include "mq_ipc.h"
|
|
||||||
#include "jsmn.h"
|
|
||||||
#include "url_lib.h"
|
|
||||||
|
|
||||||
#define IPC_BUF_SIZE 5*1024 // account for 4kb payload
|
|
||||||
#define IPC_TIMEOUT 2
|
|
||||||
|
|
||||||
static char *defaultLaunchParam = "source_type=12";
|
|
||||||
static char * mq_send_ch = "/fromAppManager";
|
|
||||||
static char * mq_receive_ch = "/toAppManager";
|
|
||||||
static char * mq_tx_msg_base = " {\"args\":\"%s\",\"message\":%d}";
|
|
||||||
|
|
||||||
static int s_run_id = 0;
|
|
||||||
|
|
||||||
typedef enum ControllerCommand {
|
|
||||||
//-----------------------------------
|
|
||||||
// Commands sent to AM
|
|
||||||
//-----------------------------------
|
|
||||||
CMD_CNT_START, // Launch the app
|
|
||||||
CMD_CNT_HIDE, // Suspend app
|
|
||||||
CMD_CNT_START_FROM_HIDE, // Resume app
|
|
||||||
CMD_CNT_STOP=6, // Terminate app nicely because the user killed Netflix.
|
|
||||||
CMD_CNT_GET_STATUS=8, // Provide status of the app
|
|
||||||
}ControllerCommand_t;
|
|
||||||
|
|
||||||
typedef enum ControllerResp {
|
|
||||||
//-----------------------------------
|
|
||||||
// Resp sent from AM
|
|
||||||
//-----------------------------------
|
|
||||||
RESP_OK,
|
|
||||||
RESP_ERR,
|
|
||||||
}ControllerResp_t;
|
|
||||||
|
|
||||||
typedef enum NetflixStatus {
|
|
||||||
//-----------------------------------
|
|
||||||
// Netflix status
|
|
||||||
//-----------------------------------
|
|
||||||
STATUS_NETFLIX_RUNNING,
|
|
||||||
STATUS_NETFLIX_HIDE1,
|
|
||||||
STATUS_NETFLIX_HIDE2,
|
|
||||||
STATUS_NETFLIX_STOPPED,
|
|
||||||
}NetflixStatus_t;
|
|
||||||
|
|
||||||
|
|
||||||
void errorMsg()
|
|
||||||
{
|
|
||||||
printf("\nIn this mode, a matching application manager must be started and listen on the appropriate IPC.\n\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
|
|
||||||
if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
|
|
||||||
strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetflixStatus_t parse_nf_state(char* json_str, jsmntok_t* tokens, int num_tokens)
|
|
||||||
{
|
|
||||||
for (int i=0; i<num_tokens; i++){
|
|
||||||
if (jsoneq(json_str, &tokens[i], "state") == 0) {
|
|
||||||
char * tempStr = strndup(json_str+tokens[i+1].start, tokens[i+1].end - tokens[i+1].start);
|
|
||||||
printf ("token: %s\n", tempStr);
|
|
||||||
NetflixStatus_t status = (NetflixStatus_t) (atoi(tempStr));
|
|
||||||
free(tempStr);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return STATUS_NETFLIX_STOPPED;
|
|
||||||
}
|
|
||||||
|
|
||||||
DIALStatus get_nf_state()
|
|
||||||
{
|
|
||||||
//connect
|
|
||||||
if (mq_ipc_connect(mq_send_ch, mq_receive_ch))
|
|
||||||
exit(1);
|
|
||||||
//send status request
|
|
||||||
char tx_buf[IPC_BUF_SIZE];
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, "", CMD_CNT_GET_STATUS);
|
|
||||||
if (mq_ipc_send_timed(tx_buf, IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
//recieve status
|
|
||||||
char rx_buf[IPC_BUF_SIZE];
|
|
||||||
if(mq_ipc_receive_timed(rx_buf, sizeof(rx_buf), IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
ATRACE("recieved: \n %s\n", rx_buf);
|
|
||||||
|
|
||||||
mq_ipc_disconnect();
|
|
||||||
|
|
||||||
// parse response
|
|
||||||
jsmn_parser json_parser;
|
|
||||||
jsmntok_t tokens[32]; /* We expect no more than 32 tokens */
|
|
||||||
int num_tokens;
|
|
||||||
jsmn_init(&json_parser);
|
|
||||||
num_tokens = jsmn_parse(&json_parser, rx_buf, strlen(rx_buf), tokens, 32);
|
|
||||||
|
|
||||||
// get status
|
|
||||||
NetflixStatus_t am_status = parse_nf_state(rx_buf, tokens, num_tokens);
|
|
||||||
|
|
||||||
switch (am_status){
|
|
||||||
case STATUS_NETFLIX_HIDE1:
|
|
||||||
case STATUS_NETFLIX_HIDE2:
|
|
||||||
// hide state
|
|
||||||
return kDIALStatusHide;
|
|
||||||
break;
|
|
||||||
case STATUS_NETFLIX_STOPPED:
|
|
||||||
// stopped state
|
|
||||||
return kDIALStatusStopped;
|
|
||||||
break;
|
|
||||||
case STATUS_NETFLIX_RUNNING:
|
|
||||||
// running state
|
|
||||||
return kDIALStatusRunning;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// error state
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return kDIALStatusStopped;
|
|
||||||
}
|
|
||||||
|
|
||||||
ControllerResp_t parse_am_status(char* buf)
|
|
||||||
{
|
|
||||||
jsmn_parser json_parser;
|
|
||||||
jsmntok_t tokens[32]; /* We expect no more than 32 tokens */
|
|
||||||
int num_tokens;
|
|
||||||
jsmn_init(&json_parser);
|
|
||||||
num_tokens = jsmn_parse(&json_parser, buf, strlen(buf), tokens, 32);
|
|
||||||
|
|
||||||
for (int i=0; i<num_tokens; i++){
|
|
||||||
if (jsoneq(buf, &tokens[i], "state") == 0) {
|
|
||||||
char * tempStr = strndup(buf+tokens[i+1].start, tokens[i+1].end - tokens[i+1].start);
|
|
||||||
printf ("token: %s\n", tempStr);
|
|
||||||
ControllerResp_t status = (ControllerResp_t) (atoi(tempStr));
|
|
||||||
free(tempStr);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return RESP_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************* public API ********************/
|
|
||||||
DIALStatus am_netflix_start(DIALServer *ds, const char *appname,
|
|
||||||
const char *payload, const char *additionalDataUrl,
|
|
||||||
DIAL_run_t *run_id, void *callback_data)
|
|
||||||
{
|
|
||||||
DIALStatus current_state = get_nf_state();
|
|
||||||
ATRACE("current state: %d\n", current_state);
|
|
||||||
|
|
||||||
ATRACE ("start netflix via app manager..\n");
|
|
||||||
|
|
||||||
char tx_buf[IPC_BUF_SIZE];
|
|
||||||
char rx_buf[IPC_BUF_SIZE];
|
|
||||||
mq_ipc_connect(mq_send_ch, mq_receive_ch);
|
|
||||||
|
|
||||||
char sQueryParam[DIAL_MAX_PAYLOAD+DIAL_MAX_ADDITIONALURL+40];
|
|
||||||
memset( sQueryParam, 0, sizeof(sQueryParam) );
|
|
||||||
strcat( sQueryParam, "-Q ");
|
|
||||||
strcat( sQueryParam, defaultLaunchParam );
|
|
||||||
if(strlen(payload)){
|
|
||||||
char * pUrlEncodedParams;
|
|
||||||
pUrlEncodedParams = url_encode( payload );
|
|
||||||
if( pUrlEncodedParams ){
|
|
||||||
strcat( sQueryParam, "&dial=");
|
|
||||||
strcat( sQueryParam, pUrlEncodedParams );
|
|
||||||
free( pUrlEncodedParams );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(strlen(additionalDataUrl)){
|
|
||||||
strcat(sQueryParam, "&");
|
|
||||||
strcat(sQueryParam, additionalDataUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (current_state) {
|
|
||||||
case kDIALStatusHide:
|
|
||||||
// resume Netflix
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, sQueryParam, CMD_CNT_START_FROM_HIDE);
|
|
||||||
break;
|
|
||||||
case kDIALStatusStopped:
|
|
||||||
// start Netflix
|
|
||||||
s_run_id++;
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, sQueryParam, CMD_CNT_START);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// Already running. Just get status
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, "", CMD_CNT_GET_STATUS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mq_ipc_send_timed(tx_buf, IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
if (mq_ipc_receive_timed(rx_buf, sizeof(rx_buf), IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
ATRACE("recieved: \n %s\n", rx_buf);
|
|
||||||
|
|
||||||
mq_ipc_disconnect();
|
|
||||||
|
|
||||||
return get_nf_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
DIALStatus am_netflix_hide(DIALServer *ds, const char *app_name,
|
|
||||||
DIAL_run_t *run_id, void *callback_data)
|
|
||||||
{
|
|
||||||
//connect
|
|
||||||
if (mq_ipc_connect(mq_send_ch, mq_receive_ch))
|
|
||||||
exit(1);
|
|
||||||
//send status request
|
|
||||||
char tx_buf[IPC_BUF_SIZE];
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, "", CMD_CNT_HIDE);
|
|
||||||
if (mq_ipc_send_timed(tx_buf, IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
//recieve status
|
|
||||||
char rx_buf[IPC_BUF_SIZE];
|
|
||||||
if(mq_ipc_receive_timed(rx_buf, sizeof(rx_buf), IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
ATRACE("recieved: \n %s\n", rx_buf);
|
|
||||||
mq_ipc_disconnect();
|
|
||||||
|
|
||||||
return get_nf_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
DIALStatus am_netflix_status(DIALServer *ds, const char *appname,
|
|
||||||
DIAL_run_t run_id, int* pCanStop, void *callback_data)
|
|
||||||
{
|
|
||||||
return get_nf_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
void am_netflix_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
|
||||||
void *callback_data)
|
|
||||||
{
|
|
||||||
//connect
|
|
||||||
if (mq_ipc_connect(mq_send_ch, mq_receive_ch))
|
|
||||||
exit(1);
|
|
||||||
//send status request
|
|
||||||
char tx_buf[IPC_BUF_SIZE];
|
|
||||||
snprintf(tx_buf, sizeof(tx_buf), mq_tx_msg_base, "", CMD_CNT_STOP);
|
|
||||||
if (mq_ipc_send_timed(tx_buf, IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
//recieve status
|
|
||||||
char rx_buf[IPC_BUF_SIZE];
|
|
||||||
if(mq_ipc_receive_timed(rx_buf, sizeof(rx_buf), IPC_TIMEOUT))
|
|
||||||
errorMsg();
|
|
||||||
ATRACE("recieved: \n %s\n", rx_buf);
|
|
||||||
mq_ipc_disconnect();
|
|
||||||
}
|
|
||||||
93
server/nf_callbacks.c
Normal file
93
server/nf_callbacks.c
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <regex.h>
|
||||||
|
#include "dial_server.h"
|
||||||
|
#include "url_lib.h"
|
||||||
|
|
||||||
|
extern char *spAppNetflix;
|
||||||
|
extern char spNetflix[];
|
||||||
|
static char *defaultLaunchParam = "source_type=12";
|
||||||
|
|
||||||
|
// Adding 20 bytes for prepended source_type for Netflix
|
||||||
|
static char sQueryParam[DIAL_MAX_PAYLOAD+DIAL_MAX_ADDITIONALURL+40];
|
||||||
|
|
||||||
|
int isAppRunning( char *pzName, char *pzCommandPattern );
|
||||||
|
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,
|
||||||
|
DIAL_run_t *run_id, void *callback_data) {
|
||||||
|
int shouldRelaunchApp = 0;
|
||||||
|
int appPid = 0;
|
||||||
|
|
||||||
|
// only launch Netflix if it isn't running
|
||||||
|
appPid = isAppRunning( spAppNetflix, NULL );
|
||||||
|
shouldRelaunchApp = shouldRelaunch( ds, appname, payload );
|
||||||
|
|
||||||
|
// construct the payload to determine if it has changed from the previous launch
|
||||||
|
memset( sQueryParam, 0, sizeof(sQueryParam) );
|
||||||
|
strcat( sQueryParam, defaultLaunchParam );
|
||||||
|
if(strlen(payload))
|
||||||
|
{
|
||||||
|
char * pUrlEncodedParams;
|
||||||
|
pUrlEncodedParams = url_encode( payload );
|
||||||
|
if( pUrlEncodedParams ){
|
||||||
|
strcat( sQueryParam, "&dial=");
|
||||||
|
strcat( sQueryParam, pUrlEncodedParams );
|
||||||
|
free( pUrlEncodedParams );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strlen(additionalDataUrl)){
|
||||||
|
strcat(sQueryParam, "&");
|
||||||
|
strcat(sQueryParam, additionalDataUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("appPid = %s, shouldRelaunch = %s queryParams = %s\n",
|
||||||
|
appPid?"TRUE":"FALSE",
|
||||||
|
shouldRelaunchApp?"TRUE":"FALSE",
|
||||||
|
sQueryParam );
|
||||||
|
|
||||||
|
// if its not running, launch it. The Netflix application should
|
||||||
|
// never be relaunched
|
||||||
|
if( !appPid ){
|
||||||
|
const char * const netflix_args[] = {spNetflix, "-Q", sQueryParam, 0};
|
||||||
|
return runApplication( netflix_args, run_id );
|
||||||
|
}
|
||||||
|
else return kDIALStatusRunning;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIALStatus netflix_hide(DIALServer *ds, const char *app_name,
|
||||||
|
DIAL_run_t *run_id, void *callback_data)
|
||||||
|
{
|
||||||
|
return (isAppRunning( spAppNetflix, NULL )) ? kDIALStatusRunning : kDIALStatusStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
DIALStatus netflix_status(DIALServer *ds, const char *appname,
|
||||||
|
DIAL_run_t run_id, int* pCanStop, void *callback_data) {
|
||||||
|
// Netflix application can stop
|
||||||
|
*pCanStop = 1;
|
||||||
|
|
||||||
|
waitpid((pid_t)(long)run_id, NULL, WNOHANG); // reap child
|
||||||
|
|
||||||
|
return isAppRunning( spAppNetflix, NULL ) ? kDIALStatusRunning : kDIALStatusStopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
void netflix_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
||||||
|
void *callback_data) {
|
||||||
|
int pid;
|
||||||
|
pid = isAppRunning( spAppNetflix, NULL );
|
||||||
|
if( pid ){
|
||||||
|
printf("Killing pid %d\n", pid);
|
||||||
|
kill((pid_t)pid, SIGTERM);
|
||||||
|
waitpid((pid_t)pid, NULL, 0); // reap child
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -23,23 +23,23 @@
|
|||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _NF_APPMANAGER_H_
|
#ifndef _NF_CALLBACKS_H
|
||||||
#define _NF_APPMANAGER_H_
|
#define _NF_CALLBACKS_H
|
||||||
|
|
||||||
#include "dial_server.h"
|
#include "dial_server.h"
|
||||||
|
|
||||||
DIALStatus am_netflix_start(DIALServer *ds, const char *appname,
|
DIALStatus netflix_start(DIALServer *ds, const char *appname,
|
||||||
const char *payload, const char *additionalDataUrl,
|
const char *payload, const char *additionalDataUrl,
|
||||||
DIAL_run_t *run_id, void *callback_data);
|
DIAL_run_t *run_id, void *callback_data);
|
||||||
|
|
||||||
|
|
||||||
DIALStatus am_netflix_hide(DIALServer *ds, const char *app_name,
|
DIALStatus netflix_hide(DIALServer *ds, const char *app_name,
|
||||||
DIAL_run_t *run_id, void *callback_data);
|
DIAL_run_t *run_id, void *callback_data);
|
||||||
|
|
||||||
DIALStatus am_netflix_status(DIALServer *ds, const char *appname,
|
DIALStatus netflix_status(DIALServer *ds, const char *appname,
|
||||||
DIAL_run_t run_id, int* pCanStop, void *callback_data);
|
DIAL_run_t run_id, int* pCanStop, void *callback_data);
|
||||||
|
|
||||||
void am_netflix_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
void netflix_stop(DIALServer *ds, const char *appname, DIAL_run_t run_id,
|
||||||
void *callback_data);
|
void *callback_data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user