relabelled all log outputs
This commit is contained in:
parent
0219d7460a
commit
0f3cc61875
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
|||
VERSION = 1.2.2
|
||||
VERSION = 1.2.3
|
||||
|
||||
CFLAGS += -O2 -Wall -Wextra -Wshadow -rdynamic -D_GNU_SOURCE\
|
||||
-D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\
|
||||
|
|
1447
src/cache.c
1447
src/cache.c
File diff suppressed because it is too large
Load Diff
42
src/config.c
42
src/config.c
|
@ -28,46 +28,46 @@ ConfigStruct CONFIG;
|
|||
*/
|
||||
void Config_init(void)
|
||||
{
|
||||
CONFIG.mode = NORMAL;
|
||||
CONFIG.mode = NORMAL;
|
||||
|
||||
CONFIG.log_level = log_level_init();
|
||||
CONFIG.log_type = log_level_init();
|
||||
|
||||
/*---------------- Network related --------------*/
|
||||
CONFIG.http_username = NULL;
|
||||
CONFIG.http_username = NULL;
|
||||
|
||||
CONFIG.http_password = NULL;
|
||||
CONFIG.http_password = NULL;
|
||||
|
||||
CONFIG.proxy = NULL;
|
||||
CONFIG.proxy = NULL;
|
||||
|
||||
CONFIG.proxy_username = NULL;
|
||||
CONFIG.proxy_username = NULL;
|
||||
|
||||
CONFIG.proxy_password = NULL;
|
||||
CONFIG.proxy_password = NULL;
|
||||
|
||||
CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
|
||||
CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
|
||||
|
||||
CONFIG.user_agent = DEFAULT_USER_AGENT;
|
||||
CONFIG.user_agent = DEFAULT_USER_AGENT;
|
||||
|
||||
CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC;
|
||||
CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC;
|
||||
|
||||
CONFIG.no_range_check = 0;
|
||||
CONFIG.no_range_check = 0;
|
||||
|
||||
CONFIG.insecure_tls = 0;
|
||||
CONFIG.insecure_tls = 0;
|
||||
|
||||
/*--------------- Cache related ---------------*/
|
||||
CONFIG.cache_enabled = 0;
|
||||
CONFIG.cache_enabled = 0;
|
||||
|
||||
CONFIG.cache_dir = NULL;
|
||||
CONFIG.cache_dir = NULL;
|
||||
|
||||
CONFIG.data_blksz = DEFAULT_DATA_BLKSZ;
|
||||
CONFIG.data_blksz = DEFAULT_DATA_BLKSZ;
|
||||
|
||||
CONFIG.max_segbc = DEFAULT_MAX_SEGBC;
|
||||
CONFIG.max_segbc = DEFAULT_MAX_SEGBC;
|
||||
|
||||
/*-------------- Sonic related -------------*/
|
||||
CONFIG.sonic_username = NULL;
|
||||
CONFIG.sonic_username = NULL;
|
||||
|
||||
CONFIG.sonic_password = NULL;
|
||||
CONFIG.sonic_password = NULL;
|
||||
|
||||
CONFIG.sonic_id3 = 0;
|
||||
CONFIG.sonic_id3 = 0;
|
||||
|
||||
CONFIG.sonic_insecure = 0;
|
||||
}
|
||||
CONFIG.sonic_insecure = 0;
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ typedef struct {
|
|||
/** \brief Operation Mode */
|
||||
OperationMode mode;
|
||||
/** \brief Current log level */
|
||||
int log_level;
|
||||
int log_type;
|
||||
/*---------------- Network related --------------*/
|
||||
/** \brief HTTP username */
|
||||
char *http_username;
|
||||
|
|
218
src/fuse_local.c
218
src/fuse_local.c
|
@ -2,7 +2,9 @@
|
|||
|
||||
#include "cache.h"
|
||||
|
||||
/* must be included before including <fuse.h> */
|
||||
/*
|
||||
* must be included before including <fuse.h>
|
||||
*/
|
||||
#define FUSE_USE_VERSION 26
|
||||
#include <fuse.h>
|
||||
|
||||
|
@ -12,105 +14,106 @@
|
|||
|
||||
static void *fs_init(struct fuse_conn_info *conn)
|
||||
{
|
||||
(void) conn;
|
||||
return NULL;
|
||||
(void)conn;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** \brief release an opened file */
|
||||
static int fs_release(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
(void) path;
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
Cache_close((Cache *)fi->fh);
|
||||
}
|
||||
return 0;
|
||||
(void)path;
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
Cache_close((Cache *) fi->fh);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** \brief return the attributes for a single file indicated by path */
|
||||
static int fs_getattr(const char *path, struct stat *stbuf)
|
||||
{
|
||||
int res = 0;
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
int res = 0;
|
||||
memset(stbuf, 0, sizeof(struct stat));
|
||||
|
||||
if (!strcmp(path, "/")) {
|
||||
stbuf->st_mode = S_IFDIR | 0755;
|
||||
stbuf->st_nlink = 1;
|
||||
} else {
|
||||
Link *link = path_to_Link(path);
|
||||
if (!link) {
|
||||
return -ENOENT;
|
||||
}
|
||||
struct timespec spec;
|
||||
spec.tv_sec = link->time;
|
||||
if (!strcmp(path, "/")) {
|
||||
stbuf->st_mode = S_IFDIR | 0755;
|
||||
stbuf->st_nlink = 1;
|
||||
} else {
|
||||
Link *link = path_to_Link(path);
|
||||
if (!link) {
|
||||
return -ENOENT;
|
||||
}
|
||||
struct timespec spec;
|
||||
spec.tv_sec = link->time;
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
stbuf->st_mtimespec = spec;
|
||||
stbuf->st_mtimespec = spec;
|
||||
#else
|
||||
stbuf->st_mtim = spec;
|
||||
stbuf->st_mtim = spec;
|
||||
#endif
|
||||
switch (link->type) {
|
||||
case LINK_DIR:
|
||||
stbuf->st_mode = S_IFDIR | 0755;
|
||||
stbuf->st_nlink = 1;
|
||||
break;
|
||||
case LINK_FILE:
|
||||
stbuf->st_mode = S_IFREG | 0444;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = link->content_length;
|
||||
stbuf->st_blksize = 128*1024;
|
||||
stbuf->st_blocks = (link->content_length)/512;
|
||||
break;
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
stbuf->st_uid = getuid();
|
||||
stbuf->st_gid = getgid();
|
||||
switch (link->type) {
|
||||
case LINK_DIR:
|
||||
stbuf->st_mode = S_IFDIR | 0755;
|
||||
stbuf->st_nlink = 1;
|
||||
break;
|
||||
case LINK_FILE:
|
||||
stbuf->st_mode = S_IFREG | 0444;
|
||||
stbuf->st_nlink = 1;
|
||||
stbuf->st_size = link->content_length;
|
||||
stbuf->st_blksize = 128 * 1024;
|
||||
stbuf->st_blocks = (link->content_length) / 512;
|
||||
break;
|
||||
default:
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
stbuf->st_uid = getuid();
|
||||
stbuf->st_gid = getgid();
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/** \brief read a file */
|
||||
static int fs_read(const char *path, char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *fi)
|
||||
static int
|
||||
fs_read(const char *path, char *buf, size_t size, off_t offset,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
long received;
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
received = Cache_read((Cache *)fi->fh, buf, size, offset);
|
||||
} else {
|
||||
received = path_download(path, buf, size, offset);
|
||||
}
|
||||
return received;
|
||||
long received;
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
received = Cache_read((Cache *) fi->fh, buf, size, offset);
|
||||
} else {
|
||||
received = path_download(path, buf, size, offset);
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
/** \brief open a file indicated by the path */
|
||||
static int fs_open(const char *path, struct fuse_file_info *fi)
|
||||
{
|
||||
Link *link = path_to_Link(path);
|
||||
if (!link) {
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((fi->flags & 3) != O_RDONLY) {
|
||||
return -EACCES;
|
||||
}
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
fi->fh = (uint64_t) Cache_open(path);
|
||||
if (!fi->fh) {
|
||||
/*
|
||||
* The link clearly exists, the cache cannot be opened, attempt
|
||||
* cache creation
|
||||
*/
|
||||
Cache_delete(path);
|
||||
Cache_create(path);
|
||||
fi->fh = (uint64_t) Cache_open(path);
|
||||
/*
|
||||
* The cache definitely cannot be opened for some reason.
|
||||
*/
|
||||
if (!fi->fh) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
Link *link = path_to_Link(path);
|
||||
if (!link) {
|
||||
return -ENOENT;
|
||||
}
|
||||
if ((fi->flags & 3) != O_RDONLY) {
|
||||
return -EACCES;
|
||||
}
|
||||
if (CACHE_SYSTEM_INIT) {
|
||||
fi->fh = (uint64_t) Cache_open(path);
|
||||
if (!fi->fh) {
|
||||
/*
|
||||
* The link clearly exists, the cache cannot be opened, attempt
|
||||
* cache creation
|
||||
*/
|
||||
Cache_delete(path);
|
||||
Cache_create(path);
|
||||
fi->fh = (uint64_t) Cache_open(path);
|
||||
/*
|
||||
* The cache definitely cannot be opened for some reason.
|
||||
*/
|
||||
if (!fi->fh) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,46 +127,49 @@ static int fs_open(const char *path, struct fuse_file_info *fi)
|
|||
* generate the LinkTables for previous level directories. We might
|
||||
* as well maintain our own tree structure.
|
||||
*/
|
||||
static int fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
static int
|
||||
fs_readdir(const char *path, void *buf, fuse_fill_dir_t dir_add,
|
||||
off_t offset, struct fuse_file_info *fi)
|
||||
{
|
||||
(void) offset;
|
||||
(void) fi;
|
||||
(void)offset;
|
||||
(void)fi;
|
||||
|
||||
LinkTable *linktbl;
|
||||
LinkTable *linktbl;
|
||||
|
||||
if (!strcmp(path, "/")) {
|
||||
linktbl = ROOT_LINK_TBL;
|
||||
} else {
|
||||
linktbl = path_to_Link_LinkTable_new(path);
|
||||
if(!linktbl) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (!strcmp(path, "/")) {
|
||||
linktbl = ROOT_LINK_TBL;
|
||||
} else {
|
||||
linktbl = path_to_Link_LinkTable_new(path);
|
||||
if (!linktbl) {
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* start adding the links */
|
||||
dir_add(buf, ".", NULL, 0);
|
||||
dir_add(buf, "..", NULL, 0);
|
||||
for (int i = 1; i < linktbl->num; i++) {
|
||||
Link *link = linktbl->links[i];
|
||||
if (link->type != LINK_INVALID) {
|
||||
dir_add(buf, link->linkname, NULL, 0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* start adding the links
|
||||
*/
|
||||
dir_add(buf, ".", NULL, 0);
|
||||
dir_add(buf, "..", NULL, 0);
|
||||
for (int i = 1; i < linktbl->num; i++) {
|
||||
Link *link = linktbl->links[i];
|
||||
if (link->type != LINK_INVALID) {
|
||||
dir_add(buf, link->linkname, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct fuse_operations fs_oper = {
|
||||
.getattr = fs_getattr,
|
||||
.readdir = fs_readdir,
|
||||
.open = fs_open,
|
||||
.read = fs_read,
|
||||
.init = fs_init,
|
||||
.release = fs_release
|
||||
.getattr = fs_getattr,
|
||||
.readdir = fs_readdir,
|
||||
.open = fs_open,
|
||||
.read = fs_read,
|
||||
.init = fs_init,
|
||||
.release = fs_release
|
||||
};
|
||||
|
||||
int fuse_local_init(int argc, char **argv)
|
||||
{
|
||||
return fuse_main(argc, argv, &fs_oper, NULL);
|
||||
return fuse_main(argc, argv, &fs_oper, NULL);
|
||||
}
|
||||
|
|
1287
src/link.c
1287
src/link.c
File diff suppressed because it is too large
Load Diff
80
src/log.c
80
src/log.c
|
@ -9,48 +9,50 @@
|
|||
|
||||
int log_level_init()
|
||||
{
|
||||
char *env = getenv("HTTPDIRFS_LOG_LEVEL");
|
||||
if (env) {
|
||||
return atoi(env);
|
||||
}
|
||||
return DEFAULT_LOG_LEVEL;
|
||||
char *env = getenv("HTTPDIRFS_LOG_LEVEL");
|
||||
if (env) {
|
||||
return atoi(env);
|
||||
}
|
||||
return DEFAULT_LOG_LEVEL;
|
||||
}
|
||||
|
||||
void log_printf(LogType type, const char *file, const char *func, int line,
|
||||
const char *format, ...)
|
||||
void
|
||||
log_printf(LogType type, const char *file, const char *func, int line,
|
||||
const char *format, ...)
|
||||
{
|
||||
FILE *out = stderr;
|
||||
if (type & CONFIG.log_level) {
|
||||
switch (type) {
|
||||
case fatal:
|
||||
fprintf(out, "Fatal: ");
|
||||
break;
|
||||
case error:
|
||||
fprintf(out, "Error: ");
|
||||
break;
|
||||
case warning:
|
||||
fprintf(out, "Warning: ");
|
||||
break;
|
||||
case info:
|
||||
out = stdout;
|
||||
goto print_actual_message;
|
||||
break;
|
||||
default:
|
||||
fprintf(out, "Debug (%x):", type);
|
||||
break;
|
||||
}
|
||||
FILE *out = stderr;
|
||||
if (type & CONFIG.log_type) {
|
||||
switch (type) {
|
||||
case fatal:
|
||||
fprintf(out, "Fatal: ");
|
||||
break;
|
||||
case error:
|
||||
fprintf(out, "Error: ");
|
||||
break;
|
||||
case warning:
|
||||
fprintf(out, "Warning: ");
|
||||
break;
|
||||
case info:
|
||||
out = stdout;
|
||||
goto print_actual_message;
|
||||
break;
|
||||
default:
|
||||
fprintf(out, "Debug (%x):", type);
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(out, "(%s:%s:%d): ", file, func, line);
|
||||
fprintf(out, "(%s:%s:%d): ", file, func, line);
|
||||
|
||||
print_actual_message:
|
||||
{}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(out, format, args);
|
||||
va_end(args);
|
||||
print_actual_message:
|
||||
{
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(out, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (type == fatal) {
|
||||
exit_failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type == fatal) {
|
||||
exit_failure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ typedef enum {
|
|||
info = 1 << 3,
|
||||
debug = 1 << 4,
|
||||
link_lock_debug = 1 << 5,
|
||||
cache_lock_debug = 1 << 6,
|
||||
network_lock_debug = 1 << 6,
|
||||
cache_lock_debug = 1 << 7,
|
||||
} LogType;
|
||||
|
||||
/**
|
||||
|
|
526
src/main.c
526
src/main.c
|
@ -20,258 +20,301 @@ static char *config_path = NULL;
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
/* Automatically print help if not enough arguments are supplied */
|
||||
if (argc < 2) {
|
||||
print_help(argv[0], 0);
|
||||
fprintf(stderr, "For more information, run \"%s --help.\"\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/*
|
||||
* Automatically print help if not enough arguments are supplied
|
||||
*/
|
||||
if (argc < 2) {
|
||||
print_help(argv[0], 0);
|
||||
fprintf(stderr, "For more information, run \"%s --help.\"\n",
|
||||
argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* These are passed into fuse initialiser */
|
||||
char **fuse_argv = NULL;
|
||||
int fuse_argc = 0;
|
||||
/* These are the combined argument with the config file */
|
||||
char **all_argv = NULL;
|
||||
int all_argc = 0;
|
||||
/*
|
||||
* These are passed into fuse initialiser
|
||||
*/
|
||||
char **fuse_argv = NULL;
|
||||
int fuse_argc = 0;
|
||||
/*
|
||||
* These are the combined argument with the config file
|
||||
*/
|
||||
char **all_argv = NULL;
|
||||
int all_argc = 0;
|
||||
|
||||
/*--- Add the program's name to the combined argument list ---*/
|
||||
add_arg(&all_argv, &all_argc, argv[0]);
|
||||
add_arg(&all_argv, &all_argc, argv[0]);
|
||||
/*--- FUSE expects the first initialisation to be the program's name ---*/
|
||||
add_arg(&fuse_argv, &fuse_argc, argv[0]);
|
||||
add_arg(&fuse_argv, &fuse_argc, argv[0]);
|
||||
|
||||
/* initialise network configuration struct */
|
||||
Config_init();
|
||||
/*
|
||||
* initialise network configuration struct
|
||||
*/
|
||||
Config_init();
|
||||
|
||||
/* initialise network subsystem */
|
||||
NetworkSystem_init();
|
||||
/*
|
||||
* initialise network subsystem
|
||||
*/
|
||||
NetworkSystem_init();
|
||||
|
||||
/* Copy the command line argument list to the combined argument list */
|
||||
for (int i = 1; i < argc; i++) {
|
||||
add_arg(&all_argv, &all_argc, argv[i]);
|
||||
if (!strcmp(argv[i], "--config")) {
|
||||
config_path = strdup(argv[i+1]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copy the command line argument list to the combined argument list
|
||||
*/
|
||||
for (int i = 1; i < argc; i++) {
|
||||
add_arg(&all_argv, &all_argc, argv[i]);
|
||||
if (!strcmp(argv[i], "--config")) {
|
||||
config_path = strdup(argv[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* parse the config file, if it exists, store it in all_argv and all_argc */
|
||||
parse_config_file(&all_argv, &all_argc);
|
||||
/*
|
||||
* parse the config file, if it exists, store it in all_argv and
|
||||
* all_argc
|
||||
*/
|
||||
parse_config_file(&all_argv, &all_argc);
|
||||
|
||||
/* parse the combined argument list */
|
||||
if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) {
|
||||
/*
|
||||
* The user basically didn't supply enough arguments, if we reach here
|
||||
* The point is to print some error messages
|
||||
*/
|
||||
goto fuse_start;
|
||||
}
|
||||
/*
|
||||
* parse the combined argument list
|
||||
*/
|
||||
if (parse_arg_list(all_argc, all_argv, &fuse_argv, &fuse_argc)) {
|
||||
/*
|
||||
* The user basically didn't supply enough arguments, if we reach here
|
||||
* The point is to print some error messages
|
||||
*/
|
||||
goto fuse_start;
|
||||
}
|
||||
|
||||
/*--- Add the last remaining argument, which is the mountpoint ---*/
|
||||
add_arg(&fuse_argv, &fuse_argc, argv[argc-1]);
|
||||
add_arg(&fuse_argv, &fuse_argc, argv[argc - 1]);
|
||||
|
||||
/* The second last remaining argument is the URL */
|
||||
char *base_url = argv[argc-2];
|
||||
if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) {
|
||||
fprintf(stderr, "Error: Please supply a valid URL.\n");
|
||||
print_help(argv[0], 0);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (CONFIG.sonic_username && CONFIG.sonic_password) {
|
||||
CONFIG.mode = SONIC;
|
||||
} else if (CONFIG.sonic_username || CONFIG.sonic_password) {
|
||||
fprintf(stderr,
|
||||
"Error: You have to supply both username and password to \
|
||||
/*
|
||||
* The second last remaining argument is the URL
|
||||
*/
|
||||
char *base_url = argv[argc - 2];
|
||||
if (strncmp(base_url, "http://", 7) && strncmp(base_url, "https://", 8)) {
|
||||
fprintf(stderr, "Error: Please supply a valid URL.\n");
|
||||
print_help(argv[0], 0);
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
if (CONFIG.sonic_username && CONFIG.sonic_password) {
|
||||
CONFIG.mode = SONIC;
|
||||
} else if (CONFIG.sonic_username || CONFIG.sonic_password) {
|
||||
fprintf(stderr,
|
||||
"Error: You have to supply both username and password to \
|
||||
activate Sonic mode.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(!LinkSystem_init(base_url)) {
|
||||
fprintf(stderr, "Network initialisation failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!LinkSystem_init(base_url)) {
|
||||
fprintf(stderr, "Network initialisation failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
fuse_start:
|
||||
fuse_local_init(fuse_argc, fuse_argv);
|
||||
fuse_start:
|
||||
fuse_local_init(fuse_argc, fuse_argv);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void parse_config_file(char ***argv, int *argc)
|
||||
{
|
||||
char *full_path;
|
||||
if (!config_path) {
|
||||
char *xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
if (!xdg_config_home) {
|
||||
char *home = getenv("HOME");
|
||||
char *xdg_config_home_default = "/.config";
|
||||
xdg_config_home = path_append(home, xdg_config_home_default);
|
||||
}
|
||||
full_path = path_append(xdg_config_home, "/httpdirfs/config");
|
||||
} else {
|
||||
full_path = config_path;
|
||||
}
|
||||
char *full_path;
|
||||
if (!config_path) {
|
||||
char *xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
if (!xdg_config_home) {
|
||||
char *home = getenv("HOME");
|
||||
char *xdg_config_home_default = "/.config";
|
||||
xdg_config_home =
|
||||
path_append(home, xdg_config_home_default);
|
||||
}
|
||||
full_path = path_append(xdg_config_home, "/httpdirfs/config");
|
||||
} else {
|
||||
full_path = config_path;
|
||||
}
|
||||
|
||||
/* The buffer has to be able to fit a URL */
|
||||
int buf_len = MAX_PATH_LEN;
|
||||
char buf[buf_len];
|
||||
FILE *config = fopen(full_path, "r");
|
||||
if (config) {
|
||||
while (fgets(buf, buf_len, config)) {
|
||||
if (buf[0] == '-') {
|
||||
(*argc)++;
|
||||
buf[strnlen(buf, buf_len) - 1] = '\0';
|
||||
char *space;
|
||||
space = strchr(buf, ' ');
|
||||
if (!space) {
|
||||
*argv = realloc(*argv, *argc * sizeof(char **));
|
||||
(*argv)[*argc - 1] = strndup(buf, buf_len);
|
||||
} else {
|
||||
(*argc)++;
|
||||
*argv = realloc(*argv, *argc * sizeof(char **));
|
||||
/* Only copy up to the space character*/
|
||||
(*argv)[*argc - 2] = strndup(buf, space - buf);
|
||||
/* Starts copying after the space */
|
||||
(*argv)[*argc - 1] = strndup(space + 1,
|
||||
buf_len - (space + 1 - buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE(full_path);
|
||||
/*
|
||||
* The buffer has to be able to fit a URL
|
||||
*/
|
||||
int buf_len = MAX_PATH_LEN;
|
||||
char buf[buf_len];
|
||||
FILE *config = fopen(full_path, "r");
|
||||
if (config) {
|
||||
while (fgets(buf, buf_len, config)) {
|
||||
if (buf[0] == '-') {
|
||||
(*argc)++;
|
||||
buf[strnlen(buf, buf_len) - 1] = '\0';
|
||||
char *space;
|
||||
space = strchr(buf, ' ');
|
||||
if (!space) {
|
||||
*argv =
|
||||
realloc(*argv,
|
||||
*argc * sizeof(char **));
|
||||
(*argv)[*argc - 1] =
|
||||
strndup(buf, buf_len);
|
||||
} else {
|
||||
(*argc)++;
|
||||
*argv =
|
||||
realloc(*argv,
|
||||
*argc * sizeof(char **));
|
||||
/*
|
||||
* Only copy up to the space character
|
||||
*/
|
||||
(*argv)[*argc - 2] =
|
||||
strndup(buf, space - buf);
|
||||
/*
|
||||
* Starts copying after the space
|
||||
*/
|
||||
(*argv)[*argc - 1] = strndup(space + 1,
|
||||
buf_len -
|
||||
(space +
|
||||
1 - buf));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
FREE(full_path);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
||||
{
|
||||
char c;
|
||||
int long_index = 0;
|
||||
const char *short_opts = "o:hVdfsp:u:P:";
|
||||
const struct option long_opts[] = {
|
||||
/* Note that 'L' is returned for long options */
|
||||
{"help", no_argument, NULL, 'h'}, /* 0 */
|
||||
{"version", no_argument, NULL, 'V'}, /* 1 */
|
||||
{"debug", no_argument, NULL, 'd'}, /* 2 */
|
||||
{"username", required_argument, NULL, 'u'}, /* 3 */
|
||||
{"password", required_argument, NULL, 'p'}, /* 4 */
|
||||
{"proxy", required_argument, NULL, 'P'}, /* 5 */
|
||||
{"proxy-username", required_argument, NULL, 'L'}, /* 6 */
|
||||
{"proxy-password", required_argument, NULL, 'L'}, /* 7 */
|
||||
{"cache", no_argument, NULL, 'L'}, /* 8 */
|
||||
{"dl-seg-size", required_argument, NULL, 'L'}, /* 9 */
|
||||
{"max-seg-count", required_argument, NULL, 'L'}, /* 10 */
|
||||
{"max-conns", required_argument, NULL, 'L'}, /* 11 */
|
||||
{"user-agent", required_argument, NULL, 'L'}, /* 12 */
|
||||
{"retry-wait", required_argument, NULL, 'L'}, /* 13 */
|
||||
{"cache-location", required_argument, NULL, 'L'}, /* 14 */
|
||||
{"sonic-username", required_argument, NULL, 'L'}, /* 15 */
|
||||
{"sonic-password", required_argument, NULL, 'L'}, /* 16 */
|
||||
{"sonic-id3", no_argument, NULL, 'L'}, /* 17 */
|
||||
{"no-range-check", no_argument, NULL, 'L'}, /* 18 */
|
||||
{"sonic-insecure", no_argument, NULL, 'L'}, /* 19 */
|
||||
{"insecure-tls", no_argument, NULL, 'L'}, /* 20 */
|
||||
{"config", required_argument, NULL, 'L'}, /* 21 */
|
||||
{"single-file-mode", required_argument, NULL, 'L'}, /* 22 */
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
while ((c =
|
||||
getopt_long(argc, argv, short_opts, long_opts,
|
||||
&long_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'o':
|
||||
add_arg(fuse_argv, fuse_argc, "-o");
|
||||
add_arg(fuse_argv, fuse_argc, optarg);
|
||||
break;
|
||||
case 'h':
|
||||
print_help(argv[0], 1);
|
||||
add_arg(fuse_argv, fuse_argc, "-ho");
|
||||
/* skip everything else to print the help */
|
||||
return 1;
|
||||
case 'V':
|
||||
print_version(argv[0], 1);
|
||||
add_arg(fuse_argv, fuse_argc, "-V");
|
||||
return 1;
|
||||
case 'd':
|
||||
add_arg(fuse_argv, fuse_argc, "-d");
|
||||
break;
|
||||
case 'f':
|
||||
add_arg(fuse_argv, fuse_argc, "-f");
|
||||
break;
|
||||
case 's':
|
||||
add_arg(fuse_argv, fuse_argc, "-s");
|
||||
break;
|
||||
case 'u':
|
||||
CONFIG.http_username = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
CONFIG.http_password = strdup(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
CONFIG.proxy = strdup(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
/* Long options */
|
||||
switch (long_index) {
|
||||
case 6:
|
||||
CONFIG.proxy_username = strdup(optarg);
|
||||
break;
|
||||
case 7:
|
||||
CONFIG.proxy_password = strdup(optarg);
|
||||
break;
|
||||
case 8:
|
||||
CONFIG.cache_enabled = 1;
|
||||
break;
|
||||
case 9:
|
||||
CONFIG.data_blksz = atoi(optarg) * 1024 * 1024;
|
||||
break;
|
||||
case 10:
|
||||
CONFIG.max_segbc = atoi(optarg);
|
||||
break;
|
||||
case 11:
|
||||
CONFIG.max_conns = atoi(optarg);
|
||||
break;
|
||||
case 12:
|
||||
CONFIG.user_agent = strdup(optarg);
|
||||
break;
|
||||
case 13:
|
||||
CONFIG.http_wait_sec = atoi(optarg);
|
||||
break;
|
||||
case 14:
|
||||
CONFIG.cache_dir = strdup(optarg);
|
||||
break;
|
||||
case 15:
|
||||
CONFIG.sonic_username = strdup(optarg);
|
||||
break;
|
||||
case 16:
|
||||
CONFIG.sonic_password = strdup(optarg);
|
||||
break;
|
||||
case 17:
|
||||
CONFIG.sonic_id3 = 1;
|
||||
break;
|
||||
case 18:
|
||||
CONFIG.no_range_check = 1;
|
||||
break;
|
||||
case 19:
|
||||
CONFIG.sonic_insecure = 1;
|
||||
break;
|
||||
case 20:
|
||||
CONFIG.insecure_tls = 1;
|
||||
break;
|
||||
case 21:
|
||||
/* This is for --config, we don't need to do anything */
|
||||
break;
|
||||
case 22:
|
||||
CONFIG.mode = SINGLE_FILE;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
return 0;
|
||||
char c;
|
||||
int long_index = 0;
|
||||
const char *short_opts = "o:hVdfsp:u:P:";
|
||||
const struct option long_opts[] = {
|
||||
/*
|
||||
* Note that 'L' is returned for long options
|
||||
*/
|
||||
{"help", no_argument, NULL, 'h'}, /* 0 */
|
||||
{"version", no_argument, NULL, 'V'}, /* 1 */
|
||||
{"debug", no_argument, NULL, 'd'}, /* 2 */
|
||||
{"username", required_argument, NULL, 'u'}, /* 3 */
|
||||
{"password", required_argument, NULL, 'p'}, /* 4 */
|
||||
{"proxy", required_argument, NULL, 'P'}, /* 5 */
|
||||
{"proxy-username", required_argument, NULL, 'L'}, /* 6 */
|
||||
{"proxy-password", required_argument, NULL, 'L'}, /* 7 */
|
||||
{"cache", no_argument, NULL, 'L'}, /* 8 */
|
||||
{"dl-seg-size", required_argument, NULL, 'L'}, /* 9 */
|
||||
{"max-seg-count", required_argument, NULL, 'L'}, /* 10 */
|
||||
{"max-conns", required_argument, NULL, 'L'}, /* 11 */
|
||||
{"user-agent", required_argument, NULL, 'L'}, /* 12 */
|
||||
{"retry-wait", required_argument, NULL, 'L'}, /* 13 */
|
||||
{"cache-location", required_argument, NULL, 'L'}, /* 14 */
|
||||
{"sonic-username", required_argument, NULL, 'L'}, /* 15 */
|
||||
{"sonic-password", required_argument, NULL, 'L'}, /* 16 */
|
||||
{"sonic-id3", no_argument, NULL, 'L'}, /* 17 */
|
||||
{"no-range-check", no_argument, NULL, 'L'}, /* 18 */
|
||||
{"sonic-insecure", no_argument, NULL, 'L'}, /* 19 */
|
||||
{"insecure-tls", no_argument, NULL, 'L'}, /* 20 */
|
||||
{"config", required_argument, NULL, 'L'}, /* 21 */
|
||||
{"single-file-mode", required_argument, NULL, 'L'}, /* 22 */
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
while ((c =
|
||||
getopt_long(argc, argv, short_opts, long_opts,
|
||||
&long_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'o':
|
||||
add_arg(fuse_argv, fuse_argc, "-o");
|
||||
add_arg(fuse_argv, fuse_argc, optarg);
|
||||
break;
|
||||
case 'h':
|
||||
print_help(argv[0], 1);
|
||||
add_arg(fuse_argv, fuse_argc, "-ho");
|
||||
/*
|
||||
* skip everything else to print the help
|
||||
*/
|
||||
return 1;
|
||||
case 'V':
|
||||
print_version(argv[0], 1);
|
||||
add_arg(fuse_argv, fuse_argc, "-V");
|
||||
return 1;
|
||||
case 'd':
|
||||
add_arg(fuse_argv, fuse_argc, "-d");
|
||||
break;
|
||||
case 'f':
|
||||
add_arg(fuse_argv, fuse_argc, "-f");
|
||||
break;
|
||||
case 's':
|
||||
add_arg(fuse_argv, fuse_argc, "-s");
|
||||
break;
|
||||
case 'u':
|
||||
CONFIG.http_username = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
CONFIG.http_password = strdup(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
CONFIG.proxy = strdup(optarg);
|
||||
break;
|
||||
case 'L':
|
||||
/*
|
||||
* Long options
|
||||
*/
|
||||
switch (long_index) {
|
||||
case 6:
|
||||
CONFIG.proxy_username = strdup(optarg);
|
||||
break;
|
||||
case 7:
|
||||
CONFIG.proxy_password = strdup(optarg);
|
||||
break;
|
||||
case 8:
|
||||
CONFIG.cache_enabled = 1;
|
||||
break;
|
||||
case 9:
|
||||
CONFIG.data_blksz = atoi(optarg) * 1024 * 1024;
|
||||
break;
|
||||
case 10:
|
||||
CONFIG.max_segbc = atoi(optarg);
|
||||
break;
|
||||
case 11:
|
||||
CONFIG.max_conns = atoi(optarg);
|
||||
break;
|
||||
case 12:
|
||||
CONFIG.user_agent = strdup(optarg);
|
||||
break;
|
||||
case 13:
|
||||
CONFIG.http_wait_sec = atoi(optarg);
|
||||
break;
|
||||
case 14:
|
||||
CONFIG.cache_dir = strdup(optarg);
|
||||
break;
|
||||
case 15:
|
||||
CONFIG.sonic_username = strdup(optarg);
|
||||
break;
|
||||
case 16:
|
||||
CONFIG.sonic_password = strdup(optarg);
|
||||
break;
|
||||
case 17:
|
||||
CONFIG.sonic_id3 = 1;
|
||||
break;
|
||||
case 18:
|
||||
CONFIG.no_range_check = 1;
|
||||
break;
|
||||
case 19:
|
||||
CONFIG.sonic_insecure = 1;
|
||||
break;
|
||||
case 20:
|
||||
CONFIG.insecure_tls = 1;
|
||||
break;
|
||||
case 21:
|
||||
/*
|
||||
* This is for --config, we don't need to do anything
|
||||
*/
|
||||
break;
|
||||
case 22:
|
||||
CONFIG.mode = SINGLE_FILE;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -280,32 +323,33 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
|||
*/
|
||||
void add_arg(char ***fuse_argv_ptr, int *fuse_argc, char *opt_string)
|
||||
{
|
||||
(*fuse_argc)++;
|
||||
*fuse_argv_ptr = realloc(*fuse_argv_ptr, *fuse_argc * sizeof(char *));
|
||||
char **fuse_argv = *fuse_argv_ptr;
|
||||
fuse_argv[*fuse_argc - 1] = strdup(opt_string);
|
||||
(*fuse_argc)++;
|
||||
*fuse_argv_ptr = realloc(*fuse_argv_ptr, *fuse_argc * sizeof(char *));
|
||||
char **fuse_argv = *fuse_argv_ptr;
|
||||
fuse_argv[*fuse_argc - 1] = strdup(opt_string);
|
||||
}
|
||||
|
||||
static void print_help(char *program_name, int long_help)
|
||||
{
|
||||
printf("usage: %s [options] URL mountpoint\n", program_name);
|
||||
if (long_help) {
|
||||
print_long_help();
|
||||
}
|
||||
printf("usage: %s [options] URL mountpoint\n", program_name);
|
||||
if (long_help) {
|
||||
print_long_help();
|
||||
}
|
||||
}
|
||||
|
||||
static void print_version()
|
||||
{
|
||||
printf("HTTPDirFS version " VERSION "\n");
|
||||
/* --------- Print off SSL engine version --------- */
|
||||
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
|
||||
printf("libcurl SSL engine: %s\n", data->ssl_version);
|
||||
printf("HTTPDirFS version " VERSION "\n");
|
||||
/*
|
||||
* --------- Print off SSL engine version ---------
|
||||
*/
|
||||
curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
|
||||
printf("libcurl SSL engine: %s\n", data->ssl_version);
|
||||
}
|
||||
|
||||
static void print_long_help()
|
||||
{
|
||||
printf(
|
||||
"\n\
|
||||
printf("\n\
|
||||
general options:\n\
|
||||
--config Specify a configuration file \n\
|
||||
-o opt,[opt...] Mount options\n\
|
||||
|
|
542
src/network.c
542
src/network.c
|
@ -11,11 +11,14 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* ----------------- External variables ---------------------- */
|
||||
/*
|
||||
* ----------------- External variables ----------------------
|
||||
*/
|
||||
CURLSH *CURL_SHARE;
|
||||
|
||||
/* ----------------- Static variable ----------------------- */
|
||||
/*
|
||||
* ----------------- Static variable -----------------------
|
||||
*/
|
||||
/** \brief curl multi interface handle */
|
||||
static CURLM *curl_multi;
|
||||
/** \brief mutex for transfer functions */
|
||||
|
@ -25,7 +28,9 @@ static pthread_mutex_t *crypto_lockarray;
|
|||
/** \brief mutex for curl share interface itself */
|
||||
static pthread_mutex_t curl_lock;
|
||||
|
||||
/* -------------------- Functions -------------------------- */
|
||||
/*
|
||||
* -------------------- Functions --------------------------
|
||||
*/
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
/**
|
||||
|
@ -34,13 +39,13 @@ static pthread_mutex_t curl_lock;
|
|||
*/
|
||||
static void crypto_lock_callback(int mode, int type, char *file, int line)
|
||||
{
|
||||
(void) file;
|
||||
(void) line;
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
PTHREAD_MUTEX_LOCK(&(crypto_lockarray[type]));
|
||||
} else {
|
||||
PTHREAD_MUTEX_UNLOCK(&(crypto_lockarray[type]));
|
||||
}
|
||||
(void)file;
|
||||
(void)line;
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
PTHREAD_MUTEX_LOCK(&(crypto_lockarray[type]));
|
||||
} else {
|
||||
PTHREAD_MUTEX_UNLOCK(&(crypto_lockarray[type]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,25 +54,31 @@ static void crypto_lock_callback(int mode, int type, char *file, int line)
|
|||
*/
|
||||
static unsigned long thread_id(void)
|
||||
{
|
||||
unsigned long ret;
|
||||
unsigned long ret;
|
||||
|
||||
ret = (unsigned long)pthread_self();
|
||||
return ret;
|
||||
ret = (unsigned long)pthread_self();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static void crypto_lock_init(void)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
crypto_lockarray = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() *
|
||||
sizeof(pthread_mutex_t));
|
||||
for(i = 0; i<CRYPTO_num_locks(); i++) {
|
||||
pthread_mutex_init(&(crypto_lockarray[i]), NULL);
|
||||
}
|
||||
crypto_lockarray =
|
||||
(pthread_mutex_t *) OPENSSL_malloc(CRYPTO_num_locks() *
|
||||
sizeof(pthread_mutex_t));
|
||||
for (i = 0; i < CRYPTO_num_locks(); i++) {
|
||||
if (pthread_mutex_init(&(crypto_lockarray[i]), NULL)) {
|
||||
lprintf(fatal,
|
||||
"crypto_lock_init(): crypto_lockarray[%d] initialisation \
|
||||
failed!\n", i);
|
||||
};
|
||||
}
|
||||
|
||||
CRYPTO_set_id_callback((unsigned long (*)())thread_id);
|
||||
CRYPTO_set_locking_callback((void (*)())crypto_lock_callback);
|
||||
CRYPTO_set_id_callback((unsigned long (*)())thread_id);
|
||||
CRYPTO_set_locking_callback((void (*)())crypto_lock_callback);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,23 +86,24 @@ static void crypto_lock_init(void)
|
|||
* \details Adapted from:
|
||||
* https://curl.haxx.se/libcurl/c/threaded-shared-conn.html
|
||||
*/
|
||||
static void curl_callback_lock(CURL *handle, curl_lock_data data,
|
||||
curl_lock_access access, void *userptr)
|
||||
static void
|
||||
curl_callback_lock(CURL * handle, curl_lock_data data,
|
||||
curl_lock_access access, void *userptr)
|
||||
{
|
||||
(void)access; /* unused */
|
||||
(void)userptr; /* unused */
|
||||
(void)handle; /* unused */
|
||||
(void)data; /* unused */
|
||||
PTHREAD_MUTEX_LOCK(&curl_lock);
|
||||
(void)access; /* unused */
|
||||
(void)userptr; /* unused */
|
||||
(void)handle; /* unused */
|
||||
(void)data; /* unused */
|
||||
PTHREAD_MUTEX_LOCK(&curl_lock);
|
||||
}
|
||||
|
||||
static void curl_callback_unlock(CURL *handle, curl_lock_data data,
|
||||
void *userptr)
|
||||
static void
|
||||
curl_callback_unlock(CURL * handle, curl_lock_data data, void *userptr)
|
||||
{
|
||||
(void)userptr; /* unused */
|
||||
(void)handle; /* unused */
|
||||
(void)data; /* unused */
|
||||
PTHREAD_MUTEX_UNLOCK(&curl_lock);
|
||||
(void)userptr; /* unused */
|
||||
(void)handle; /* unused */
|
||||
(void)data; /* unused */
|
||||
PTHREAD_MUTEX_UNLOCK(&curl_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,57 +111,62 @@ static void curl_callback_unlock(CURL *handle, curl_lock_data data,
|
|||
* \details Adapted from:
|
||||
* https://curl.haxx.se/libcurl/c/10-at-a-time.html
|
||||
*/
|
||||
static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
|
||||
int n_mesgs)
|
||||
static void
|
||||
curl_process_msgs(CURLMsg * curl_msg, int n_running_curl, int n_mesgs)
|
||||
{
|
||||
(void) n_running_curl;
|
||||
(void) n_mesgs;
|
||||
static volatile int slept = 0;
|
||||
if (curl_msg->msg == CURLMSG_DONE) {
|
||||
TransferStruct *transfer;
|
||||
CURL *curl = curl_msg->easy_handle;
|
||||
curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE,
|
||||
&transfer);
|
||||
transfer->transferring = 0;
|
||||
char *url = NULL;
|
||||
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
(void)n_running_curl;
|
||||
(void)n_mesgs;
|
||||
static volatile int slept = 0;
|
||||
if (curl_msg->msg == CURLMSG_DONE) {
|
||||
TransferStruct *transfer;
|
||||
CURL *curl = curl_msg->easy_handle;
|
||||
curl_easy_getinfo(curl_msg->easy_handle, CURLINFO_PRIVATE,
|
||||
&transfer);
|
||||
transfer->transferring = 0;
|
||||
char *url = NULL;
|
||||
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
|
||||
/* Wait for 5 seconds if we get HTTP 429 */
|
||||
long http_resp = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
|
||||
if (HTTP_temp_failure(http_resp)) {
|
||||
if (!slept) {
|
||||
lprintf(debug,
|
||||
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
|
||||
http_resp, CONFIG.http_wait_sec);
|
||||
sleep(CONFIG.http_wait_sec);
|
||||
slept = 1;
|
||||
}
|
||||
} else {
|
||||
slept = 0;
|
||||
}
|
||||
/*
|
||||
* Wait for 5 seconds if we get HTTP 429
|
||||
*/
|
||||
long http_resp = 0;
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_resp);
|
||||
if (HTTP_temp_failure(http_resp)) {
|
||||
if (!slept) {
|
||||
lprintf(warning,
|
||||
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
|
||||
http_resp, CONFIG.http_wait_sec);
|
||||
sleep(CONFIG.http_wait_sec);
|
||||
slept = 1;
|
||||
}
|
||||
} else {
|
||||
slept = 0;
|
||||
}
|
||||
|
||||
if (!curl_msg->data.result) {
|
||||
/* Transfer successful, set the file size */
|
||||
if (transfer->type == FILESTAT) {
|
||||
Link_set_file_stat(transfer->link, curl);
|
||||
}
|
||||
} else {
|
||||
lprintf(debug, "curl_process_msgs(): %d - %s <%s>\n",
|
||||
curl_msg->data.result,
|
||||
curl_easy_strerror(curl_msg->data.result),
|
||||
url);
|
||||
}
|
||||
curl_multi_remove_handle(curl_multi, curl);
|
||||
/* clean up the handle, if we are querying the file size */
|
||||
if (transfer->type == FILESTAT) {
|
||||
curl_easy_cleanup(curl);
|
||||
FREE(transfer);
|
||||
}
|
||||
} else {
|
||||
lprintf(debug, "curl_process_msgs(): curl_msg->msg: %d\n",
|
||||
curl_msg->msg);
|
||||
}
|
||||
if (!curl_msg->data.result) {
|
||||
/*
|
||||
* Transfer successful, set the file size
|
||||
*/
|
||||
if (transfer->type == FILESTAT) {
|
||||
Link_set_file_stat(transfer->link, curl);
|
||||
}
|
||||
} else {
|
||||
lprintf(error, "curl_process_msgs(): %d - %s <%s>\n",
|
||||
curl_msg->data.result,
|
||||
curl_easy_strerror(curl_msg->data.result), url);
|
||||
}
|
||||
curl_multi_remove_handle(curl_multi, curl);
|
||||
/*
|
||||
* clean up the handle, if we are querying the file size
|
||||
*/
|
||||
if (transfer->type == FILESTAT) {
|
||||
curl_easy_cleanup(curl);
|
||||
FREE(transfer);
|
||||
}
|
||||
} else {
|
||||
lprintf(warning, "curl_process_msgs(): curl_msg->msg: %d\n",
|
||||
curl_msg->msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,214 +175,229 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
|
|||
*/
|
||||
int curl_multi_perform_once(void)
|
||||
{
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"curl_multi_perform_once(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
/* Get curl multi interface to perform pending tasks */
|
||||
int n_running_curl;
|
||||
CURLMcode mc = curl_multi_perform(curl_multi, &n_running_curl);
|
||||
if(mc > 0) {
|
||||
lprintf(debug, "curl_multi_perform(): %s\n", curl_multi_strerror(mc));
|
||||
}
|
||||
lprintf(network_lock_debug,
|
||||
"curl_multi_perform_once(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd = -1;
|
||||
/*
|
||||
* Get curl multi interface to perform pending tasks
|
||||
*/
|
||||
int n_running_curl;
|
||||
CURLMcode mc = curl_multi_perform(curl_multi, &n_running_curl);
|
||||
if (mc > 0) {
|
||||
lprintf(error, "curl_multi_perform(): %s\n",
|
||||
curl_multi_strerror(mc));
|
||||
}
|
||||
|
||||
long curl_timeo = -1;
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd = -1;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
long curl_timeo = -1;
|
||||
|
||||
/* set a default timeout for select() */
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
|
||||
curl_multi_timeout(curl_multi, &curl_timeo);
|
||||
/* We effectively cap timeout to 1 sec */
|
||||
if (curl_timeo >= 0) {
|
||||
timeout.tv_sec = curl_timeo / 1000;
|
||||
if (timeout.tv_sec > 1) {
|
||||
timeout.tv_sec = 1;
|
||||
} else {
|
||||
timeout.tv_usec = (curl_timeo % 1000) * 1000;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* set a default timeout for select()
|
||||
*/
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* get file descriptors from the transfers */
|
||||
mc = curl_multi_fdset(curl_multi, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
curl_multi_timeout(curl_multi, &curl_timeo);
|
||||
/*
|
||||
* We effectively cap timeout to 1 sec
|
||||
*/
|
||||
if (curl_timeo >= 0) {
|
||||
timeout.tv_sec = curl_timeo / 1000;
|
||||
if (timeout.tv_sec > 1) {
|
||||
timeout.tv_sec = 1;
|
||||
} else {
|
||||
timeout.tv_usec = (curl_timeo % 1000) * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
if (mc > 0) {
|
||||
lprintf(debug, "curl_multi_fdset(): %s.\n", curl_multi_strerror(mc));
|
||||
}
|
||||
/*
|
||||
* get file descriptors from the transfers
|
||||
*/
|
||||
mc = curl_multi_fdset(curl_multi, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
|
||||
if (maxfd == -1) {
|
||||
usleep(100*1000);
|
||||
} else {
|
||||
if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) < 0) {
|
||||
lprintf(debug, "curl_multi_perform_once(): select(): %s.\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
if (mc > 0) {
|
||||
lprintf(error, "curl_multi_fdset(): %s.\n",
|
||||
curl_multi_strerror(mc));
|
||||
}
|
||||
|
||||
/* Process the message queue */
|
||||
int n_mesgs;
|
||||
CURLMsg *curl_msg;
|
||||
while((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) {
|
||||
curl_process_msgs(curl_msg, n_running_curl, n_mesgs);
|
||||
}
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"curl_multi_perform_once(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
return n_running_curl;
|
||||
if (maxfd == -1) {
|
||||
usleep(100 * 1000);
|
||||
} else {
|
||||
if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) <
|
||||
0) {
|
||||
lprintf(error,
|
||||
"curl_multi_perform_once(): select(): %s.\n",
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process the message queue
|
||||
*/
|
||||
int n_mesgs;
|
||||
CURLMsg *curl_msg;
|
||||
while ((curl_msg = curl_multi_info_read(curl_multi, &n_mesgs))) {
|
||||
curl_process_msgs(curl_msg, n_running_curl, n_mesgs);
|
||||
}
|
||||
|
||||
lprintf(network_lock_debug,
|
||||
"curl_multi_perform_once(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
|
||||
return n_running_curl;
|
||||
}
|
||||
|
||||
void NetworkSystem_init(void)
|
||||
{
|
||||
/* ------- Global related ----------*/
|
||||
if (curl_global_init(CURL_GLOBAL_ALL)) {
|
||||
lprintf(debug, "network_init(): curl_global_init() failed!\n");
|
||||
exit_failure();
|
||||
}
|
||||
/*
|
||||
* ------- Global related ----------
|
||||
*/
|
||||
if (curl_global_init(CURL_GLOBAL_ALL)) {
|
||||
lprintf(fatal, "network_init(): curl_global_init() failed!\n");
|
||||
}
|
||||
|
||||
/* -------- Share related ----------*/
|
||||
CURL_SHARE = curl_share_init();
|
||||
if (!(CURL_SHARE)) {
|
||||
lprintf(debug, "network_init(): curl_share_init() failed!\n");
|
||||
exit_failure();
|
||||
}
|
||||
/*
|
||||
* -------- Share related ----------
|
||||
*/
|
||||
CURL_SHARE = curl_share_init();
|
||||
if (!(CURL_SHARE)) {
|
||||
lprintf(fatal, "network_init(): curl_share_init() failed!\n");
|
||||
}
|
||||
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_SHARE,
|
||||
CURL_LOCK_DATA_SSL_SESSION);
|
||||
|
||||
if (pthread_mutex_init(&curl_lock, NULL) != 0) {
|
||||
lprintf(debug, "network_init(): curl_lock initialisation failed!\n");
|
||||
exit_failure();
|
||||
}
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_LOCKFUNC, curl_callback_lock);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_UNLOCKFUNC, curl_callback_unlock);
|
||||
if (pthread_mutex_init(&curl_lock, NULL)) {
|
||||
lprintf(fatal,
|
||||
"network_init(): curl_lock initialisation failed!\n");
|
||||
}
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_LOCKFUNC, curl_callback_lock);
|
||||
curl_share_setopt(CURL_SHARE, CURLSHOPT_UNLOCKFUNC,
|
||||
curl_callback_unlock);
|
||||
|
||||
/* ------------- Multi related -----------*/
|
||||
curl_multi = curl_multi_init();
|
||||
if (!curl_multi) {
|
||||
lprintf(debug, "network_init(): curl_multi_init() failed!\n");
|
||||
exit_failure();
|
||||
}
|
||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||
CONFIG.max_conns);
|
||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS,
|
||||
CONFIG.max_conns);
|
||||
/*
|
||||
* ------------- Multi related -----------
|
||||
*/
|
||||
curl_multi = curl_multi_init();
|
||||
if (!curl_multi) {
|
||||
lprintf(fatal, "network_init(): curl_multi_init() failed!\n");
|
||||
}
|
||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||
CONFIG.max_conns);
|
||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS,
|
||||
CONFIG.max_conns);
|
||||
|
||||
/* ------------ Initialise locks ---------*/
|
||||
if (pthread_mutex_init(&transfer_lock, NULL)) {
|
||||
lprintf(debug,
|
||||
"network_init(): transfer_lock initialisation failed!\n");
|
||||
exit_failure();
|
||||
}
|
||||
/*
|
||||
* ------------ Initialise locks ---------
|
||||
*/
|
||||
if (pthread_mutex_init(&transfer_lock, NULL)) {
|
||||
lprintf(fatal,
|
||||
"network_init(): transfer_lock initialisation failed!\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* cryptographic lock functions were shamelessly copied from
|
||||
* https://curl.haxx.se/libcurl/c/threaded-ssl.html
|
||||
*/
|
||||
crypto_lock_init();
|
||||
/*
|
||||
* cryptographic lock functions were shamelessly copied from
|
||||
* https://curl.haxx.se/libcurl/c/threaded-ssl.html
|
||||
*/
|
||||
crypto_lock_init();
|
||||
}
|
||||
|
||||
void transfer_blocking(CURL *curl)
|
||||
void transfer_blocking(CURL * curl)
|
||||
{
|
||||
/*
|
||||
* We don't need to malloc here, as the transfer is finished before
|
||||
* the variable gets popped from the stack
|
||||
*/
|
||||
volatile TransferStruct transfer;
|
||||
transfer.type = DATA;
|
||||
transfer.transferring = 1;
|
||||
curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer);
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"transfer_blocking(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
CURLMcode res = curl_multi_add_handle(curl_multi, curl);
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"transfer_blocking(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
/*
|
||||
* We don't need to malloc here, as the transfer is finished before
|
||||
* the variable gets popped from the stack
|
||||
*/
|
||||
volatile TransferStruct transfer;
|
||||
transfer.type = DATA;
|
||||
transfer.transferring = 1;
|
||||
curl_easy_setopt(curl, CURLOPT_PRIVATE, &transfer);
|
||||
|
||||
if(res > 0) {
|
||||
lprintf(debug, "transfer_blocking(): %d, %s\n",
|
||||
res, curl_multi_strerror(res));
|
||||
exit_failure();
|
||||
}
|
||||
lprintf(network_lock_debug,
|
||||
"transfer_blocking(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
|
||||
while (transfer.transferring) {
|
||||
curl_multi_perform_once();
|
||||
}
|
||||
CURLMcode res = curl_multi_add_handle(curl_multi, curl);
|
||||
|
||||
lprintf(network_lock_debug,
|
||||
"transfer_blocking(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
|
||||
if (res > 0) {
|
||||
lprintf(error, "transfer_blocking(): %d, %s\n",
|
||||
res, curl_multi_strerror(res));
|
||||
}
|
||||
|
||||
while (transfer.transferring) {
|
||||
curl_multi_perform_once();
|
||||
}
|
||||
}
|
||||
|
||||
void transfer_nonblocking(CURL *curl)
|
||||
void transfer_nonblocking(CURL * curl)
|
||||
{
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"transfer_nonblocking(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
CURLMcode res = curl_multi_add_handle(curl_multi, curl);
|
||||
#ifdef NETWORK_LOCK_DEBUG
|
||||
lprintf(debug,
|
||||
"transfer_nonblocking(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
#endif
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
lprintf(network_lock_debug,
|
||||
"transfer_nonblocking(): thread %x: locking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_LOCK(&transfer_lock);
|
||||
|
||||
if(res > 0) {
|
||||
lprintf(debug, "transfer_nonblocking(): %s\n",
|
||||
curl_multi_strerror(res));
|
||||
}
|
||||
CURLMcode res = curl_multi_add_handle(curl_multi, curl);
|
||||
|
||||
lprintf(network_lock_debug,
|
||||
"transfer_nonblocking(): thread %x: unlocking transfer_lock;\n",
|
||||
pthread_self());
|
||||
PTHREAD_MUTEX_UNLOCK(&transfer_lock);
|
||||
|
||||
if (res > 0) {
|
||||
lprintf(error, "transfer_nonblocking(): %s\n",
|
||||
curl_multi_strerror(res));
|
||||
}
|
||||
}
|
||||
|
||||
size_t write_memory_callback(void *contents, size_t size, size_t nmemb,
|
||||
void *userp)
|
||||
size_t
|
||||
write_memory_callback(void *contents, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
DataStruct *mem = (DataStruct *)userp;
|
||||
size_t realsize = size * nmemb;
|
||||
DataStruct *mem = (DataStruct *) userp;
|
||||
|
||||
mem->data = realloc(mem->data, mem->size + realsize + 1);
|
||||
if(!mem->data) {
|
||||
/* out of memory! */
|
||||
lprintf(debug, "write_memory_callback(): realloc failure!\n");
|
||||
exit_failure();
|
||||
return 0;
|
||||
}
|
||||
mem->data = realloc(mem->data, mem->size + realsize + 1);
|
||||
if (!mem->data) {
|
||||
/*
|
||||
* out of memory!
|
||||
*/
|
||||
lprintf(fatal, "write_memory_callback(): realloc failure!\n");
|
||||
}
|
||||
|
||||
memmove(&mem->data[mem->size], contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->data[mem->size] = 0;
|
||||
memmove(&mem->data[mem->size], contents, realsize);
|
||||
mem->size += realsize;
|
||||
mem->data[mem->size] = 0;
|
||||
|
||||
return realsize;
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int HTTP_temp_failure(HTTPResponseCode http_resp)
|
||||
{
|
||||
switch (http_resp) {
|
||||
case HTTP_TOO_MANY_REQUESTS:
|
||||
case HTTP_CLOUDFLARE_UNKNOWN_ERROR:
|
||||
case HTTP_CLOUDFLARE_TIMEOUT:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
switch (http_resp) {
|
||||
case HTTP_TOO_MANY_REQUESTS:
|
||||
case HTTP_CLOUDFLARE_UNKNOWN_ERROR:
|
||||
case HTTP_CLOUDFLARE_TIMEOUT:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
701
src/sonic.c
701
src/sonic.c
|
@ -14,11 +14,11 @@
|
|||
#include <unistd.h>
|
||||
|
||||
typedef struct {
|
||||
char *server;
|
||||
char *username;
|
||||
char *password;
|
||||
char *client;
|
||||
char *api_version;
|
||||
char *server;
|
||||
char *username;
|
||||
char *password;
|
||||
char *client;
|
||||
char *api_version;
|
||||
} SonicConfigStruct;
|
||||
|
||||
static SonicConfigStruct SONIC_CONFIG;
|
||||
|
@ -26,31 +26,34 @@ static SonicConfigStruct SONIC_CONFIG;
|
|||
/**
|
||||
* \brief initalise Sonic configuration struct
|
||||
*/
|
||||
void sonic_config_init(const char *server, const char *username,
|
||||
const char *password)
|
||||
void
|
||||
sonic_config_init(const char *server, const char *username,
|
||||
const char *password)
|
||||
{
|
||||
SONIC_CONFIG.server = strndup(server, MAX_PATH_LEN);
|
||||
/* Correct for the extra '/' */
|
||||
size_t server_url_len = strnlen(SONIC_CONFIG.server, MAX_PATH_LEN) - 1;
|
||||
if (SONIC_CONFIG.server[server_url_len] == '/') {
|
||||
SONIC_CONFIG.server[server_url_len] = '\0';
|
||||
}
|
||||
SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN);
|
||||
SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN);
|
||||
SONIC_CONFIG.client = DEFAULT_USER_AGENT;
|
||||
SONIC_CONFIG.server = strndup(server, MAX_PATH_LEN);
|
||||
/*
|
||||
* Correct for the extra '/'
|
||||
*/
|
||||
size_t server_url_len = strnlen(SONIC_CONFIG.server, MAX_PATH_LEN) - 1;
|
||||
if (SONIC_CONFIG.server[server_url_len] == '/') {
|
||||
SONIC_CONFIG.server[server_url_len] = '\0';
|
||||
}
|
||||
SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN);
|
||||
SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN);
|
||||
SONIC_CONFIG.client = DEFAULT_USER_AGENT;
|
||||
|
||||
if (!CONFIG.sonic_insecure) {
|
||||
/*
|
||||
* API 1.13.0 is the minimum version that supports
|
||||
* salt authentication scheme
|
||||
*/
|
||||
SONIC_CONFIG.api_version = "1.13.0";
|
||||
} else {
|
||||
/*
|
||||
* API 1.8.0 is the minimum version that supports ID3 mode
|
||||
*/
|
||||
SONIC_CONFIG.api_version = "1.8.0";
|
||||
}
|
||||
if (!CONFIG.sonic_insecure) {
|
||||
/*
|
||||
* API 1.13.0 is the minimum version that supports
|
||||
* salt authentication scheme
|
||||
*/
|
||||
SONIC_CONFIG.api_version = "1.13.0";
|
||||
} else {
|
||||
/*
|
||||
* API 1.8.0 is the minimum version that supports ID3 mode
|
||||
*/
|
||||
SONIC_CONFIG.api_version = "1.8.0";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,32 +61,33 @@ void sonic_config_init(const char *server, const char *username,
|
|||
*/
|
||||
static char *sonic_gen_auth_str(void)
|
||||
{
|
||||
if (!CONFIG.sonic_insecure) {
|
||||
char *salt = generate_salt();
|
||||
size_t pwd_len = strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
||||
size_t pwd_salt_len = pwd_len + strnlen(salt, MAX_FILENAME_LEN);
|
||||
char *pwd_salt = CALLOC(pwd_salt_len + 1, sizeof(char));
|
||||
strncat(pwd_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
||||
strncat(pwd_salt + pwd_len, salt, MAX_FILENAME_LEN);
|
||||
char *token = generate_md5sum(pwd_salt);
|
||||
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(auth_str, MAX_PATH_LEN,
|
||||
".view?u=%s&t=%s&s=%s&v=%s&c=%s",
|
||||
SONIC_CONFIG.username, token, salt,
|
||||
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
|
||||
FREE(salt);
|
||||
FREE(token);
|
||||
return auth_str;
|
||||
} else {
|
||||
char *pwd_hex = str_to_hex(SONIC_CONFIG.password);
|
||||
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(auth_str, MAX_PATH_LEN,
|
||||
".view?u=%s&p=enc:%s&v=%s&c=%s",
|
||||
SONIC_CONFIG.username, pwd_hex, SONIC_CONFIG.api_version,
|
||||
SONIC_CONFIG.client);
|
||||
FREE(pwd_hex);
|
||||
return auth_str;
|
||||
}
|
||||
if (!CONFIG.sonic_insecure) {
|
||||
char *salt = generate_salt();
|
||||
size_t pwd_len =
|
||||
strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
||||
size_t pwd_salt_len = pwd_len + strnlen(salt, MAX_FILENAME_LEN);
|
||||
char *pwd_salt = CALLOC(pwd_salt_len + 1, sizeof(char));
|
||||
strncat(pwd_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
||||
strncat(pwd_salt + pwd_len, salt, MAX_FILENAME_LEN);
|
||||
char *token = generate_md5sum(pwd_salt);
|
||||
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(auth_str, MAX_PATH_LEN,
|
||||
".view?u=%s&t=%s&s=%s&v=%s&c=%s",
|
||||
SONIC_CONFIG.username, token, salt,
|
||||
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
|
||||
FREE(salt);
|
||||
FREE(token);
|
||||
return auth_str;
|
||||
} else {
|
||||
char *pwd_hex = str_to_hex(SONIC_CONFIG.password);
|
||||
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(auth_str, MAX_PATH_LEN,
|
||||
".view?u=%s&p=enc:%s&v=%s&c=%s",
|
||||
SONIC_CONFIG.username, pwd_hex,
|
||||
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
|
||||
FREE(pwd_hex);
|
||||
return auth_str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,12 +95,12 @@ static char *sonic_gen_auth_str(void)
|
|||
*/
|
||||
static char *sonic_gen_url_first_part(char *method)
|
||||
{
|
||||
char *auth_str = sonic_gen_auth_str();
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s/rest/%s%s", SONIC_CONFIG.server, method,
|
||||
auth_str);
|
||||
FREE(auth_str);
|
||||
return url;
|
||||
char *auth_str = sonic_gen_auth_str();
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s/rest/%s%s", SONIC_CONFIG.server,
|
||||
method, auth_str);
|
||||
FREE(auth_str);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,11 +108,11 @@ static char *sonic_gen_url_first_part(char *method)
|
|||
*/
|
||||
static char *sonic_getMusicDirectory_link(const char *id)
|
||||
{
|
||||
char *first_part = sonic_gen_url_first_part("getMusicDirectory");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
char *first_part = sonic_gen_url_first_part("getMusicDirectory");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,11 +120,11 @@ static char *sonic_getMusicDirectory_link(const char *id)
|
|||
*/
|
||||
static char *sonic_getArtist_link(const char *id)
|
||||
{
|
||||
char *first_part = sonic_gen_url_first_part("getArtist");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
char *first_part = sonic_gen_url_first_part("getArtist");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,11 +132,11 @@ static char *sonic_getArtist_link(const char *id)
|
|||
*/
|
||||
static char *sonic_getAlbum_link(const char *id)
|
||||
{
|
||||
char *first_part = sonic_gen_url_first_part("getAlbum");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
char *first_part = sonic_gen_url_first_part("getAlbum");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,12 +144,11 @@ static char *sonic_getAlbum_link(const char *id)
|
|||
*/
|
||||
static char *sonic_stream_link(const char *id)
|
||||
{
|
||||
char *first_part = sonic_gen_url_first_part("stream");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN,
|
||||
"%s&format=raw&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
char *first_part = sonic_gen_url_first_part("stream");
|
||||
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||
snprintf(url, MAX_PATH_LEN, "%s&format=raw&id=%s", first_part, id);
|
||||
FREE(first_part);
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,299 +165,345 @@ static char *sonic_stream_link(const char *id)
|
|||
* parser terminates the strings properly, which is a fair assumption,
|
||||
* considering how mature expat is.
|
||||
*/
|
||||
static void XMLCALL XML_parser_general(void *data, const char *elem,
|
||||
const char **attr)
|
||||
static void XMLCALL
|
||||
XML_parser_general(void *data, const char *elem, const char **attr)
|
||||
{
|
||||
/* Error checking */
|
||||
if (!strcmp(elem, "error")) {
|
||||
lprintf(error, "XML_parser_general() error:\n");
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
lprintf(error, "%s: %s\n", attr[i], attr[i+1]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Error checking
|
||||
*/
|
||||
if (!strcmp(elem, "error")) {
|
||||
lprintf(error, "XML_parser_general() error:\n");
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
lprintf(error, "%s: %s\n", attr[i], attr[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
LinkTable *linktbl = (LinkTable *) data;
|
||||
Link *link;
|
||||
LinkTable *linktbl = (LinkTable *) data;
|
||||
Link *link;
|
||||
|
||||
/*
|
||||
* Please refer to the documentation at the function prototype of
|
||||
* sonic_LinkTable_new_id3()
|
||||
*/
|
||||
if (!strcmp(elem, "child")) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
/* Initialise to LINK_DIR, as the LINK_FILE is set later. */
|
||||
link->type = LINK_DIR;
|
||||
} else if (!strcmp(elem, "artist") && linktbl->links[0]->sonic_depth != 3) {
|
||||
/* We want to skip the first "artist" element in the album table */
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
} else if (!strcmp(elem, "album") && linktbl->links[0]->sonic_depth == 3) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
/* The new table should be a level 4 song table */
|
||||
link->sonic_depth = 4;
|
||||
} else if (!strcmp(elem, "song") && linktbl->links[0]->sonic_depth == 4) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_FILE;
|
||||
} else {
|
||||
/* The element does not contain directory structural information */
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Please refer to the documentation at the function prototype of
|
||||
* sonic_LinkTable_new_id3()
|
||||
*/
|
||||
if (!strcmp(elem, "child")) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
/*
|
||||
* Initialise to LINK_DIR, as the LINK_FILE is set later.
|
||||
*/
|
||||
link->type = LINK_DIR;
|
||||
} else if (!strcmp(elem, "artist")
|
||||
&& linktbl->links[0]->sonic_depth != 3) {
|
||||
/*
|
||||
* We want to skip the first "artist" element in the album table
|
||||
*/
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
} else if (!strcmp(elem, "album")
|
||||
&& linktbl->links[0]->sonic_depth == 3) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
/*
|
||||
* The new table should be a level 4 song table
|
||||
*/
|
||||
link->sonic_depth = 4;
|
||||
} else if (!strcmp(elem, "song") && linktbl->links[0]->sonic_depth == 4) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_FILE;
|
||||
} else {
|
||||
/*
|
||||
* The element does not contain directory structural information
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
int id_set = 0;
|
||||
int linkname_set = 0;
|
||||
int id_set = 0;
|
||||
int linkname_set = 0;
|
||||
|
||||
int track = 0;
|
||||
char *title = "";
|
||||
char *suffix = "";
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("id", attr[i])) {
|
||||
link->sonic_id = CALLOC(MAX_FILENAME_LEN + 1, sizeof(char));
|
||||
strncpy(link->sonic_id, attr[i+1], MAX_FILENAME_LEN);
|
||||
id_set = 1;
|
||||
continue;
|
||||
}
|
||||
int track = 0;
|
||||
char *title = "";
|
||||
char *suffix = "";
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("id", attr[i])) {
|
||||
link->sonic_id =
|
||||
CALLOC(MAX_FILENAME_LEN + 1, sizeof(char));
|
||||
strncpy(link->sonic_id, attr[i + 1], MAX_FILENAME_LEN);
|
||||
id_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("path", attr[i])) {
|
||||
memset(link->linkname, 0, MAX_FILENAME_LEN);
|
||||
/* Skip to the last '/' if it exists */
|
||||
char *s = strrchr(attr[i+1], '/');
|
||||
if (s) {
|
||||
strncpy(link->linkname, s + 1, MAX_FILENAME_LEN);
|
||||
} else {
|
||||
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
|
||||
}
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("path", attr[i])) {
|
||||
memset(link->linkname, 0, MAX_FILENAME_LEN);
|
||||
/*
|
||||
* Skip to the last '/' if it exists
|
||||
*/
|
||||
char *s = strrchr(attr[i + 1], '/');
|
||||
if (s) {
|
||||
strncpy(link->linkname, s + 1,
|
||||
MAX_FILENAME_LEN);
|
||||
} else {
|
||||
strncpy(link->linkname, attr[i + 1],
|
||||
MAX_FILENAME_LEN);
|
||||
}
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* "title" is used for directory name,
|
||||
* "name" is for top level directories
|
||||
* N.B. "path" attribute is given the preference
|
||||
*/
|
||||
if (!linkname_set) {
|
||||
if (!strcmp("title", attr[i]) || !strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* "title" is used for directory name,
|
||||
* "name" is for top level directories
|
||||
* N.B. "path" attribute is given the preference
|
||||
*/
|
||||
if (!linkname_set) {
|
||||
if (!strcmp("title", attr[i])
|
||||
|| !strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i + 1],
|
||||
MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcmp("isDir", attr[i])) {
|
||||
if (!strcmp("false", attr[i+1])) {
|
||||
link->type = LINK_FILE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("isDir", attr[i])) {
|
||||
if (!strcmp("false", attr[i + 1])) {
|
||||
link->type = LINK_FILE;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("created", attr[i])) {
|
||||
struct tm *tm = CALLOC(1, sizeof(struct tm));
|
||||
strptime(attr[i+1], "%Y-%m-%dT%H:%M:%S.000Z", tm);
|
||||
link->time = mktime(tm);
|
||||
FREE(tm);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("created", attr[i])) {
|
||||
struct tm *tm = CALLOC(1, sizeof(struct tm));
|
||||
strptime(attr[i + 1], "%Y-%m-%dT%H:%M:%S.000Z", tm);
|
||||
link->time = mktime(tm);
|
||||
FREE(tm);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("size", attr[i])) {
|
||||
link->content_length = atoll(attr[i+1]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("size", attr[i])) {
|
||||
link->content_length = atoll(attr[i + 1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("track", attr[i])) {
|
||||
track = atoi(attr[i+1]);
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("track", attr[i])) {
|
||||
track = atoi(attr[i + 1]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("title", attr[i])) {
|
||||
title = (char *) attr[i+1];
|
||||
continue;
|
||||
}
|
||||
if (!strcmp("title", attr[i])) {
|
||||
title = (char *)attr[i + 1];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("suffix", attr[i])) {
|
||||
suffix = (char *) attr[i+1];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!strcmp("suffix", attr[i])) {
|
||||
suffix = (char *)attr[i + 1];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!linkname_set && strlen(title) > 0 && strlen(suffix) > 0) {
|
||||
snprintf(link->linkname, MAX_FILENAME_LEN, "%02d - %s.%s",
|
||||
track, title, suffix);
|
||||
linkname_set = 1;
|
||||
}
|
||||
if (!linkname_set && strlen(title) > 0 && strlen(suffix) > 0) {
|
||||
snprintf(link->linkname, MAX_FILENAME_LEN, "%02d - %s.%s",
|
||||
track, title, suffix);
|
||||
linkname_set = 1;
|
||||
}
|
||||
|
||||
/* Clean up if linkname or id is not set */
|
||||
if (!linkname_set || !id_set) {
|
||||
FREE(link);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Clean up if linkname or id is not set
|
||||
*/
|
||||
if (!linkname_set || !id_set) {
|
||||
FREE(link);
|
||||
return;
|
||||
}
|
||||
|
||||
if (link->type == LINK_FILE) {
|
||||
char *url = sonic_stream_link(link->sonic_id);
|
||||
strncpy(link->f_url, url, MAX_PATH_LEN);
|
||||
FREE(url);
|
||||
}
|
||||
if (link->type == LINK_FILE) {
|
||||
char *url = sonic_stream_link(link->sonic_id);
|
||||
strncpy(link->f_url, url, MAX_PATH_LEN);
|
||||
FREE(url);
|
||||
}
|
||||
|
||||
LinkTable_add(linktbl, link);
|
||||
LinkTable_add(linktbl, link);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief parse a XML string in order to fill in the LinkTable
|
||||
*/
|
||||
static LinkTable *sonic_url_to_LinkTable(const char *url,
|
||||
XML_StartElementHandler handler,
|
||||
int depth)
|
||||
XML_StartElementHandler handler,
|
||||
int depth)
|
||||
{
|
||||
LinkTable *linktbl = LinkTable_alloc(url);
|
||||
linktbl->links[0]->sonic_depth = depth;
|
||||
LinkTable *linktbl = LinkTable_alloc(url);
|
||||
linktbl->links[0]->sonic_depth = depth;
|
||||
|
||||
/* start downloading the base URL */
|
||||
DataStruct xml = Link_to_DataStruct(linktbl->links[0]);
|
||||
if (xml.size == 0) {
|
||||
LinkTable_free(linktbl);
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* start downloading the base URL
|
||||
*/
|
||||
DataStruct xml = Link_to_DataStruct(linktbl->links[0]);
|
||||
if (xml.size == 0) {
|
||||
LinkTable_free(linktbl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(parser, linktbl);
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_SetUserData(parser, linktbl);
|
||||
|
||||
XML_SetStartElementHandler(parser, handler);
|
||||
XML_SetStartElementHandler(parser, handler);
|
||||
|
||||
if (XML_Parse(parser, xml.data, xml.size, 1) == XML_STATUS_ERROR) {
|
||||
lprintf(error,
|
||||
"sonic_XML_to_LinkTable(): Parse error at line %lu: %s\n",
|
||||
XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
}
|
||||
if (XML_Parse(parser, xml.data, xml.size, 1) == XML_STATUS_ERROR) {
|
||||
lprintf(error,
|
||||
"sonic_XML_to_LinkTable(): Parse error at line %lu: %s\n",
|
||||
XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
XML_ParserFree(parser);
|
||||
|
||||
FREE(xml.data);
|
||||
FREE(xml.data);
|
||||
|
||||
LinkTable_print(linktbl);
|
||||
LinkTable_print(linktbl);
|
||||
|
||||
return linktbl;
|
||||
return linktbl;
|
||||
|
||||
}
|
||||
|
||||
LinkTable *sonic_LinkTable_new_index(const char *id)
|
||||
{
|
||||
char *url;
|
||||
if (strcmp(id, "0")) {
|
||||
url = sonic_getMusicDirectory_link(id);
|
||||
} else {
|
||||
url = sonic_gen_url_first_part("getIndexes");
|
||||
}
|
||||
LinkTable *linktbl = sonic_url_to_LinkTable(url, XML_parser_general, 0);
|
||||
FREE(url);
|
||||
return linktbl;
|
||||
char *url;
|
||||
if (strcmp(id, "0")) {
|
||||
url = sonic_getMusicDirectory_link(id);
|
||||
} else {
|
||||
url = sonic_gen_url_first_part("getIndexes");
|
||||
}
|
||||
LinkTable *linktbl = sonic_url_to_LinkTable(url, XML_parser_general, 0);
|
||||
FREE(url);
|
||||
return linktbl;
|
||||
}
|
||||
|
||||
|
||||
static void XMLCALL XML_parser_id3_root(void *data, const char *elem,
|
||||
const char **attr)
|
||||
static void XMLCALL
|
||||
XML_parser_id3_root(void *data, const char *elem, const char **attr)
|
||||
{
|
||||
if (!strcmp(elem, "error")) {
|
||||
lprintf(error, "XML_parser_id3_root():\n");
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
lprintf(error, "%s: %s\n", attr[i], attr[i+1]);
|
||||
}
|
||||
}
|
||||
if (!strcmp(elem, "error")) {
|
||||
lprintf(error, "XML_parser_id3_root():\n");
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
lprintf(error, "%s: %s\n", attr[i], attr[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
LinkTable *root_linktbl = (LinkTable *) data;
|
||||
LinkTable *this_linktbl = NULL;
|
||||
LinkTable *root_linktbl = (LinkTable *) data;
|
||||
LinkTable *this_linktbl = NULL;
|
||||
|
||||
/* Set the current linktbl, if we have more than head link. */
|
||||
if (root_linktbl->num > 1) {
|
||||
this_linktbl = root_linktbl->links[root_linktbl->num - 1]->next_table;
|
||||
}
|
||||
/*
|
||||
* Set the current linktbl, if we have more than head link.
|
||||
*/
|
||||
if (root_linktbl->num > 1) {
|
||||
this_linktbl =
|
||||
root_linktbl->links[root_linktbl->num - 1]->next_table;
|
||||
}
|
||||
|
||||
int id_set = 0;
|
||||
int linkname_set = 0;
|
||||
Link *link;
|
||||
if (!strcmp(elem, "index")) {
|
||||
/* Add a subdirectory */
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
/* Allocate a new LinkTable */
|
||||
link->next_table = LinkTable_alloc("/");
|
||||
}
|
||||
}
|
||||
/* Make sure we don't add an empty directory */
|
||||
if (linkname_set) {
|
||||
LinkTable_add(root_linktbl, link);
|
||||
} else {
|
||||
FREE(link);
|
||||
}
|
||||
return;
|
||||
} else if (!strcmp(elem, "artist")) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
/* The new table should be a level 3 album table */
|
||||
link->sonic_depth = 3;
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
int id_set = 0;
|
||||
int linkname_set = 0;
|
||||
Link *link;
|
||||
if (!strcmp(elem, "index")) {
|
||||
/*
|
||||
* Add a subdirectory
|
||||
*/
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i + 1],
|
||||
MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
/*
|
||||
* Allocate a new LinkTable
|
||||
*/
|
||||
link->next_table = LinkTable_alloc("/");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Make sure we don't add an empty directory
|
||||
*/
|
||||
if (linkname_set) {
|
||||
LinkTable_add(root_linktbl, link);
|
||||
} else {
|
||||
FREE(link);
|
||||
}
|
||||
return;
|
||||
} else if (!strcmp(elem, "artist")) {
|
||||
link = CALLOC(1, sizeof(Link));
|
||||
link->type = LINK_DIR;
|
||||
/*
|
||||
* The new table should be a level 3 album table
|
||||
*/
|
||||
link->sonic_depth = 3;
|
||||
for (int i = 0; attr[i]; i += 2) {
|
||||
if (!strcmp("name", attr[i])) {
|
||||
strncpy(link->linkname, attr[i + 1],
|
||||
MAX_FILENAME_LEN);
|
||||
linkname_set = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp("id", attr[i])) {
|
||||
link->sonic_id = CALLOC(MAX_FILENAME_LEN + 1, sizeof(char));
|
||||
strncpy(link->sonic_id, attr[i+1], MAX_FILENAME_LEN);
|
||||
id_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!strcmp("id", attr[i])) {
|
||||
link->sonic_id =
|
||||
CALLOC(MAX_FILENAME_LEN + 1, sizeof(char));
|
||||
strncpy(link->sonic_id, attr[i + 1],
|
||||
MAX_FILENAME_LEN);
|
||||
id_set = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up if linkname is not set */
|
||||
if (!linkname_set || !id_set) {
|
||||
FREE(link);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Clean up if linkname is not set
|
||||
*/
|
||||
if (!linkname_set || !id_set) {
|
||||
FREE(link);
|
||||
return;
|
||||
}
|
||||
|
||||
LinkTable_add(this_linktbl, link);
|
||||
}
|
||||
/*
|
||||
* If we reach here, then this element does not contain directory structural
|
||||
* information
|
||||
*/
|
||||
LinkTable_add(this_linktbl, link);
|
||||
}
|
||||
/*
|
||||
* If we reach here, then this element does not contain directory structural
|
||||
* information
|
||||
*/
|
||||
}
|
||||
|
||||
LinkTable *sonic_LinkTable_new_id3(int depth, const char *id)
|
||||
{
|
||||
char *url;
|
||||
LinkTable *linktbl = ROOT_LINK_TBL;
|
||||
switch (depth) {
|
||||
/* Root table */
|
||||
case 0:
|
||||
url = sonic_gen_url_first_part("getArtists");
|
||||
linktbl = sonic_url_to_LinkTable(url, XML_parser_id3_root, 0);
|
||||
FREE(url);
|
||||
break;
|
||||
/* Album table - get all the albums of an artist */
|
||||
case 3:
|
||||
url = sonic_getArtist_link(id);
|
||||
linktbl = sonic_url_to_LinkTable(url, XML_parser_general, depth);
|
||||
FREE(url);
|
||||
break;
|
||||
/* Song table - get all the songs of an album */
|
||||
case 4:
|
||||
url = sonic_getAlbum_link(id);
|
||||
linktbl = sonic_url_to_LinkTable(url, XML_parser_general, depth);
|
||||
FREE(url);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* We shouldn't reach here.
|
||||
*/
|
||||
lprintf(fatal, "sonic_LinkTable_new_id3(): case %d.\n", depth);
|
||||
break;
|
||||
}
|
||||
return linktbl;
|
||||
char *url;
|
||||
LinkTable *linktbl = ROOT_LINK_TBL;
|
||||
switch (depth) {
|
||||
/*
|
||||
* Root table
|
||||
*/
|
||||
case 0:
|
||||
url = sonic_gen_url_first_part("getArtists");
|
||||
linktbl = sonic_url_to_LinkTable(url, XML_parser_id3_root, 0);
|
||||
FREE(url);
|
||||
break;
|
||||
/*
|
||||
* Album table - get all the albums of an artist
|
||||
*/
|
||||
case 3:
|
||||
url = sonic_getArtist_link(id);
|
||||
linktbl =
|
||||
sonic_url_to_LinkTable(url, XML_parser_general, depth);
|
||||
FREE(url);
|
||||
break;
|
||||
/*
|
||||
* Song table - get all the songs of an album
|
||||
*/
|
||||
case 4:
|
||||
url = sonic_getAlbum_link(id);
|
||||
linktbl =
|
||||
sonic_url_to_LinkTable(url, XML_parser_general, depth);
|
||||
FREE(url);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
* We shouldn't reach here.
|
||||
*/
|
||||
lprintf(fatal, "sonic_LinkTable_new_id3(): case %d.\n", depth);
|
||||
break;
|
||||
}
|
||||
return linktbl;
|
||||
}
|
||||
|
||||
|
|
159
src/util.c
159
src/util.c
|
@ -29,123 +29,126 @@
|
|||
|
||||
char *path_append(const char *path, const char *filename)
|
||||
{
|
||||
int needs_separator = 0;
|
||||
if ((path[strnlen(path, MAX_PATH_LEN)-1] != '/') && (filename[0] != '/')) {
|
||||
needs_separator = 1;
|
||||
}
|
||||
int needs_separator = 0;
|
||||
if ((path[strnlen(path, MAX_PATH_LEN) - 1] != '/')
|
||||
&& (filename[0] != '/')) {
|
||||
needs_separator = 1;
|
||||
}
|
||||
|
||||
char *str;
|
||||
size_t ul = strnlen(path, MAX_PATH_LEN);
|
||||
size_t sl = strnlen(filename, MAX_FILENAME_LEN);
|
||||
str = CALLOC(ul + sl + needs_separator + 1, sizeof(char));
|
||||
strncpy(str, path, ul);
|
||||
if (needs_separator) {
|
||||
str[ul] = '/';
|
||||
}
|
||||
strncat(str, filename, sl);
|
||||
return str;
|
||||
char *str;
|
||||
size_t ul = strnlen(path, MAX_PATH_LEN);
|
||||
size_t sl = strnlen(filename, MAX_FILENAME_LEN);
|
||||
str = CALLOC(ul + sl + needs_separator + 1, sizeof(char));
|
||||
strncpy(str, path, ul);
|
||||
if (needs_separator) {
|
||||
str[ul] = '/';
|
||||
}
|
||||
strncat(str, filename, sl);
|
||||
return str;
|
||||
}
|
||||
|
||||
int64_t round_div(int64_t a, int64_t b)
|
||||
{
|
||||
return (a + (b / 2)) / b;
|
||||
return (a + (b / 2)) / b;
|
||||
}
|
||||
|
||||
void PTHREAD_MUTEX_UNLOCK(pthread_mutex_t *x)
|
||||
void PTHREAD_MUTEX_UNLOCK(pthread_mutex_t * x)
|
||||
{
|
||||
int i;
|
||||
i = pthread_mutex_unlock(x);
|
||||
if (i) {
|
||||
lprintf(fatal, "thread %x: pthread_mutex_unlock() failed, %d, %s\n",
|
||||
pthread_self(), i, strerror(i));
|
||||
}
|
||||
int i;
|
||||
i = pthread_mutex_unlock(x);
|
||||
if (i) {
|
||||
lprintf(fatal,
|
||||
"thread %x: pthread_mutex_unlock() failed, %d, %s\n",
|
||||
pthread_self(), i, strerror(i));
|
||||
}
|
||||
}
|
||||
|
||||
void PTHREAD_MUTEX_LOCK(pthread_mutex_t *x)
|
||||
void PTHREAD_MUTEX_LOCK(pthread_mutex_t * x)
|
||||
{
|
||||
int i;
|
||||
i = pthread_mutex_lock(x);
|
||||
if (i) {
|
||||
lprintf(fatal, "thread %x: pthread_mutex_lock() failed, %d, %s\n",
|
||||
pthread_self(), i, strerror(i));
|
||||
}
|
||||
int i;
|
||||
i = pthread_mutex_lock(x);
|
||||
if (i) {
|
||||
lprintf(fatal,
|
||||
"thread %x: pthread_mutex_lock() failed, %d, %s\n",
|
||||
pthread_self(), i, strerror(i));
|
||||
}
|
||||
}
|
||||
|
||||
void exit_failure(void)
|
||||
{
|
||||
int nptrs;
|
||||
void *buffer[BT_BUF_SIZE];
|
||||
int nptrs;
|
||||
void *buffer[BT_BUF_SIZE];
|
||||
|
||||
nptrs = backtrace(buffer, BT_BUF_SIZE);
|
||||
fprintf(stderr, "\nOops! HTTPDirFS crashed! :(\n");
|
||||
fprintf(stderr, "backtrace() returned the following %d addresses:\n",
|
||||
nptrs);
|
||||
backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
|
||||
nptrs = backtrace(buffer, BT_BUF_SIZE);
|
||||
fprintf(stderr, "\nOops! HTTPDirFS crashed! :(\n");
|
||||
fprintf(stderr, "backtrace() returned the following %d addresses:\n",
|
||||
nptrs);
|
||||
backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void erase_string(FILE *file, size_t max_len, char *s)
|
||||
void erase_string(FILE * file, size_t max_len, char *s)
|
||||
{
|
||||
size_t l = strnlen(s, max_len);
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, "\b");
|
||||
}
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, " ");
|
||||
}
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, "\b");
|
||||
}
|
||||
size_t l = strnlen(s, max_len);
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, "\b");
|
||||
}
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, " ");
|
||||
}
|
||||
for (size_t k = 0; k < l; k++) {
|
||||
fprintf(file, "\b");
|
||||
}
|
||||
}
|
||||
|
||||
char *generate_salt(void)
|
||||
{
|
||||
char *out;
|
||||
out = CALLOC(SALT_LEN + 1, sizeof(char));
|
||||
uuid_t uu;
|
||||
uuid_generate(uu);
|
||||
uuid_unparse(uu, out);
|
||||
return out;
|
||||
char *out;
|
||||
out = CALLOC(SALT_LEN + 1, sizeof(char));
|
||||
uuid_t uu;
|
||||
uuid_generate(uu);
|
||||
uuid_unparse(uu, out);
|
||||
return out;
|
||||
}
|
||||
|
||||
char *generate_md5sum(const char *str)
|
||||
{
|
||||
MD5_CTX c;
|
||||
unsigned char md5[MD5_DIGEST_LENGTH];
|
||||
size_t len = strnlen(str, MAX_PATH_LEN);
|
||||
char *out = CALLOC(MD5_HASH_LEN + 1, sizeof(char));
|
||||
MD5_CTX c;
|
||||
unsigned char md5[MD5_DIGEST_LENGTH];
|
||||
size_t len = strnlen(str, MAX_PATH_LEN);
|
||||
char *out = CALLOC(MD5_HASH_LEN + 1, sizeof(char));
|
||||
|
||||
MD5_Init(&c);
|
||||
MD5_Update(&c, str, len);
|
||||
MD5_Final(md5, &c);
|
||||
MD5_Init(&c);
|
||||
MD5_Update(&c, str, len);
|
||||
MD5_Final(md5, &c);
|
||||
|
||||
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
||||
sprintf(out + 2 * i, "%02x", md5[i]);
|
||||
}
|
||||
return out;
|
||||
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
||||
sprintf(out + 2 * i, "%02x", md5[i]);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void *CALLOC(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr = calloc(nmemb, size);
|
||||
if (!ptr) {
|
||||
lprintf(fatal, "calloc() failed, %s!\n", strerror(errno));
|
||||
}
|
||||
return ptr;
|
||||
void *ptr = calloc(nmemb, size);
|
||||
if (!ptr) {
|
||||
lprintf(fatal, "calloc() failed, %s!\n", strerror(errno));
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void FREE(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
free(ptr);
|
||||
ptr = NULL;
|
||||
}
|
||||
|
||||
char *str_to_hex(char *s)
|
||||
{
|
||||
char *hex = CALLOC(strlen(s) * 2 + 1, sizeof(char));
|
||||
for (char *c = s, *h = hex; *c; c++, h+=2) {
|
||||
sprintf(h, "%x", *c);
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
char *hex = CALLOC(strlen(s) * 2 + 1, sizeof(char));
|
||||
for (char *c = s, *h = hex; *c; c++, h += 2) {
|
||||
sprintf(h, "%x", *c);
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue