mirror of
https://github.com/owntone/owntone-server.git
synced 2025-03-20 04:24:20 -04:00
add io_ functions for plugins
This commit is contained in:
parent
40956ee0f9
commit
f2be31595f
26
src/ff-plugin-events.h
Normal file
26
src/ff-plugin-events.h
Normal file
@ -0,0 +1,26 @@
|
||||
|
||||
|
||||
#ifndef _FF_PLUGIN_EVENTS_H_
|
||||
#define _FF_PLUGIN_EVENTS_H_
|
||||
|
||||
/* Plugin types */
|
||||
#define PLUGIN_OUTPUT 1
|
||||
#define PLUGIN_SCANNER 2
|
||||
#define PLUGIN_DATABASE 4
|
||||
#define PLUGIN_EVENT 8
|
||||
#define PLUGIN_TRANSCODE 16
|
||||
|
||||
/* plugin event types */
|
||||
#define PLUGIN_EVENT_LOG 0
|
||||
#define PLUGIN_EVENT_FULLSCAN_START 1
|
||||
#define PLUGIN_EVENT_FULLSCAN_END 2
|
||||
#define PLUGIN_EVENT_STARTING 3
|
||||
#define PLUGIN_EVENT_SHUTDOWN 4
|
||||
#define PLUGIN_EVENT_STARTSTREAM 5
|
||||
#define PLUGIN_EVENT_ABORTSTREAM 6
|
||||
#define PLUGIN_EVENT_ENDSTREAM 7
|
||||
|
||||
#define PLUGIN_VERSION 1
|
||||
|
||||
|
||||
#endif /* _FF_PLUGIN_EVENTS_ */
|
239
src/ff-plugins.c
239
src/ff-plugins.c
@ -7,6 +7,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bsd-snprintf.h"
|
||||
#include "conf.h"
|
||||
#include "configfile.h"
|
||||
#include "daapd.h"
|
||||
@ -14,6 +15,7 @@
|
||||
#include "err.h"
|
||||
#include "ff-dbstruct.h"
|
||||
#include "ff-plugins.h"
|
||||
#include "io.h"
|
||||
#include "mp3-scanner.h"
|
||||
#include "plugin.h"
|
||||
#include "util.h"
|
||||
@ -526,4 +528,241 @@ EXPORT int pi_conf_get_int(char *section, char *key, int dflt) {
|
||||
}
|
||||
|
||||
EXPORT void pi_config_set_status(WS_CONNINFO *pwsc, int session, char *fmt, ...) {
|
||||
char *out;
|
||||
va_list ap;
|
||||
|
||||
ASSERT(fmt);
|
||||
if(!fmt)
|
||||
return;
|
||||
|
||||
va_start(ap,fmt);
|
||||
out = util_vasprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
config_set_status(pwsc, session, "%s", out);
|
||||
free(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* allocte an io object
|
||||
*
|
||||
* @returns NULL on malloc error, IOHANDLE otherwise
|
||||
*/
|
||||
EXPORT IOHANDLE pi_io_new(void) {
|
||||
return io_new();
|
||||
}
|
||||
|
||||
/**
|
||||
* open an io object given a printf-style URI
|
||||
*
|
||||
* @param io io handle allocated with pi_io_new
|
||||
* @param fmt printf-style format string for URI (%U URI-encodes strings)
|
||||
* @returns TRUE on success, FALSE otherwise. use io_err* to get error info
|
||||
*/
|
||||
EXPORT int pi_io_open(IOHANDLE io, char *fmt, ...) {
|
||||
char uri_copy[4096];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
io_util_vsnprintf(uri_copy, sizeof(uri_copy), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return io_open(io, "%s", uri_copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* close an open io_object
|
||||
*
|
||||
* @param io handle to close
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
EXPORT int pi_io_close(IOHANDLE io) {
|
||||
return io_close(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* read from an open io handle
|
||||
*
|
||||
* @param io open handle to read from
|
||||
* @param buf buffer to read into
|
||||
* @param len length to read, on return: length read
|
||||
* @returns TRUE on success, FALSE otherwise, len set with bytes read
|
||||
*/
|
||||
EXPORT int pi_io_read(IOHANDLE io, unsigned char *buf, uint32_t *len){
|
||||
return io_read(io, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* read from an io handle with timeout
|
||||
*
|
||||
* Returns FALSE on read error or timeout. Timeout versus
|
||||
* read error condition can be determined by ms. If ms is 0,
|
||||
* then a timeout condition occurred
|
||||
*
|
||||
* @param io open handle to read from
|
||||
* @param buf buffer to read into
|
||||
* @param len length to read, on return: length read
|
||||
* @param ms time to wait (in ms), on return: time left
|
||||
* @returns TRUE on success, FALSE on failure (or timeout)
|
||||
*/
|
||||
EXPORT int pi_io_read_timeout(IOHANDLE io, unsigned char *buf, uint32_t *len, uint32_t *ms) {
|
||||
return io_read_timeout(io, buf, len, ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* write a block of data to an open io handle
|
||||
*
|
||||
* @param io io handle to write to
|
||||
* @param buf buffer to write from
|
||||
* @param len bytes to write to io handle, on return: bytes written
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
EXPORT int pi_io_write(IOHANDLE io, unsigned char *buf, uint32_t *len) {
|
||||
return io_write(io, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* write a printf formatted string to io handle
|
||||
*
|
||||
* @param io io handle to write to
|
||||
* @param fmt printf style format specifier
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
EXPORT int pi_io_printf(IOHANDLE io, char *fmt, ...) {
|
||||
char *out;
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
ASSERT(fmt);
|
||||
if(!fmt)
|
||||
return FALSE;
|
||||
|
||||
va_start(ap,fmt);
|
||||
out = util_vasprintf(fmt,ap);
|
||||
va_end(ap);
|
||||
|
||||
result = io_printf(io,"%s",out);
|
||||
free(out);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the (64-bit) size of a file. Built in URI's use seekability
|
||||
* to determine extent of file, so non-seekable io objects (sockets, etc)
|
||||
* will return IO_E_BADFN.
|
||||
*
|
||||
* @param io io handle to get size of
|
||||
* @param size returns the 64-bit size of file
|
||||
* @returns TRUE on success, FALSE on error (check io_errstr)
|
||||
*/
|
||||
EXPORT int pi_io_size(IOHANDLE io, uint64_t *size) {
|
||||
return io_size(io, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* set the position of file read handle. There are several limitations
|
||||
* to this. Non seekable handles (sockets, etc) won't seek, NOT
|
||||
* EVEN FORWARD!
|
||||
*
|
||||
* FIXME: seeking on buffered file handle makes explode
|
||||
*
|
||||
* @param io handle to set position of
|
||||
* @param offset how far to move
|
||||
* @param whence from where (in lseek style -- SEEK_SET, SEEK_CUR, SEEK_END)
|
||||
* @returns TRUE on success, FALSE otherwise (check io_errstr)
|
||||
*/
|
||||
EXPORT int pi_io_setpos(IOHANDLE io, uint64_t offset, int whence) {
|
||||
return io_setpos(io, offset, whence);
|
||||
}
|
||||
|
||||
/**
|
||||
* get current file position in a stream. Like setpos, this won't work on non-
|
||||
* streamable io handles, and it won't (currently) work on buffered file handles.
|
||||
* in addition, it might behave strangely various filter drivers (ssl, etc)
|
||||
*
|
||||
* @param io io handle to get position for
|
||||
* @param pos on return, the current file position
|
||||
* @returns TRUE on success, FALSE otherwise (see io_errstr)
|
||||
*/
|
||||
EXPORT int pi_io_getpos(IOHANDLE io, uint64_t *pos) {
|
||||
return io_getpos(io, pos);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* turn on buffering for a file handle. This really only makes sense
|
||||
* when doing readlines. Note that you can't currently turn of buffered
|
||||
* mode, so if doing a mix of buffered and unbuffered io, don't buffer the
|
||||
* handle. Also, once the handle is buffered, setpos and getpos won't work
|
||||
* right, and will very likely make Bad Things Happen. You have been
|
||||
* warned.
|
||||
*
|
||||
* @param io handle to buffer
|
||||
* @returns TRUE
|
||||
*/
|
||||
EXPORT int pi_io_buffer(IOHANDLE io) {
|
||||
return io_buffer(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* read a line from the file handle. If the file is opened with
|
||||
* ascii=1, then line ending conversions to/from windows/unix will
|
||||
* take place.
|
||||
*
|
||||
* @param io handle to read line from
|
||||
* @param buf buffer to read line into
|
||||
* @param len size of buffer, on return: bytes read
|
||||
* @returns TRUE on success, FALSE on error (see io_errstr)
|
||||
*/
|
||||
EXPORT int pi_io_readline(IOHANDLE io, unsigned char *buf, uint32_t *len) {
|
||||
return io_readline(io, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* read a line from a file handle with timeout.
|
||||
*
|
||||
* Errors (including timeout) return FALSE. Timeout errors
|
||||
* can be detected because ms=0
|
||||
*
|
||||
* @param io handle to read from
|
||||
* @param buf buffer to read into
|
||||
* @param len size of buffer, on return: bytes read
|
||||
* @param ms timeout, in ms, on return: time remaining
|
||||
* @returns TRUE on success, FALSE otherwise
|
||||
*/
|
||||
EXPORT int pi_io_readline_timeout(IOHANDLE io, unsigned char *buf, uint32_t *len, uint32_t *ms) {
|
||||
return io_readline_timeout(io, buf, len, ms);
|
||||
}
|
||||
|
||||
/**
|
||||
* get error string of last error
|
||||
*
|
||||
* @param io handle to get error of
|
||||
* @returns error string, does not need to be free'd
|
||||
*/
|
||||
EXPORT char* pi_io_errstr(IOHANDLE io) {
|
||||
return io_errstr(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* get native error code
|
||||
*
|
||||
* @param io handle to get error code for
|
||||
* @returns error code (see io-errors.h)
|
||||
*/
|
||||
EXPORT int pi_io_errcode(IOHANDLE io) {
|
||||
return io_errcode(io);
|
||||
}
|
||||
|
||||
/**
|
||||
* dispose of an io handle, freeing up any internally allocated
|
||||
* memory and structs. This implicitly calls io_close, so
|
||||
* you don't *need* to do io_close(hio); io_dispoase(hio);, but I
|
||||
* do anyway. :)
|
||||
*
|
||||
* @param io handle to dispose of
|
||||
*/
|
||||
EXPORT void pi_io_dispose(IOHANDLE io) {
|
||||
return io_dispose(io);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@
|
||||
#define _FF_PLUGINS_H_
|
||||
|
||||
#include "ff-dbstruct.h"
|
||||
#include "ff-plugin-events.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# ifdef _WINDLL
|
||||
@ -40,25 +41,6 @@
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
/* Plugin types */
|
||||
#define PLUGIN_OUTPUT 1
|
||||
#define PLUGIN_SCANNER 2
|
||||
#define PLUGIN_DATABASE 4
|
||||
#define PLUGIN_EVENT 8
|
||||
#define PLUGIN_TRANSCODE 16
|
||||
|
||||
/* plugin event types */
|
||||
#define PLUGIN_EVENT_LOG 0
|
||||
#define PLUGIN_EVENT_FULLSCAN_START 1
|
||||
#define PLUGIN_EVENT_FULLSCAN_END 2
|
||||
#define PLUGIN_EVENT_STARTING 3
|
||||
#define PLUGIN_EVENT_SHUTDOWN 4
|
||||
#define PLUGIN_EVENT_STARTSTREAM 5
|
||||
#define PLUGIN_EVENT_ABORTSTREAM 6
|
||||
#define PLUGIN_EVENT_ENDSTREAM 7
|
||||
|
||||
#define PLUGIN_VERSION 1
|
||||
|
||||
#ifndef E_FATAL
|
||||
# define E_FATAL 0
|
||||
# define E_LOG 1
|
||||
@ -72,6 +54,7 @@
|
||||
#define COUNT_PLAYLISTS 1
|
||||
|
||||
struct tag_ws_conninfo;
|
||||
typedef void* HANDLE;
|
||||
|
||||
/* Functions that must be exported by different plugin types */
|
||||
typedef struct tag_plugin_output_fn {
|
||||
@ -178,11 +161,29 @@ extern EXPORT int pi_db_wait_update(struct tag_ws_conninfo *);
|
||||
extern EXPORT char *pi_conf_alloc_string(char *section, char *key, char *dflt);
|
||||
extern EXPORT void pi_conf_dispose_string(char *str);
|
||||
extern EXPORT int pi_conf_get_int(char *section, char *key, int dflt);
|
||||
|
||||
extern EXPORT void pi_config_set_status(struct tag_ws_conninfo *pwsc, int session, char *fmt, ...);
|
||||
|
||||
/* io functions */
|
||||
extern EXPORT HANDLE pi_io_new(void);
|
||||
extern EXPORT int pi_io_open(HANDLE io, char *fmt, ...);
|
||||
extern EXPORT int pi_io_close(HANDLE io);
|
||||
extern EXPORT int pi_io_read(HANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern EXPORT int pi_io_read_timeout(HANDLE io, unsigned char *buf, uint32_t *len, uint32_t *ms);
|
||||
extern EXPORT int pi_io_write(HANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern EXPORT int pi_io_printf(HANDLE io, char *fmt, ...);
|
||||
extern EXPORT int pi_io_size(HANDLE io, uint64_t *size);
|
||||
extern EXPORT int pi_io_setpos(HANDLE io, uint64_t offset, int whence);
|
||||
extern EXPORT int pi_io_getpos(HANDLE io, uint64_t *pos);
|
||||
extern EXPORT int pi_io_buffer(HANDLE io); /* unimplemented */
|
||||
extern EXPORT int pi_io_readline(HANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern EXPORT int pi_io_readline_timeout(HANDLE io, unsigned char *buf, uint32_t *len, uint32_t *ms);
|
||||
extern EXPORT char* pi_io_errstr(HANDLE io);
|
||||
extern EXPORT int pi_io_errcode(HANDLE io);
|
||||
extern EXPORT void pi_io_dispose(HANDLE io);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _FF_PLUGINS_ */
|
||||
|
62
src/io.c
62
src/io.c
@ -113,7 +113,7 @@ int io_setpos(IO_PRIVHANDLE *phandle, uint64_t offset, int whence);
|
||||
int io_getpos(IO_PRIVHANDLE *phandle, uint64_t *pos);
|
||||
int io_buffer(IO_PRIVHANDLE *phandle);
|
||||
int io_readline(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len);
|
||||
int io_readline_timed(IO_PRIVHANDLE *phandle, unsigned char *buf,
|
||||
int io_readline_timeout(IO_PRIVHANDLE *phandle, unsigned char *buf,
|
||||
uint32_t *len, uint32_t *ms);
|
||||
char *io_errstr(IO_PRIVHANDLE *phandle);
|
||||
void io_dispose(IO_PRIVHANDLE *phandle);
|
||||
@ -404,7 +404,7 @@ int io_urldecode(char *str) {
|
||||
char *current,*dst;
|
||||
int digit1, digit2;
|
||||
char *hexdigits = "0123456789abcdef";
|
||||
|
||||
|
||||
current = dst = str;
|
||||
while(*current) {
|
||||
switch(*current) {
|
||||
@ -419,7 +419,7 @@ int io_urldecode(char *str) {
|
||||
return FALSE;
|
||||
}
|
||||
current++;
|
||||
|
||||
|
||||
if(!strchr(hexdigits,tolower(*current))) {
|
||||
io_err_printf(IO_LOG_DEBUG,"urldecode: bad hex digit\n");
|
||||
return FALSE;
|
||||
@ -441,7 +441,7 @@ int io_urldecode(char *str) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*dst = '\0';
|
||||
return TRUE;
|
||||
}
|
||||
@ -664,7 +664,7 @@ int io_open(IO_PRIVHANDLE *phandle, char *fmt, ...) {
|
||||
|
||||
if(path_part)
|
||||
io_urldecode(path_part);
|
||||
|
||||
|
||||
/* find the start of the options */
|
||||
options_part = strchr(path_part,'?');
|
||||
if(options_part) {
|
||||
@ -771,7 +771,7 @@ int io_read_timeout(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len,
|
||||
ASSERT(phandle->fnptr->fn_read);
|
||||
|
||||
io_err_printf(IO_LOG_SPAM,"entering io_read_timeout\n");
|
||||
|
||||
|
||||
if((!phandle) || (!phandle->open) || (!phandle->fnptr)) {
|
||||
io_err(phandle,IO_E_NOTINIT);
|
||||
*len = 0;
|
||||
@ -826,7 +826,7 @@ int io_read(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
ASSERT(phandle->fnptr->fn_read);
|
||||
|
||||
io_err_printf(IO_LOG_SPAM,"entering io_read\n");
|
||||
|
||||
|
||||
if((!phandle) || (!phandle->open) || (!phandle->fnptr)) {
|
||||
io_err(phandle,IO_E_NOTINIT);
|
||||
*len = 0;
|
||||
@ -846,7 +846,7 @@ int io_read(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
/* fill as much as possible from buffer */
|
||||
if(phandle->buffer_offset < phandle->buffer_len) {
|
||||
io_err_printf(IO_LOG_SPAM,"Fulfilling from buffer\n");
|
||||
read_size = max_len;
|
||||
read_size = max_len;
|
||||
if(read_size > (phandle->buffer_len - phandle->buffer_offset))
|
||||
read_size = phandle->buffer_len - phandle->buffer_offset;
|
||||
memcpy((void*)buf_ptr,(void*)&phandle->buffer[phandle->buffer_offset], read_size);
|
||||
@ -863,7 +863,7 @@ int io_read(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
return FALSE;
|
||||
}
|
||||
phandle->buffer_offset = 0;
|
||||
if(phandle->buffer_len == 0)
|
||||
if(phandle->buffer_len == 0)
|
||||
return TRUE; /* can't read any more */
|
||||
}
|
||||
}
|
||||
@ -894,17 +894,17 @@ int io_read(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
* @returns TRUE on success, FALSE with ms=0 on timeout, or FALSE
|
||||
* on other kind of error
|
||||
*/
|
||||
int io_readline_timed(IO_PRIVHANDLE *phandle, unsigned char *buf,
|
||||
int io_readline_timeout(IO_PRIVHANDLE *phandle, unsigned char *buf,
|
||||
uint32_t *len, uint32_t *ms) {
|
||||
uint32_t numread = 0;
|
||||
uint32_t to_read;
|
||||
int ascii = 0;
|
||||
|
||||
|
||||
if(io_option_get(phandle,"ascii",NULL))
|
||||
ascii = 1;
|
||||
|
||||
io_err_printf(IO_LOG_SPAM,"entering readline_timed\n");
|
||||
|
||||
|
||||
io_err_printf(IO_LOG_SPAM,"entering readline_timeout\n");
|
||||
|
||||
while(numread < (*len - 1)) {
|
||||
to_read = 1;
|
||||
if(io_read_timeout(phandle, buf + numread, &to_read, ms)) {
|
||||
@ -946,7 +946,7 @@ int io_readline(IO_PRIVHANDLE *phandle, unsigned char *buf,
|
||||
uint32_t *len) {
|
||||
|
||||
io_err_printf(IO_LOG_SPAM,"entering io_readline\n");
|
||||
return io_readline_timed(phandle, buf, len, NULL);
|
||||
return io_readline_timeout(phandle, buf, len, NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -969,13 +969,13 @@ int io_write(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
uint32_t ascii_len;
|
||||
uint32_t index;
|
||||
uint32_t real_len;
|
||||
|
||||
|
||||
ASSERT(io_initialized); /* call io_init first */
|
||||
ASSERT(phandle);
|
||||
ASSERT(phandle->open);
|
||||
ASSERT(phandle->fnptr);
|
||||
ASSERT(phandle->fnptr->fn_write);
|
||||
|
||||
|
||||
if((!phandle) || (!phandle->open) || (!phandle->fnptr)) {
|
||||
io_err(phandle,IO_E_NOTINIT);
|
||||
*len = 0;
|
||||
@ -1006,7 +1006,7 @@ int io_write(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
io_err_printf(IO_LOG_FATAL,"Could not alloc buffer in io_printf\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
must_free = TRUE;
|
||||
dst = real_buffer;
|
||||
for(index = 0; index < *len; index++) {
|
||||
@ -1019,7 +1019,7 @@ int io_write(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
real_buffer = buf; /* just write what was passed */
|
||||
real_len = *len;
|
||||
}
|
||||
|
||||
|
||||
result = phandle->fnptr->fn_write(phandle,real_buffer,&real_len);
|
||||
|
||||
if(!result)
|
||||
@ -1030,7 +1030,7 @@ int io_write(IO_PRIVHANDLE *phandle, unsigned char *buf, uint32_t *len) {
|
||||
real_len = *len;
|
||||
free(real_buffer);
|
||||
}
|
||||
|
||||
|
||||
*len = real_len;
|
||||
return result;
|
||||
}
|
||||
@ -1083,7 +1083,7 @@ int io_printf(IO_PRIVHANDLE *phandle, char *fmt, ...) {
|
||||
if(!io_write(phandle,(unsigned char *)outbuf,&len) || (len != new_size)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -1194,10 +1194,10 @@ int io_getpos(IO_PRIVHANDLE *phandle, uint64_t *pos) {
|
||||
*/
|
||||
int io_buffer(IO_PRIVHANDLE *phandle) {
|
||||
ASSERT(phandle);
|
||||
|
||||
if(!phandle)
|
||||
|
||||
if(!phandle)
|
||||
return FALSE;
|
||||
|
||||
|
||||
if(phandle->buffer)
|
||||
return TRUE;
|
||||
|
||||
@ -1206,9 +1206,9 @@ int io_buffer(IO_PRIVHANDLE *phandle) {
|
||||
io_err_printf(IO_LOG_FATAL,"Malloc error in io_buffer\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
phandle->buffering=1;
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -1285,7 +1285,7 @@ void io_err(IO_PRIVHANDLE *phandle, uint32_t errorcode) {
|
||||
free(phandle->err_str);
|
||||
|
||||
phandle->err = errorcode;
|
||||
|
||||
|
||||
if(errorcode) {
|
||||
phandle->err_str = strdup(io_err_strings[errorcode & 0x00FFFFFF]);
|
||||
phandle->err = errorcode;
|
||||
@ -1778,10 +1778,10 @@ char *io_file_geterrmsg(IO_PRIVHANDLE *phandle, ERR_T *code, int *is_local) {
|
||||
if(!priv) {
|
||||
return "file not initialized";
|
||||
}
|
||||
|
||||
|
||||
if(code)
|
||||
*code = priv->err;
|
||||
|
||||
|
||||
if(priv->local_err) {
|
||||
if(is_local)
|
||||
*is_local = TRUE;
|
||||
@ -2400,7 +2400,7 @@ void io_socket_seterr(IO_PRIVHANDLE *phandle, ERR_T errcode) {
|
||||
*/
|
||||
char *io_socket_geterrmsg(IO_PRIVHANDLE *phandle, ERR_T *code, int *is_local) {
|
||||
IO_SOCKET_PRIV *priv;
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
char lpErrorBuf[256];
|
||||
#endif
|
||||
@ -2410,7 +2410,7 @@ char *io_socket_geterrmsg(IO_PRIVHANDLE *phandle, ERR_T *code, int *is_local) {
|
||||
priv = (IO_SOCKET_PRIV*)(phandle->private);
|
||||
if(*code)
|
||||
*code = priv->err;
|
||||
|
||||
|
||||
if(priv->local_err) {
|
||||
*is_local = TRUE;
|
||||
return strdup(io_socket_err_strings[priv->err & 0x00FFFFFF]);
|
||||
|
3
src/io.h
3
src/io.h
@ -67,9 +67,6 @@ extern int io_close(IOHANDLE io);
|
||||
extern int io_read(IOHANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern int io_read_timeout(IOHANDLE io, unsigned char *buf, uint32_t *len,
|
||||
uint32_t *ms);
|
||||
extern int io_readline(IOHANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern int io_readline_timed(IOHANDLE io, unsigned char *buf, uint32_t *len,
|
||||
uint32_t *ms);
|
||||
extern int io_write(IOHANDLE io, unsigned char *buf, uint32_t *len);
|
||||
extern int io_printf(IOHANDLE io, char *fmt, ...);
|
||||
extern int io_size(IOHANDLE io, uint64_t *size);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "webserver.h"
|
||||
#include "xml-rpc.h"
|
||||
#include "db-generic.h"
|
||||
#include "ff-plugin-events.h"
|
||||
|
||||
extern int plugin_init(void);
|
||||
extern int plugin_load(char **pe, char *path);
|
||||
@ -49,6 +50,4 @@ extern int plugin_ssc_transcode(WS_CONNINFO *pwsc, MP3FILE *pmp3, int offset, in
|
||||
#define PLUGIN_E_NOLOAD 1
|
||||
#define PLUGIN_E_BADFUNCS 2
|
||||
|
||||
#include "ff-plugins.h"
|
||||
|
||||
#endif /* _PLUGIN_H_ */
|
||||
|
124
src/webserver.c
124
src/webserver.c
@ -99,7 +99,7 @@ typedef struct tag_ws_private {
|
||||
WSCONFIG wsconfig;
|
||||
WS_HANDLER handlers;
|
||||
WS_CONNLIST connlist;
|
||||
|
||||
|
||||
IOHANDLE hserver;
|
||||
int stop;
|
||||
int running;
|
||||
@ -197,7 +197,7 @@ void ws_set_errhandler(void(*err_handler)(int, char*)) {
|
||||
|
||||
|
||||
/**
|
||||
* by default, just dump to stdout
|
||||
* by default, just dump to stdout
|
||||
*/
|
||||
void ws_default_errhandler(int level, char *msg) {
|
||||
fprintf(stderr,"%d: %s", level, msg);
|
||||
@ -218,7 +218,7 @@ int ws_lock_unsafe(void) {
|
||||
int retval=TRUE;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
if((err=pthread_mutex_lock(&ws_unsafe))) {
|
||||
ws_dprintf(L_WS_FATAL,"Cannot lock mutex: %s\n",strerror(err));
|
||||
retval=FALSE;
|
||||
@ -240,7 +240,7 @@ int ws_unlock_unsafe(void) {
|
||||
int retval=TRUE;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
if((err=pthread_mutex_unlock(&ws_unsafe))) {
|
||||
ws_dprintf(L_WS_FATAL,"Cannot unlock mutex: %s\n",strerror(err));
|
||||
retval=FALSE;
|
||||
@ -281,7 +281,7 @@ WSHANDLE ws_init(WSCONFIG *config) {
|
||||
ws_dprintf(L_WS_SPAM,"Malloc error: %s\n",strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
memcpy(&pwsp->wsconfig,config,sizeof(WS_PRIVATE));
|
||||
pwsp->connlist.next=NULL;
|
||||
pwsp->running=0;
|
||||
@ -299,7 +299,7 @@ WSHANDLE ws_init(WSCONFIG *config) {
|
||||
ws_dprintf(L_WS_LOG,"Error in pthread_mutex_init: %s\n",strerror(err));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return (WSHANDLE)pwsp;
|
||||
}
|
||||
@ -324,7 +324,7 @@ int ws_start(WSHANDLE ws) {
|
||||
WS_PRIVATE *pwsp = (WS_PRIVATE*)ws;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
/* this is kind of stupid, but is easier to fix once here
|
||||
* rather than mucking with differences in sockets on windows/unix
|
||||
*/
|
||||
@ -386,7 +386,7 @@ void ws_remove_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
|
||||
WS_CONNLIST *pHead, *pTail;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
ws_lock_connlist(pwsp);
|
||||
|
||||
pTail=&(pwsp->connlist);
|
||||
@ -424,7 +424,7 @@ void ws_add_dispatch_thread(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
|
||||
WS_CONNLIST *pNew;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
pNew=(WS_CONNLIST*)malloc(sizeof(WS_CONNLIST));
|
||||
pNew->next=NULL;
|
||||
pNew->pwsc=pwsc;
|
||||
@ -461,7 +461,7 @@ int ws_stop(WSHANDLE ws) {
|
||||
void *result;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
/* free the ws_handlers */
|
||||
while(pwsp->handlers.next) {
|
||||
current=pwsp->handlers.next;
|
||||
@ -534,7 +534,7 @@ void *ws_mainthread(void *arg) {
|
||||
struct in_addr hostaddr;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
while(1) {
|
||||
pwsc=(WS_CONNINFO*)malloc(sizeof(WS_CONNINFO));
|
||||
if(!pwsc) {
|
||||
@ -551,8 +551,8 @@ void *ws_mainthread(void *arg) {
|
||||
hnew = io_new();
|
||||
if(!hnew)
|
||||
ws_dprintf(L_WS_FATAL,"Malloc error in io_new()");
|
||||
|
||||
if(!io_listen_accept(pwsp->hserver,hnew,&hostaddr)) {
|
||||
|
||||
if(!io_listen_accept(pwsp->hserver,hnew,&hostaddr)) {
|
||||
ws_dprintf(L_WS_LOG,"Dispatcher: accept failed: %s\n",
|
||||
io_errstr(pwsp->hserver));
|
||||
io_close(pwsp->hserver);
|
||||
@ -606,7 +606,7 @@ void *ws_mainthread(void *arg) {
|
||||
*
|
||||
* Mainly, we just want to make sure that any
|
||||
* allocated memory has been freed
|
||||
*
|
||||
*
|
||||
* @param pwsc connection to close
|
||||
* @returns TRUE on success
|
||||
*/
|
||||
@ -614,7 +614,7 @@ void ws_close(WS_CONNINFO *pwsc) {
|
||||
WS_PRIVATE *pwsp = (WS_PRIVATE *)(pwsc->pwsp);
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
ws_dprintf(L_WS_DBG,"Thread %d: Terminating\n",pwsc->threadno);
|
||||
ws_dprintf(L_WS_DBG,"Thread %d: Freeing request headers\n",pwsc->threadno);
|
||||
ws_freearglist(&pwsc->request_headers);
|
||||
@ -696,7 +696,7 @@ void ws_emitheaders(WS_CONNINFO *pwsc) {
|
||||
* get headers. This should really only be called if
|
||||
* the method if post. This will fill in the request_headers
|
||||
* linked list.
|
||||
*
|
||||
*
|
||||
* @param pwsc session to parse post vars for
|
||||
* @returns TRUE on success
|
||||
*/
|
||||
@ -705,9 +705,9 @@ int ws_getpostvars(WS_CONNINFO *pwsc) {
|
||||
unsigned char *buffer;
|
||||
uint32_t length;
|
||||
uint32_t ms;
|
||||
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
content_length = ws_getarg(&pwsc->request_headers,"Content-Length");
|
||||
if(!content_length) {
|
||||
ws_set_err(pwsc,E_WS_CONTENTLEN);
|
||||
@ -752,7 +752,7 @@ int ws_getpostvars(WS_CONNINFO *pwsc) {
|
||||
ws_dprintf(L_WS_DBG,"Thread %d: Read post vars: %s\n",pwsc->threadno,buffer);
|
||||
|
||||
if(!ws_getgetvars(pwsc,(char*)buffer)) {
|
||||
/* assume error was set already */
|
||||
/* assume error was set already */
|
||||
free(buffer);
|
||||
ws_dprintf(L_WS_LOG,"Could not parse get vars\n");
|
||||
return FALSE;
|
||||
@ -855,8 +855,8 @@ int ws_getheaders(WS_CONNINFO *pwsc) {
|
||||
* Olive/HiFidelio issue with not honoring "Connection: close", as is
|
||||
* *REQUIRED* by RFC for HTTP 1.1 browsers, and ignored by HiFidelio.
|
||||
*
|
||||
* HiFidelio programmers, take note -- if you fixed your HTTP
|
||||
* implementation to be RFC compliant, I could provide transcoding
|
||||
* HiFidelio programmers, take note -- if you fixed your HTTP
|
||||
* implementation to be RFC compliant, I could provide transcoding
|
||||
* for your clients. (And they want it, judging by my forums)
|
||||
*
|
||||
* @param pwsc session to check for encoding style
|
||||
@ -885,7 +885,7 @@ int ws_encoding_hack(WS_CONNINFO *pwsc) {
|
||||
*
|
||||
* @params pwsc the session to parse vars for
|
||||
* @params string the argument part of the URI as requested by the client
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
int ws_getgetvars(WS_CONNINFO *pwsc, char *string) {
|
||||
char *first, *last, *middle;
|
||||
@ -940,7 +940,7 @@ int ws_getgetvars(WS_CONNINFO *pwsc, char *string) {
|
||||
* Main dispatch thread. This gets the request, reads the
|
||||
* headers, decodes the GET'd or POST'd variables,
|
||||
* then decides what function should service the request
|
||||
*
|
||||
*
|
||||
* @param arg a pointer to the WS_CONNINFO struct we are servicing
|
||||
*/
|
||||
void *ws_dispatcher(void *arg) {
|
||||
@ -969,7 +969,7 @@ void *ws_dispatcher(void *arg) {
|
||||
// and decide where to dispatch it
|
||||
ms = 1800 * 1000;
|
||||
len = sizeof(buffer);
|
||||
if(!io_readline_timed(pwsc->hclient,(unsigned char *)buffer,&len,&ms) || (!len)) {
|
||||
if(!io_readline_timeout(pwsc->hclient,(unsigned char *)buffer,&len,&ms) || (!len)) {
|
||||
ws_set_err(pwsc,E_WS_TIMEOUT);
|
||||
pwsc->error=errno;
|
||||
pwsc->close=1;
|
||||
@ -1161,7 +1161,7 @@ void *ws_dispatcher(void *arg) {
|
||||
}
|
||||
ws_close(pwsc);
|
||||
}
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return NULL;
|
||||
}
|
||||
@ -1169,7 +1169,7 @@ void *ws_dispatcher(void *arg) {
|
||||
|
||||
/**
|
||||
* Write a printf-style output to a connection.
|
||||
*
|
||||
*
|
||||
* FIXME: This has a max buffer length of 1024, and shold
|
||||
* be fixed to use a variable-length buffer. Note to self:
|
||||
* use io_printf to write a platform-indepentent aprintf, or
|
||||
@ -1197,7 +1197,7 @@ int ws_writefd(WS_CONNINFO *pwsc, char *fmt, ...) {
|
||||
ws_dprintf(L_WS_LOG,"Error writing to client socket: %s",
|
||||
io_errstr(pwsc->hclient));
|
||||
}
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return len;
|
||||
}
|
||||
@ -1212,14 +1212,14 @@ int ws_writefd(WS_CONNINFO *pwsc, char *fmt, ...) {
|
||||
*/
|
||||
int ws_writebinary(WS_CONNINFO *pwsc, char *data, int len) {
|
||||
uint32_t bytes_written;
|
||||
|
||||
|
||||
WS_ENTER();
|
||||
bytes_written = (uint32_t) len;
|
||||
if(!io_write(pwsc->hclient, (unsigned char *)data, &bytes_written)) {
|
||||
ws_dprintf(L_WS_LOG,"Error writing to client socket: %s",
|
||||
ws_dprintf(L_WS_LOG,"Error writing to client socket: %s",
|
||||
io_errstr(pwsc->hclient));
|
||||
}
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return (int)bytes_written;
|
||||
}
|
||||
@ -1242,7 +1242,7 @@ int ws_returnerror(WS_CONNINFO *pwsc,int error, char *description) {
|
||||
char *err_str;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
ws_dprintf(L_WS_WARN,"Thread %d: Entering ws_returnerror (%d: %s)\n",
|
||||
pwsc->threadno,error,description);
|
||||
ws_writefd(pwsc,"HTTP/1.1 %d %s\r\n",error,description);
|
||||
@ -1271,7 +1271,7 @@ int ws_returnerror(WS_CONNINFO *pwsc,int error, char *description) {
|
||||
ws_writefd(pwsc,"\r\n<H1>%s</H1>\r\n",description);
|
||||
ws_writefd(pwsc,"Error %d\r\n<hr>\r\n",error);
|
||||
ws_writefd(pwsc,"<i>" PACKAGE ": %s\r\n<br>",VERSION);
|
||||
|
||||
|
||||
ws_get_err(pwsc,&err_code, &err_str);
|
||||
if(E_WS_SUCCESS != err_code)
|
||||
ws_writefd(pwsc,"Error: %s\r\n",strerror(errno));
|
||||
@ -1341,7 +1341,7 @@ void ws_defaulthandler(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
|
||||
pwsc->threadno,resolved_path,strerror(errno));
|
||||
ws_returnerror(pwsc,404,"Not found");
|
||||
ws_close(pwsc);
|
||||
|
||||
|
||||
io_dispose(hfile);
|
||||
WS_EXIT();
|
||||
return;
|
||||
@ -1361,7 +1361,7 @@ void ws_defaulthandler(WS_PRIVATE *pwsp, WS_CONNINFO *pwsc) {
|
||||
|
||||
io_close(hfile);
|
||||
io_dispose(hfile);
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return;
|
||||
}
|
||||
@ -1469,7 +1469,7 @@ int ws_addarg(ARGLIST *root, char *key, char *fmt, ...) {
|
||||
char value[MAX_LINEBUFFER];
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
va_start(ap,fmt);
|
||||
vsnprintf(value,sizeof(value),fmt,ap);
|
||||
va_end(ap);
|
||||
@ -1531,7 +1531,7 @@ char *ws_urldecode(char *string, int space_as_plus) {
|
||||
int val=0;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
pnew=(char*)malloc(strlen(string)+1);
|
||||
if(!pnew) {
|
||||
WS_EXIT();
|
||||
@ -1584,7 +1584,7 @@ char *ws_urldecode(char *string, int space_as_plus) {
|
||||
|
||||
|
||||
/**
|
||||
* Register a page and auth handler.
|
||||
* Register a page and auth handler.
|
||||
*
|
||||
* @param ws pointer to private webserver struct
|
||||
* @param stem the prefix of the handled web namespace ("/upnp", etc)
|
||||
@ -1616,7 +1616,7 @@ int ws_registerhandler(WSHANDLE ws, char *stem,
|
||||
phandler->next=pwsp->handlers.next;
|
||||
pwsp->handlers.next=phandler;
|
||||
ws_unlock_unsafe();
|
||||
|
||||
|
||||
WS_EXIT();
|
||||
return TRUE;
|
||||
}
|
||||
@ -1698,9 +1698,9 @@ int ws_decodepassword(char *header, char **username, char **password) {
|
||||
*password=NULL;
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
ws_lock_unsafe();
|
||||
|
||||
|
||||
if(!ws_xlat_init) {
|
||||
ws_xlat_init=1;
|
||||
|
||||
@ -1717,7 +1717,7 @@ int ws_decodepassword(char *header, char **username, char **password) {
|
||||
ws_xlat['+'] = 62;
|
||||
ws_xlat['/'] = 63;
|
||||
}
|
||||
|
||||
|
||||
ws_unlock_unsafe();
|
||||
|
||||
/* xlat table is initialized */
|
||||
@ -1812,7 +1812,7 @@ int ws_addresponseheader(WS_CONNINFO *pwsc, char *header, char *fmt, ...) {
|
||||
char value[MAX_LINEBUFFER];
|
||||
|
||||
WS_ENTER();
|
||||
|
||||
|
||||
va_start(ap,fmt);
|
||||
vsnprintf(value,sizeof(value),fmt,ap);
|
||||
va_end(ap);
|
||||
@ -2005,7 +2005,7 @@ int ws_copyfile(WS_CONNINFO *pwsc, IOHANDLE hfile, uint64_t *bytes_copied) {
|
||||
uint64_t total_bytes = 0;
|
||||
uint32_t bytes_read = 0;
|
||||
uint32_t bytes_written = 0;
|
||||
|
||||
|
||||
ASSERT(pwsc);
|
||||
if(!pwsc)
|
||||
return -1; /* error handling! */
|
||||
@ -2018,12 +2018,12 @@ int ws_copyfile(WS_CONNINFO *pwsc, IOHANDLE hfile, uint64_t *bytes_copied) {
|
||||
*bytes_copied = total_bytes;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
if(bytes_written != bytes_read) {
|
||||
ws_dprintf(L_WS_LOG,"Internal error in ws_copyfile\n");
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
total_bytes += bytes_read;
|
||||
}
|
||||
|
||||
@ -2032,10 +2032,10 @@ int ws_copyfile(WS_CONNINFO *pwsc, IOHANDLE hfile, uint64_t *bytes_copied) {
|
||||
} else {
|
||||
ws_dprintf(L_WS_LOG,"Read error %s\n",io_errstr(hfile));
|
||||
}
|
||||
|
||||
|
||||
if(bytes_copied)
|
||||
*bytes_copied = total_bytes;
|
||||
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
@ -2057,7 +2057,7 @@ char *ws_uri(WS_CONNINFO *pwsc) {
|
||||
*/
|
||||
void ws_should_close(WS_CONNINFO *pwsc, int should_close) {
|
||||
ASSERT(pwsc);
|
||||
|
||||
|
||||
pwsc->close = should_close;
|
||||
}
|
||||
|
||||
@ -2069,7 +2069,7 @@ void ws_should_close(WS_CONNINFO *pwsc, int should_close) {
|
||||
*/
|
||||
extern int ws_threadno(WS_CONNINFO *pwsc) {
|
||||
ASSERT(pwsc);
|
||||
|
||||
|
||||
if(pwsc)
|
||||
return pwsc->threadno;
|
||||
return 0;
|
||||
@ -2077,17 +2077,17 @@ extern int ws_threadno(WS_CONNINFO *pwsc) {
|
||||
|
||||
/**
|
||||
* return the hostname of the connected endpoint
|
||||
*
|
||||
*
|
||||
* @param pwsc connection to get endpoint for
|
||||
*/
|
||||
extern char *ws_hostname(WS_CONNINFO *pwsc) {
|
||||
ASSERT(pwsc);
|
||||
ASSERT(pwsc->hostname);
|
||||
|
||||
|
||||
if((pwsc) && (pwsc->hostname)) {
|
||||
return pwsc->hostname;
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2107,19 +2107,19 @@ int ws_set_err(WS_CONNINFO *pwsc, int ws_error) {
|
||||
#endif
|
||||
|
||||
ASSERT(pwsc);
|
||||
|
||||
|
||||
if(!pwsc)
|
||||
return FALSE;
|
||||
|
||||
|
||||
if(pwsc->err_msg)
|
||||
free(pwsc->err_msg);
|
||||
|
||||
|
||||
pwsc->err_code = ws_error;
|
||||
ws_should_close(pwsc,TRUE); /* close the session on error */
|
||||
|
||||
if(E_WS_SUCCESS == ws_error)
|
||||
return TRUE;
|
||||
|
||||
|
||||
if(E_WS_NATIVE == ws_error) {
|
||||
#ifdef WIN32
|
||||
pwsc->err_native = GetLastError();
|
||||
@ -2131,9 +2131,9 @@ int ws_set_err(WS_CONNINFO *pwsc, int ws_error) {
|
||||
#else
|
||||
pwsc->err_native = errno;
|
||||
pwsc->err_msg = strdup(strerror(pwsc->err_native));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2142,7 +2142,7 @@ int ws_set_err(WS_CONNINFO *pwsc, int ws_error) {
|
||||
* Note that the error message is a pointer to an internal string.
|
||||
* The error isn't valid of other socket operations take place. The
|
||||
* error should be dup'ed or used immediately.
|
||||
*
|
||||
*
|
||||
* Sample:
|
||||
*
|
||||
* char *errstr;
|
||||
@ -2161,11 +2161,11 @@ int ws_get_err(WS_CONNINFO *pwsc, int *errcode, char **err_msg) {
|
||||
|
||||
if(!pwsc)
|
||||
return FALSE;
|
||||
|
||||
|
||||
if(errcode) {
|
||||
*errcode = pwsc->err_code;
|
||||
}
|
||||
|
||||
|
||||
if(err_msg) {
|
||||
if(E_WS_NATIVE != pwsc->err_code) {
|
||||
*err_msg = ws_errors[pwsc->err_code];
|
||||
@ -2173,7 +2173,7 @@ int ws_get_err(WS_CONNINFO *pwsc, int *errcode, char **err_msg) {
|
||||
*err_msg = pwsc->err_msg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user