mirror of
https://github.com/owntone/owntone-server.git
synced 2025-01-27 06:33:21 -05:00
more plugin work
This commit is contained in:
parent
ff0491f798
commit
1af9e8c08e
16
src/main.c
16
src/main.c
@ -109,7 +109,7 @@ CONFIG config; /**< Main configuration structure, as read from configfile */
|
||||
*/
|
||||
static void usage(char *program);
|
||||
static void txt_add(char *txtrecord, char *fmt, ...);
|
||||
|
||||
static void main_handler(WS_CONNINFO *pwsc);
|
||||
|
||||
/**
|
||||
* build a dns text string
|
||||
@ -133,6 +133,18 @@ void txt_add(char *txtrecord, char *fmt, ...) {
|
||||
strcpy(end+1,buff);
|
||||
}
|
||||
|
||||
void main_handler(WS_CONNINFO *pwsc) {
|
||||
if(plugin_url_candispatch(pwsc)) {
|
||||
DPRINTF(E_DBG,L_MAIN,"Dispatching %s to plugin\n",pwsc->uri);
|
||||
plugin_url_handle(pwsc);
|
||||
return;
|
||||
}
|
||||
|
||||
DPRINTF(E_DBG,L_MAIN,"Dispatching %s to config handler\n",pwsc->uri);
|
||||
config_handler(pwsc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Print usage information to stdout
|
||||
@ -391,7 +403,7 @@ int main(int argc, char *argv[]) {
|
||||
DPRINTF(E_FATAL,L_MAIN|L_WS,"Error staring web server: %s\n",strerror(errno));
|
||||
}
|
||||
|
||||
ws_registerhandler(config.server, "^.*$",config_handler,config_auth,1);
|
||||
ws_registerhandler(config.server, "^.*$",main_handler,config_auth,1);
|
||||
ws_registerhandler(config.server, "^/server-info$",daap_handler,NULL,0);
|
||||
ws_registerhandler(config.server, "^/content-codes$",daap_handler,daap_auth,0); /* iTunes 6.0.4+? */
|
||||
ws_registerhandler(config.server,"^/login$",daap_handler,daap_auth,0);
|
||||
|
@ -428,12 +428,22 @@ int _os_start_signal_handler(pthread_t *handler_tid) {
|
||||
*
|
||||
* @param
|
||||
*/
|
||||
void *os_loadlib(char *path) {
|
||||
return dlopen(path,RTLD_LAZY);
|
||||
void *os_loadlib(char **pe, char *path) {
|
||||
void *retval;
|
||||
|
||||
if(!(retval = dlopen(path,RTLD_NOW)))
|
||||
*pe = strdup(dlerror());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void *os_libfunc(void *handle, char *function) {
|
||||
return dlsym(handle,function);
|
||||
void *os_libfunc(char **pe, void *handle, char *function) {
|
||||
void *retval;
|
||||
|
||||
if(!(retval = dlsym(handle,function)))
|
||||
*pe = strdup(dlerror());
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int *os_unload(void *handle) {
|
||||
|
4
src/os.h
4
src/os.h
@ -34,8 +34,8 @@ extern int os_syslog(int level, char *msg);
|
||||
extern int os_chown(char *path, char *user);
|
||||
|
||||
/* library loading functions */
|
||||
extern void *os_loadlib(char *path);
|
||||
extern void *os_libfunc(void *handle, char *function);
|
||||
extern void *os_loadlib(char **pe, char *path);
|
||||
extern void *os_libfunc(char **pe, void *handle, char *function);
|
||||
extern void *os_unload(void *handle);
|
||||
|
||||
#ifdef WIN32
|
||||
|
147
src/plugin.c
147
src/plugin.c
@ -25,6 +25,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <regex.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@ -33,16 +34,21 @@
|
||||
#include "err.h"
|
||||
#include "os.h"
|
||||
#include "plugin.h"
|
||||
#include "xml-rpc.h"
|
||||
#include "webserver.h"
|
||||
|
||||
typedef struct tag_pluginentry {
|
||||
void *phandle;
|
||||
int type;
|
||||
char *versionstring;
|
||||
regex_t regex;
|
||||
void *functions;
|
||||
struct tag_pluginentry *next;
|
||||
} PLUGIN_ENTRY;
|
||||
|
||||
/* Globals */
|
||||
static PLUGIN_ENTRY _plugin_list = { NULL, 0, NULL, NULL };
|
||||
static PLUGIN_ENTRY _plugin_list;
|
||||
static int _plugin_initialized = 0;
|
||||
|
||||
static pthread_mutex_t _plugin_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static char* _plugin_error_list[] = {
|
||||
@ -51,7 +57,6 @@ static char* _plugin_error_list[] = {
|
||||
"Plugin missing required export: plugin_type/plugin_ver"
|
||||
};
|
||||
|
||||
|
||||
/* Forwards */
|
||||
void _plugin_lock(void);
|
||||
void _plugin_unlock(void);
|
||||
@ -114,14 +119,15 @@ int _plugin_error(char **pe, int error, ...) {
|
||||
int plugin_load(char **pe, char *path) {
|
||||
PLUGIN_ENTRY *ppi;
|
||||
void *phandle;
|
||||
int (*type_func)(void);
|
||||
char* (*ver_func)(void);
|
||||
PLUGIN_INFO *(*info_func)(void);
|
||||
PLUGIN_INFO *pinfo;
|
||||
|
||||
DPRINTF(E_DBG,L_PLUG,"Attempting to load plugin %s\n",path);
|
||||
|
||||
phandle = os_loadlib(path);
|
||||
phandle = os_loadlib(pe, path);
|
||||
if(!phandle) {
|
||||
return _plugin_error(pe,PLUGIN_E_NOLOAD,strerror(errno));
|
||||
DPRINTF(E_INF,L_PLUG,"Couldn't get lib handle for %s\n",path);
|
||||
return PLUGIN_E_NOLOAD;
|
||||
}
|
||||
|
||||
ppi = (PLUGIN_ENTRY*)malloc(sizeof(PLUGIN_ENTRY));
|
||||
@ -129,19 +135,32 @@ int plugin_load(char **pe, char *path) {
|
||||
|
||||
ppi->phandle = phandle;
|
||||
|
||||
type_func = (int(*)(void)) os_libfunc(phandle,"plugin_type");
|
||||
ver_func = (char*(*)(void)) os_libfunc(phandle,"plugin_ver");
|
||||
|
||||
if((type_func == NULL) || (ver_func == NULL))
|
||||
return _plugin_error(pe,PLUGIN_E_BADFUNCS);
|
||||
|
||||
ppi->type = type_func();
|
||||
ppi->versionstring = ver_func();
|
||||
info_func = (PLUGIN_INFO*(*)(void)) os_libfunc(pe, phandle,"plugin_info");
|
||||
if(info_func == NULL) {
|
||||
DPRINTF(E_INF,L_PLUG,"Couldn't get info_func for %s\n",path);
|
||||
return PLUGIN_E_BADFUNCS;
|
||||
}
|
||||
|
||||
pinfo = info_func();
|
||||
|
||||
ppi->type = pinfo->type;
|
||||
ppi->versionstring = pinfo->server;
|
||||
if(ppi->type == PLUGIN_OUTPUT) {
|
||||
/* build the regex */
|
||||
if(regcomp(&ppi->regex,pinfo->url,REG_EXTENDED | REG_NOSUB)) {
|
||||
DPRINTF(E_LOG,L_PLUG,"Bad regex in %s: %s\n",path,pinfo->url);
|
||||
}
|
||||
}
|
||||
ppi->functions = pinfo->handler_functions;
|
||||
|
||||
DPRINTF(E_INF,L_PLUG,"Loaded plugin %s (%s)\n",path,ppi->versionstring);
|
||||
|
||||
_plugin_lock();
|
||||
|
||||
if(!_plugin_initialized) {
|
||||
_plugin_initialized = 1;
|
||||
memset((void*)&_plugin_list,0,sizeof(_plugin_list));
|
||||
}
|
||||
|
||||
ppi->next = _plugin_list.next;
|
||||
_plugin_list.next = ppi;
|
||||
|
||||
@ -149,4 +168,100 @@ int plugin_load(char **pe, char *path) {
|
||||
|
||||
return PLUGIN_E_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check to see if we want to dispatch a particular url
|
||||
*
|
||||
* @param pwsc the connection info (including uri) to check
|
||||
* @returns TRUE if we want to handle it
|
||||
*/
|
||||
int plugin_url_candispatch(WS_CONNINFO *pwsc) {
|
||||
PLUGIN_ENTRY *ppi;
|
||||
|
||||
_plugin_lock();
|
||||
ppi = _plugin_list.next;
|
||||
while(ppi) {
|
||||
if(ppi->type == PLUGIN_OUTPUT) {
|
||||
if(!regexec(&ppi->regex,pwsc->uri,0,NULL,0)) {
|
||||
/* we have a winner */
|
||||
_plugin_unlock();
|
||||
return TRUE;
|
||||
}
|
||||
ppi = ppi->next;
|
||||
}
|
||||
}
|
||||
_plugin_unlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* actually DISPATCH the hander we said we wanted
|
||||
*
|
||||
* @param pwsc the connection info (including uri) to check
|
||||
* @returns TRUE if we want to handle it
|
||||
*/
|
||||
void plugin_url_handle(WS_CONNINFO *pwsc) {
|
||||
PLUGIN_ENTRY *ppi;
|
||||
void (*disp_fn)(WS_CONNINFO *pwsc);
|
||||
|
||||
_plugin_lock();
|
||||
ppi = _plugin_list.next;
|
||||
while(ppi) {
|
||||
if(ppi->type == PLUGIN_OUTPUT) {
|
||||
if(!regexec(&ppi->regex,pwsc->uri,0,NULL,0)) {
|
||||
/* we have a winner */
|
||||
DPRINTF(E_DBG,L_PLUG,"Dispatching %s to %s\n", pwsc->uri,
|
||||
ppi->versionstring);
|
||||
|
||||
/* so functions must be a tag_plugin_output_fn */
|
||||
disp_fn=(((PLUGIN_OUTPUT_FN*)ppi->functions)->handler);
|
||||
disp_fn(pwsc);
|
||||
|
||||
ws_returnerror(pwsc,404,"Wtf!");
|
||||
_plugin_unlock();
|
||||
return;
|
||||
}
|
||||
ppi = ppi->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* should 500 here or something */
|
||||
ws_returnerror(pwsc, 500, "Can't find plugin handler");
|
||||
_plugin_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
/* plugin wrappers for utility functions & stuff
|
||||
*
|
||||
* these functions need to be wrapped so we can maintain a stable
|
||||
* interface to older plugins even if we get newer functions or apis
|
||||
* upstream... it's a binary compatibility layer.
|
||||
*/
|
||||
XMLSTRUCT *pi_xml_init(WS_CONNINFO *pwsc, int emit_header) {
|
||||
return xml_init(pwsc, emit_header);
|
||||
}
|
||||
|
||||
void pi_xml_push(XMLSTRUCT *pxml, char *term) {
|
||||
return xml_push(pxml, term);
|
||||
}
|
||||
|
||||
void pi_xml_pop(XMLSTRUCT *pxml) {
|
||||
return xml_pop(pxml);
|
||||
}
|
||||
|
||||
/* FIXME: 256? */
|
||||
void pi_xml_output(XMLSTRUCT *pxml, char *section, char *fmt, ...) {
|
||||
char buf[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap,fmt);
|
||||
vsnprintf(buf,sizeof(buf),fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
xml_output(pxml,section,"%s",buf);
|
||||
}
|
||||
|
||||
void pi_xml_deinit(XMLSTRUCT *pxml) {
|
||||
return xml_deinit(pxml);
|
||||
}
|
||||
|
27
src/plugin.h
27
src/plugin.h
@ -22,11 +22,38 @@
|
||||
#ifndef _PLUGIN_H_
|
||||
#define _PLUGIN_H_
|
||||
|
||||
#include "webserver.h"
|
||||
|
||||
extern int plugin_load(char **pe, char *path);
|
||||
|
||||
/* Interfaces for web */
|
||||
extern int plugin_url_candispatch(WS_CONNINFO *pwsc);
|
||||
extern void plugin_url_handle(WS_CONNINFO *pwsc);
|
||||
|
||||
#define PLUGIN_E_SUCCESS 0
|
||||
#define PLUGIN_E_NOLOAD 1
|
||||
#define PLUGIN_E_BADFUNCS 2
|
||||
|
||||
#define PLUGIN_OUTPUT 0
|
||||
#define PLUGIN_SCANNER 1
|
||||
#define PLUGIN_DATABASE 2
|
||||
#define PLUGIN_OTHER 3
|
||||
|
||||
#define PLUGIN_VERSION 1
|
||||
|
||||
|
||||
typedef struct tag_plugin_output_fn {
|
||||
void(*handler)(WS_CONNINFO *pwsc);
|
||||
} PLUGIN_OUTPUT_FN;
|
||||
|
||||
/* version 1 plugin info */
|
||||
typedef struct tag_plugin_info {
|
||||
int version;
|
||||
int type;
|
||||
char *server;
|
||||
char *url; /* for output plugins */
|
||||
void *handler_functions;
|
||||
} PLUGIN_INFO;
|
||||
|
||||
|
||||
#endif /* _PLUGIN_H_ */
|
||||
|
@ -1268,10 +1268,6 @@ char *ws_urldecode(char *string, int space_as_plus) {
|
||||
|
||||
while(*src) {
|
||||
switch(*src) {
|
||||
/* DWB - space gets converted to %20, not +, this definitely breaks compatibility with iTunes */
|
||||
/* But the browsers encode space as plus, so when using the web interface,
|
||||
* anything with a plus is broken. This will end up having to be sniffed
|
||||
* by remote agent */
|
||||
case '+':
|
||||
if(space_as_plus) {
|
||||
*dst++=' ';
|
||||
|
@ -165,6 +165,8 @@ void xml_pop(XMLSTRUCT *pxml) {
|
||||
pxml->stack_level--;
|
||||
}
|
||||
|
||||
/* FIXME: Fixed at 256? And can't I get an expandable sprintf/cat? */
|
||||
|
||||
/**
|
||||
* output a string
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user