move the thread status stuff into the webserver, add status info to xml-rpc
This commit is contained in:
parent
a35a59af31
commit
a82c564426
|
@ -42,7 +42,7 @@ mt_daapd_SOURCES = main.c daapd.h rend.h uici.c uici.h webserver.c \
|
||||||
db-generic.c db-generic.h dispatch.c dispatch.h \
|
db-generic.c db-generic.h dispatch.c dispatch.h \
|
||||||
rxml.c rxml.h redblack.c redblack.h scan-mp3.c \
|
rxml.c rxml.h redblack.c redblack.h scan-mp3.c \
|
||||||
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
|
scan-xml.c scan-wma.c scan-aac.c scan-aac.h scan-wav.c scan-url.c \
|
||||||
smart-parser.c smart-parser.h \
|
smart-parser.c smart-parser.h xml-rpc.c xml-rpc.h \
|
||||||
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
|
$(PRENDSRC) $(ORENDSRC) $(HRENDSRC) $(OGGVORBISSRC) $(FLACSRC) \
|
||||||
$(MUSEPACKSRC) $(SQLITEDB)
|
$(MUSEPACKSRC) $(SQLITEDB)
|
||||||
|
|
||||||
|
|
169
src/configfile.c
169
src/configfile.c
|
@ -50,7 +50,7 @@
|
||||||
#include "configfile.h"
|
#include "configfile.h"
|
||||||
#include "db-generic.h"
|
#include "db-generic.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
//#include "xml-rpc.h"
|
#include "xml-rpc.h"
|
||||||
|
|
||||||
#ifndef WITHOUT_MDNS
|
#ifndef WITHOUT_MDNS
|
||||||
# include "rend.h"
|
# include "rend.h"
|
||||||
|
@ -76,8 +76,6 @@ static void config_emit_flags(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||||
static void config_emit_host(WS_CONNINFO *pwsc, void *value, char *arg);
|
static void config_emit_host(WS_CONNINFO *pwsc, void *value, char *arg);
|
||||||
static void config_subst_stream(WS_CONNINFO *pwsc, int fd_src);
|
static void config_subst_stream(WS_CONNINFO *pwsc, int fd_src);
|
||||||
static int config_file_is_readonly(void);
|
static int config_file_is_readonly(void);
|
||||||
static int config_mutex_lock(void);
|
|
||||||
static int config_mutex_unlock(void);
|
|
||||||
static int config_existdir(char *path);
|
static int config_existdir(char *path);
|
||||||
static int config_makedir(char *path);
|
static int config_makedir(char *path);
|
||||||
static void config_content_type(WS_CONNINFO *pwsc, char *path);
|
static void config_content_type(WS_CONNINFO *pwsc, char *path);
|
||||||
|
@ -156,17 +154,6 @@ CONFIGELEMENT config_elements[] = {
|
||||||
{ -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL }
|
{ -1,1,0,CONFIG_TYPE_STRING,NULL,NULL,NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** table of thread status -- as displayed on the status page */
|
|
||||||
typedef struct tag_scan_status {
|
|
||||||
int session;
|
|
||||||
int thread;
|
|
||||||
char *what;
|
|
||||||
char *host;
|
|
||||||
struct tag_scan_status *next;
|
|
||||||
} SCAN_STATUS;
|
|
||||||
|
|
||||||
SCAN_STATUS scan_status = { 0,0,NULL,NULL }; /**< root of status list */
|
|
||||||
pthread_mutex_t scan_mutex = PTHREAD_MUTEX_INITIALIZER; /**< status list mutex */
|
|
||||||
int config_session=0; /**< session counter */
|
int config_session=0; /**< session counter */
|
||||||
|
|
||||||
#define MAX_LINE 1024
|
#define MAX_LINE 1024
|
||||||
|
@ -685,7 +672,6 @@ void config_handler(WS_CONNINFO *pwsc) {
|
||||||
pwsc->close=1;
|
pwsc->close=1;
|
||||||
ws_addresponseheader(pwsc,"Connection","close");
|
ws_addresponseheader(pwsc,"Connection","close");
|
||||||
|
|
||||||
/*
|
|
||||||
if(strcasecmp(pwsc->uri,"/xml-rpc")==0) {
|
if(strcasecmp(pwsc->uri,"/xml-rpc")==0) {
|
||||||
// perhaps this should get a separate handler
|
// perhaps this should get a separate handler
|
||||||
config_set_status(pwsc,0,"Serving xml-rpc method");
|
config_set_status(pwsc,0,"Serving xml-rpc method");
|
||||||
|
@ -694,7 +680,7 @@ void config_handler(WS_CONNINFO *pwsc) {
|
||||||
config_set_status(pwsc,0,NULL);
|
config_set_status(pwsc,0,NULL);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
snprintf(path,PATH_MAX,"%s/%s",config.web_root,pwsc->uri);
|
snprintf(path,PATH_MAX,"%s/%s",config.web_root,pwsc->uri);
|
||||||
if(!realpath(path,resolved_path)) {
|
if(!realpath(path,resolved_path)) {
|
||||||
pwsc->error=errno;
|
pwsc->error=errno;
|
||||||
|
@ -994,30 +980,16 @@ void config_emit_service_status(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||||
* \returns connected user count
|
* \returns connected user count
|
||||||
*/
|
*/
|
||||||
int config_get_session_count(void) {
|
int config_get_session_count(void) {
|
||||||
SCAN_STATUS *pcurrent, *pcheck;
|
WSTHREADENUM wste;
|
||||||
|
WS_CONNINFO *pwsc;
|
||||||
int count=0;
|
int count=0;
|
||||||
|
|
||||||
if(config_mutex_lock()) {
|
pwsc = ws_thread_enum_first(config.server,&wste);
|
||||||
return 0;
|
while(pwsc) {
|
||||||
}
|
|
||||||
|
|
||||||
pcurrent=scan_status.next;
|
|
||||||
|
|
||||||
while(pcurrent) {
|
|
||||||
pcheck=scan_status.next;
|
|
||||||
while(pcheck != pcurrent) {
|
|
||||||
if(strcmp(pcheck->host,pcurrent->host) == 0)
|
|
||||||
break;
|
|
||||||
pcheck=pcheck->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pcheck == pcurrent)
|
|
||||||
count++;
|
count++;
|
||||||
|
pwsc = ws_thread_enum_next(config.server,&wste);
|
||||||
pcurrent=pcurrent->next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config_mutex_unlock();
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1043,25 +1015,26 @@ void config_emit_session_count(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||||
* \param arg any args passwd with the meta command. Also unused
|
* \param arg any args passwd with the meta command. Also unused
|
||||||
*/
|
*/
|
||||||
void config_emit_threadstatus(WS_CONNINFO *pwsc, void *value, char *arg) {
|
void config_emit_threadstatus(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||||
|
WS_CONNINFO *pci;
|
||||||
SCAN_STATUS *pss;
|
SCAN_STATUS *pss;
|
||||||
|
WSTHREADENUM wste;
|
||||||
if(config_mutex_lock())
|
|
||||||
return;
|
|
||||||
|
|
||||||
ws_writefd(pwsc,"<table><tr><th align=\"left\">Thread</th>");
|
ws_writefd(pwsc,"<table><tr><th align=\"left\">Thread</th>");
|
||||||
ws_writefd(pwsc,"<th align=\"left\">Session</th><th align=\"left\">Host</th>");
|
ws_writefd(pwsc,"<th align=\"left\">Session</th><th align=\"left\">Host</th>");
|
||||||
ws_writefd(pwsc,"<th align=\"left\">Action</th></tr>\n");
|
ws_writefd(pwsc,"<th align=\"left\">Action</th></tr>\n");
|
||||||
|
|
||||||
|
|
||||||
pss=scan_status.next;
|
pci = ws_thread_enum_first(config.server,&wste);
|
||||||
while(pss) {
|
while(pci) {
|
||||||
|
pss = ws_get_local_storage(pci);
|
||||||
|
if(pss) {
|
||||||
ws_writefd(pwsc,"<tr><td>%d</td><td>%d</td><td>%s</td><td>%s</td></tr>\n",
|
ws_writefd(pwsc,"<tr><td>%d</td><td>%d</td><td>%s</td><td>%s</td></tr>\n",
|
||||||
pss->thread,pss->session,pss->host,pss->what);
|
pss->thread,pss->session,pss->host,pss->what);
|
||||||
pss=pss->next;
|
}
|
||||||
|
pci=ws_thread_enum_next(config.server,&wste);
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_writefd(pwsc,"</table>\n");
|
ws_writefd(pwsc,"</table>\n");
|
||||||
config_mutex_unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1235,11 +1208,27 @@ void config_emit_include(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the status info for a particuarl thread. The thread
|
* free a SCAN_STATUS block
|
||||||
|
*
|
||||||
|
* @param vp pointer to SCAN_STATUS block
|
||||||
|
*/
|
||||||
|
void config_freescan(void *vp) {
|
||||||
|
SCAN_STATUS *pss = (SCAN_STATUS*)vp;
|
||||||
|
|
||||||
|
if(pss) {
|
||||||
|
if(pss->what)
|
||||||
|
free(pss->what);
|
||||||
|
if(pss->host)
|
||||||
|
free(pss->host);
|
||||||
|
free(pss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the status info for a particular thread. The thread
|
||||||
* status is the string displayed in the THREADSTAT block of the
|
* status is the string displayed in the THREADSTAT block of the
|
||||||
* admin page. That string is set with the function, which take
|
* admin page. That string is set with the function, which take
|
||||||
* a printf-style format specifier. Setting the status to NULL
|
* a printf-style format specifier.
|
||||||
* will remove the thread from the config table.
|
|
||||||
*
|
*
|
||||||
* \param pwsc the web connection of the thread to update
|
* \param pwsc the web connection of the thread to update
|
||||||
* \param session the session id of that thread
|
* \param session the session id of that thread
|
||||||
|
@ -1248,106 +1237,56 @@ void config_emit_include(WS_CONNINFO *pwsc, void *value, char *arg) {
|
||||||
void config_set_status(WS_CONNINFO *pwsc, int session, char *fmt, ...) {
|
void config_set_status(WS_CONNINFO *pwsc, int session, char *fmt, ...) {
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
va_list ap;
|
va_list ap;
|
||||||
SCAN_STATUS *pfirst, *plast;
|
SCAN_STATUS *pfirst;
|
||||||
|
char *newmsg = NULL;
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_CONF,"Entering config_set_status\n");
|
DPRINTF(E_DBG,L_CONF,"Entering config_set_status\n");
|
||||||
|
|
||||||
if(config_mutex_lock()) {
|
|
||||||
/* we should really shutdown the app here... */
|
|
||||||
DPRINTF(E_FATAL,L_CONF,"Error acquiring config mutex\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
pfirst=plast=scan_status.next;
|
|
||||||
while((pfirst) && (pfirst->thread != pwsc->threadno)) {
|
|
||||||
plast=pfirst;
|
|
||||||
pfirst=pfirst->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(fmt) {
|
if(fmt) {
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
vsnprintf(buffer, 1024, fmt, ap);
|
vsnprintf(buffer, 1024, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
if(pfirst) { /* already there */
|
newmsg = strdup(buffer);
|
||||||
free(pfirst->what);
|
}
|
||||||
pfirst->what = strdup(buffer);
|
|
||||||
pfirst->session = session; /* this might change! */
|
if(!(pfirst = ws_get_local_storage(pwsc))) {
|
||||||
} else {
|
/* new info */
|
||||||
pfirst=(SCAN_STATUS*)malloc(sizeof(SCAN_STATUS));
|
pfirst=(SCAN_STATUS*)malloc(sizeof(SCAN_STATUS));
|
||||||
if(pfirst) {
|
if(pfirst) {
|
||||||
pfirst->what = strdup(buffer);
|
pfirst->what = strdup(buffer);
|
||||||
pfirst->session = session;
|
pfirst->session = session;
|
||||||
pfirst->thread = pwsc->threadno;
|
pfirst->thread = pwsc->threadno;
|
||||||
pfirst->next = scan_status.next;
|
|
||||||
pfirst->host = strdup(pwsc->hostname);
|
pfirst->host = strdup(pwsc->hostname);
|
||||||
scan_status.next=pfirst;
|
ws_set_local_storage(pwsc,pfirst,config_freescan);
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(!pfirst) {
|
if(newmsg)
|
||||||
config_mutex_unlock();
|
free(newmsg);
|
||||||
DPRINTF(E_DBG,L_CONF,"Exiting config_set_status\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pfirst==plast) {
|
|
||||||
scan_status.next=pfirst->next;
|
|
||||||
free(pfirst->what);
|
|
||||||
free(pfirst->host);
|
|
||||||
free(pfirst);
|
|
||||||
} else {
|
|
||||||
plast->next = pfirst->next;
|
|
||||||
free(pfirst->what);
|
|
||||||
free(pfirst->host);
|
|
||||||
free(pfirst);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config_mutex_unlock();
|
/* just update */
|
||||||
|
if(pfirst->what) {
|
||||||
|
free(pfirst->what);
|
||||||
|
}
|
||||||
|
pfirst->what=newmsg;
|
||||||
|
pfirst->session=session;
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_CONF,"Exiting config_set_status\n");
|
DPRINTF(E_DBG,L_CONF,"Exiting config_set_status\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock the config mutex. This is the mutex that provides
|
|
||||||
* thread safety around the threadstat list.
|
|
||||||
*/
|
|
||||||
int config_mutex_lock(void) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if((err=pthread_mutex_lock(&scan_mutex))) {
|
|
||||||
errno=err;
|
|
||||||
return - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlock the config mutex. This is the mutex that provides
|
|
||||||
* thread safety for the threadstat list
|
|
||||||
*/
|
|
||||||
int config_mutex_unlock(void) {
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if((err=pthread_mutex_unlock(&scan_mutex))) {
|
|
||||||
errno=err;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next available session id.
|
* Get the next available session id.
|
||||||
|
* This is vulnerable to races, but we don't track sessions,
|
||||||
|
* so there really isn't a point anyway.
|
||||||
*
|
*
|
||||||
* \returns duh... the next available session id
|
* @returns duh... the next available session id
|
||||||
*/
|
*/
|
||||||
int config_get_next_session(void) {
|
int config_get_next_session(void) {
|
||||||
int session;
|
int session;
|
||||||
config_mutex_lock();
|
|
||||||
|
|
||||||
session=++config_session;
|
session=++config_session;
|
||||||
config_mutex_unlock();
|
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,4 +34,12 @@ extern int config_get_session_count(void);
|
||||||
extern int config_get_next_session(void);
|
extern int config_get_next_session(void);
|
||||||
extern void config_close(void);
|
extern void config_close(void);
|
||||||
|
|
||||||
|
/** thread local storage */
|
||||||
|
typedef struct tag_scan_status {
|
||||||
|
int session;
|
||||||
|
int thread;
|
||||||
|
char *what;
|
||||||
|
char *host;
|
||||||
|
} SCAN_STATUS;
|
||||||
|
|
||||||
#endif /* _CONFIGFILE_H_ */
|
#endif /* _CONFIGFILE_H_ */
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#ifndef _DAAPD_H_
|
#ifndef _DAAPD_H_
|
||||||
#define _DAAPD_H_
|
#define _DAAPD_H_
|
||||||
|
|
||||||
|
#include "webserver.h"
|
||||||
|
|
||||||
/** Simple struct for holding stat info.
|
/** Simple struct for holding stat info.
|
||||||
* \todo wire up the tag_stats#bytes_served stuff into r_write() in restart.c
|
* \todo wire up the tag_stats#bytes_served stuff into r_write() in restart.c
|
||||||
*/
|
*/
|
||||||
|
@ -73,6 +75,7 @@ typedef struct tag_config {
|
||||||
char *compdirs; /**< Compilations directories */
|
char *compdirs; /**< Compilations directories */
|
||||||
char **complist; /**< list of compilation directories */
|
char **complist; /**< list of compilation directories */
|
||||||
STATS stats; /**< Stats structure (see above) */
|
STATS stats; /**< Stats structure (see above) */
|
||||||
|
WSHANDLE server; /**< webserver handle */
|
||||||
} CONFIG;
|
} CONFIG;
|
||||||
|
|
||||||
extern CONFIG config;
|
extern CONFIG config;
|
||||||
|
|
23
src/main.c
23
src/main.c
|
@ -348,7 +348,6 @@ int main(int argc, char *argv[]) {
|
||||||
char *configfile=DEFAULT_CONFIGFILE;
|
char *configfile=DEFAULT_CONFIGFILE;
|
||||||
char *pidfile=PIDFILE;
|
char *pidfile=PIDFILE;
|
||||||
WSCONFIG ws_config;
|
WSCONFIG ws_config;
|
||||||
WSHANDLE server;
|
|
||||||
int foreground=0;
|
int foreground=0;
|
||||||
int reload=0;
|
int reload=0;
|
||||||
int start_time;
|
int start_time;
|
||||||
|
@ -506,19 +505,19 @@ int main(int argc, char *argv[]) {
|
||||||
DPRINTF(E_LOG,L_MAIN|L_WS,"Starting web server from %s on port %d\n",
|
DPRINTF(E_LOG,L_MAIN|L_WS,"Starting web server from %s on port %d\n",
|
||||||
config.web_root, config.port);
|
config.web_root, config.port);
|
||||||
|
|
||||||
server=ws_start(&ws_config);
|
config.server=ws_start(&ws_config);
|
||||||
if(!server) {
|
if(!config.server) {
|
||||||
DPRINTF(E_FATAL,L_MAIN|L_WS,"Error staring web server: %s\n",strerror(errno));
|
DPRINTF(E_FATAL,L_MAIN|L_WS,"Error staring web server: %s\n",strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_registerhandler(server, "^.*$",config_handler,config_auth,1);
|
ws_registerhandler(config.server, "^.*$",config_handler,config_auth,1);
|
||||||
ws_registerhandler(server, "^/server-info$",daap_handler,NULL,0);
|
ws_registerhandler(config.server, "^/server-info$",daap_handler,NULL,0);
|
||||||
ws_registerhandler(server, "^/content-codes$",daap_handler,NULL,0);
|
ws_registerhandler(config.server, "^/content-codes$",daap_handler,NULL,0);
|
||||||
ws_registerhandler(server,"^/login$",daap_handler,daap_auth,0);
|
ws_registerhandler(config.server,"^/login$",daap_handler,daap_auth,0);
|
||||||
ws_registerhandler(server,"^/update$",daap_handler,daap_auth,0);
|
ws_registerhandler(config.server,"^/update$",daap_handler,daap_auth,0);
|
||||||
ws_registerhandler(server,"^/databases$",daap_handler,daap_auth,0);
|
ws_registerhandler(config.server,"^/databases$",daap_handler,daap_auth,0);
|
||||||
ws_registerhandler(server,"^/logout$",daap_handler,NULL,0);
|
ws_registerhandler(config.server,"^/logout$",daap_handler,NULL,0);
|
||||||
ws_registerhandler(server,"^/databases/.*",daap_handler,NULL,0);
|
ws_registerhandler(config.server,"^/databases/.*",daap_handler,NULL,0);
|
||||||
|
|
||||||
#ifndef WITHOUT_MDNS
|
#ifndef WITHOUT_MDNS
|
||||||
if(config.use_mdns) { /* register services */
|
if(config.use_mdns) { /* register services */
|
||||||
|
@ -581,7 +580,7 @@ int main(int argc, char *argv[]) {
|
||||||
* cause the accept to fail on some libcs.
|
* cause the accept to fail on some libcs.
|
||||||
*
|
*
|
||||||
DPRINTF(E_LOG,L_MAIN|L_WS,"Stopping web server\n");
|
DPRINTF(E_LOG,L_MAIN|L_WS,"Stopping web server\n");
|
||||||
ws_stop(server);
|
ws_stop(config.server);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
config_close();
|
config_close();
|
||||||
|
|
|
@ -170,6 +170,21 @@ int ws_unlock_unsafe(void) {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lock the connection list
|
||||||
|
*/
|
||||||
|
void ws_lock_connlist(WS_PRIVATE *pwsp) {
|
||||||
|
if(pthread_mutex_lock(&pwsp->exit_mutex))
|
||||||
|
DPRINTF(E_FATAL,L_WS,"Cannot lock condition mutex\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws_unlock_connlist(WS_PRIVATE *pwsp) {
|
||||||
|
pthread_mutex_unlock(&pwsp->exit_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ws_start
|
* ws_start
|
||||||
*
|
*
|
||||||
|
@ -462,12 +477,15 @@ void ws_close(WS_CONNINFO *pwsc) {
|
||||||
|
|
||||||
DPRINTF(E_SPAM,L_WS,"Entering ws_close\n");
|
DPRINTF(E_SPAM,L_WS,"Entering ws_close\n");
|
||||||
|
|
||||||
/* DWB: update the status so it doesn't fill up with no longer
|
if(pwsc->local_storage) {
|
||||||
relevant entries */
|
if(pwsc->storage_callback) {
|
||||||
|
pwsc->storage_callback(pwsc->local_storage);
|
||||||
/* FIXME: status handling should be done with a callback or something */
|
pwsc->local_storage=NULL;
|
||||||
|
} else {
|
||||||
config_set_status(pwsc, 0, NULL);
|
free(pwsc->local_storage);
|
||||||
|
pwsc->local_storage=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(E_DBG,L_WS,"Thread %d: Terminating\n",pwsc->threadno);
|
DPRINTF(E_DBG,L_WS,"Thread %d: Terminating\n",pwsc->threadno);
|
||||||
DPRINTF(E_DBG,L_WS,"Thread %d: Freeing request headers\n",pwsc->threadno);
|
DPRINTF(E_DBG,L_WS,"Thread %d: Freeing request headers\n",pwsc->threadno);
|
||||||
|
@ -1502,3 +1520,69 @@ char *ws_getvar(WS_CONNINFO *pwsc, char *var) {
|
||||||
char *ws_getrequestheader(WS_CONNINFO *pwsc, char *header) {
|
char *ws_getrequestheader(WS_CONNINFO *pwsc, char *header) {
|
||||||
return ws_getarg(&pwsc->request_headers,header);
|
return ws_getarg(&pwsc->request_headers,header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the local storage pointer
|
||||||
|
*
|
||||||
|
* @param pwsc connection to get local storage for
|
||||||
|
*/
|
||||||
|
void *ws_get_local_storage(WS_CONNINFO *pwsc) {
|
||||||
|
return pwsc->local_storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the local storage pointer (and callback)
|
||||||
|
*/
|
||||||
|
void ws_set_local_storage(WS_CONNINFO *pwsc, void *ptr, void (*callback)(void *)) {
|
||||||
|
if(pwsc->local_storage) {
|
||||||
|
if(pwsc->storage_callback) {
|
||||||
|
pwsc->storage_callback(pwsc->local_storage);
|
||||||
|
pwsc->local_storage=NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pwsc->storage_callback = callback;
|
||||||
|
pwsc->local_storage = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* walk through the connection list and enumerate all the items
|
||||||
|
*/
|
||||||
|
WS_CONNINFO *ws_thread_enum_first(WSHANDLE wsh, WSTHREADENUM *vpp) {
|
||||||
|
WS_PRIVATE *pwsp;
|
||||||
|
WS_CONNINFO *pwsc;
|
||||||
|
WS_CONNLIST *pconlist;
|
||||||
|
|
||||||
|
pwsp = (WS_PRIVATE *)wsh;
|
||||||
|
ws_lock_connlist(pwsp);
|
||||||
|
|
||||||
|
pconlist = pwsp->connlist.next;
|
||||||
|
pwsc = pconlist->pwsc;
|
||||||
|
*vpp = (WSTHREADENUM)pconlist;
|
||||||
|
|
||||||
|
if(pwsc == NULL) {
|
||||||
|
ws_unlock_connlist(pwsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pwsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
WS_CONNINFO *ws_thread_enum_next(WSHANDLE wsh, WSTHREADENUM *vpp) {
|
||||||
|
WS_PRIVATE *pwsp;
|
||||||
|
WS_CONNINFO *pwsc = NULL;
|
||||||
|
WS_CONNLIST *pconlist;
|
||||||
|
|
||||||
|
pwsp = (WS_PRIVATE *)wsh;
|
||||||
|
|
||||||
|
pconlist = (WS_CONNLIST*)*vpp;
|
||||||
|
if((!pconlist) || (!pconlist->next)) {
|
||||||
|
ws_unlock_connlist(pwsp);
|
||||||
|
} else {
|
||||||
|
pconlist=pconlist->next;
|
||||||
|
*vpp = (WSTHREADENUM)pconlist;
|
||||||
|
pwsc = pconlist->pwsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pwsc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
|
|
||||||
|
|
||||||
typedef void* WSHANDLE;
|
typedef void* WSHANDLE;
|
||||||
|
typedef void* WSTHREADENUM;
|
||||||
|
|
||||||
typedef struct tag_wsconfig {
|
typedef struct tag_wsconfig {
|
||||||
char *web_root;
|
char *web_root;
|
||||||
|
@ -57,6 +58,8 @@ typedef struct tag_ws_conninfo {
|
||||||
char *uri;
|
char *uri;
|
||||||
char *hostname;
|
char *hostname;
|
||||||
int close;
|
int close;
|
||||||
|
void *local_storage;
|
||||||
|
void (*storage_callback)(void*);
|
||||||
ARGLIST request_headers;
|
ARGLIST request_headers;
|
||||||
ARGLIST response_headers;
|
ARGLIST response_headers;
|
||||||
ARGLIST request_vars;
|
ARGLIST request_vars;
|
||||||
|
@ -76,6 +79,12 @@ extern int ws_registerhandler(WSHANDLE ws, char *regex,
|
||||||
int(*auth)(char *, char *),
|
int(*auth)(char *, char *),
|
||||||
int addheaders);
|
int addheaders);
|
||||||
|
|
||||||
|
extern void *ws_get_local_storage(WS_CONNINFO *pwsc);
|
||||||
|
extern void ws_set_local_storage(WS_CONNINFO *pwsc, void *ptr, void (*callback)(void *));
|
||||||
|
|
||||||
|
extern WS_CONNINFO *ws_thread_enum_first(WSHANDLE, WSTHREADENUM *);
|
||||||
|
extern WS_CONNINFO *ws_thread_enum_next(WSHANDLE, WSTHREADENUM *);
|
||||||
|
|
||||||
/* for handlers */
|
/* for handlers */
|
||||||
extern void ws_close(WS_CONNINFO *pwsc);
|
extern void ws_close(WS_CONNINFO *pwsc);
|
||||||
extern int ws_returnerror(WS_CONNINFO *pwsc, int error, char *description);
|
extern int ws_returnerror(WS_CONNINFO *pwsc, int error, char *description);
|
||||||
|
|
124
src/xml-rpc.c
124
src/xml-rpc.c
|
@ -6,15 +6,17 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "configfile.h"
|
||||||
|
#include "daapd.h"
|
||||||
#include "err.h"
|
#include "err.h"
|
||||||
#include "db-memory.h"
|
|
||||||
#include "mp3-scanner.h"
|
#include "mp3-scanner.h"
|
||||||
#include "webserver.h"
|
#include "webserver.h"
|
||||||
|
|
||||||
/* Forwards */
|
/* Forwards */
|
||||||
void xml_get_playlists(WS_CONNINFO *pwsc);
|
void xml_get_stats(WS_CONNINFO *pwsc);
|
||||||
void xml_get_playlistitems(WS_CONNINFO *pwsc);
|
|
||||||
char *xml_entity_encode(char *original);
|
char *xml_entity_encode(char *original);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,11 +32,8 @@ void xml_handle(WS_CONNINFO *pwsc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(strcasecmp(method,"getPlaylists") == 0) {
|
if(strcasecmp(method,"stats") == 0) {
|
||||||
xml_get_playlists(pwsc);
|
xml_get_stats(pwsc);
|
||||||
return;
|
|
||||||
} else if(strcasecmp(method,"getPlaylistItems") == 0) {
|
|
||||||
xml_get_playlistitems(pwsc);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,79 +44,78 @@ void xml_handle(WS_CONNINFO *pwsc) {
|
||||||
/**
|
/**
|
||||||
* return xml file of all playlists
|
* return xml file of all playlists
|
||||||
*/
|
*/
|
||||||
void xml_get_playlists(WS_CONNINFO *pwsc) {
|
void xml_get_stats(WS_CONNINFO *pwsc) {
|
||||||
ENUMHANDLE henum;
|
int r_secs, r_days, r_hours, r_mins;
|
||||||
int playlistid;
|
char buf[80];
|
||||||
char *temp;
|
WS_CONNINFO *pci;
|
||||||
|
SCAN_STATUS *pss;
|
||||||
|
WSTHREADENUM wste;
|
||||||
|
|
||||||
|
|
||||||
ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
|
ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
|
||||||
ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
||||||
ws_emitheaders(pwsc);
|
ws_emitheaders(pwsc);
|
||||||
|
|
||||||
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
||||||
ws_writefd(pwsc,"<playlists>");
|
ws_writefd(pwsc,"<status>");
|
||||||
|
|
||||||
/* enumerate all the playlists */
|
ws_writefd(pwsc,"<service_status>");
|
||||||
henum=db_playlist_enum_begin();
|
/* enumerate services? */
|
||||||
while(henum) {
|
ws_writefd(pwsc,"</service_status>");
|
||||||
playlistid=db_playlist_enum(&henum);
|
|
||||||
ws_writefd(pwsc,"<item>");
|
ws_writefd(pwsc,"<thread_status>");
|
||||||
ws_writefd(pwsc,"<id>%d</id>",playlistid);
|
/* enumerate thread status */
|
||||||
temp=xml_entity_encode(db_get_playlist_name(playlistid));
|
|
||||||
ws_writefd(pwsc,"<name>%s</name>",temp);
|
pci = ws_thread_enum_first(config.server,&wste);
|
||||||
if(temp) free(temp);
|
while(pci) {
|
||||||
ws_writefd(pwsc,"<smart>%d</smart>",db_get_playlist_is_smart(playlistid));
|
pss = ws_get_local_storage(pci);
|
||||||
ws_writefd(pwsc,"<entries>%d</entries>",db_get_playlist_entry_count(playlistid));
|
if(pss) {
|
||||||
ws_writefd(pwsc," </item>");
|
ws_writefd(pwsc,"<id>%d</id><sourceip>%s</sourceip><action>%s</action>",
|
||||||
|
pss->thread,pss->host,pss->what);
|
||||||
|
}
|
||||||
|
pci=ws_thread_enum_next(config.server,&wste);
|
||||||
}
|
}
|
||||||
|
|
||||||
ws_writefd(pwsc,"</playlists>\n");
|
|
||||||
|
|
||||||
return;
|
ws_writefd(pwsc,"</thread_status>");
|
||||||
}
|
|
||||||
|
|
||||||
|
ws_writefd(pwsc,"<statistics>");
|
||||||
|
/* dump stats */
|
||||||
|
|
||||||
/**
|
ws_writefd(pwsc,"<stat name=\"uptime\">");
|
||||||
* return xml file of playlist info
|
|
||||||
*/
|
|
||||||
void xml_get_playlistitems(WS_CONNINFO *pwsc) {
|
|
||||||
char *playlistnum;
|
|
||||||
int playlistid;
|
|
||||||
ENUMHANDLE henum;
|
|
||||||
unsigned long int itemid;
|
|
||||||
char *temp;
|
|
||||||
MP3FILE *current;
|
|
||||||
|
|
||||||
if((playlistnum=ws_getvar(pwsc,"playlistid")) == NULL) {
|
r_secs=time(NULL)-config.stats.start_time;
|
||||||
ws_returnerror(pwsc,500,"no playlistid specified");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ws_addresponseheader(pwsc,"Content-Type","text/xml; charset=utf-8");
|
r_days=r_secs/(3600 * 24);
|
||||||
ws_writefd(pwsc,"HTTP/1.0 200 OK\r\n");
|
r_secs -= ((3600 * 24) * r_days);
|
||||||
ws_emitheaders(pwsc);
|
|
||||||
|
|
||||||
playlistid=atoi(playlistnum);
|
r_hours=r_secs/3600;
|
||||||
|
r_secs -= (3600 * r_hours);
|
||||||
|
|
||||||
ws_writefd(pwsc,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>");
|
r_mins=r_secs/60;
|
||||||
ws_writefd(pwsc,"<playlist>");
|
r_secs -= 60 * r_mins;
|
||||||
|
|
||||||
henum=db_playlist_items_enum_begin(playlistid);
|
memset(buf,0x0,sizeof(buf));
|
||||||
while((itemid=db_playlist_items_enum(&henum)) != -1) {
|
if(r_days)
|
||||||
current=db_find(itemid);
|
sprintf((char*)&buf[strlen(buf)],"%d day%s, ", r_days,
|
||||||
if(0 != current) {
|
r_days == 1 ? "" : "s");
|
||||||
ws_writefd(pwsc,"<item>");
|
|
||||||
ws_writefd(pwsc,"<id>%lu</id>",itemid);
|
|
||||||
temp=xml_entity_encode(current->title);
|
|
||||||
ws_writefd(pwsc,"<name>%s</name>",temp);
|
|
||||||
ws_writefd(pwsc,"</item>");
|
|
||||||
free(temp);
|
|
||||||
db_dispose(current);
|
|
||||||
free(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ws_writefd(pwsc,"</playlist>");
|
if(r_days || r_hours)
|
||||||
|
sprintf((char*)&buf[strlen(buf)],"%d hour%s, ", r_hours,
|
||||||
|
r_hours == 1 ? "" : "s");
|
||||||
|
|
||||||
|
if(r_days || r_hours || r_mins)
|
||||||
|
sprintf((char*)&buf[strlen(buf)],"%d minute%s, ", r_mins,
|
||||||
|
r_mins == 1 ? "" : "s");
|
||||||
|
|
||||||
|
sprintf((char*)&buf[strlen(buf)],"%d second%s ", r_secs,
|
||||||
|
r_secs == 1 ? "" : "s");
|
||||||
|
|
||||||
|
ws_writefd(pwsc,"<name>Uptime</name>");
|
||||||
|
ws_writefd(pwsc,"<value>%s</value>",buf);
|
||||||
|
ws_writefd(pwsc,"</stat>");
|
||||||
|
ws_writefd(pwsc,"</statistics>");
|
||||||
|
ws_writefd(pwsc,"</status>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue