Finished writing the code to generate Subsonic LinkTable
- Also refactored various bits and pieces
This commit is contained in:
parent
b7c63f4418
commit
5062f511bd
5
Makefile
5
Makefile
|
@ -1,7 +1,8 @@
|
||||||
VERSION=1.1.10
|
VERSION=1.1.10
|
||||||
|
|
||||||
CFLAGS+= -O2 -Wall -Wextra -Wshadow -rdynamic\
|
CFLAGS+= -O2 -Wall -Wextra -Wshadow\
|
||||||
-D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\" \
|
-rdynamic -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE\
|
||||||
|
-D_FILE_OFFSET_BITS=64 -DVERSION=\"$(VERSION)\"\
|
||||||
`pkg-config --cflags-only-I gumbo libcurl fuse uuid expat`
|
`pkg-config --cflags-only-I gumbo libcurl fuse uuid expat`
|
||||||
LIBS = -pthread -lgumbo -lcurl -lfuse -lcrypto -luuid -lexpat
|
LIBS = -pthread -lgumbo -lcurl -lfuse -lcrypto -luuid -lexpat
|
||||||
COBJS = network.o fuse_local.o link.o cache.o util.o main.o
|
COBJS = network.o fuse_local.o link.o cache.o util.o main.o
|
||||||
|
|
30
src/cache.c
30
src/cache.c
|
@ -9,21 +9,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Data file block size
|
|
||||||
* \details We set it to 1024*1024*8 = 8MiB
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DEFAULT_DATA_BLK_SZ 8*1024*1024
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Maximum segment block count
|
|
||||||
* \details This is set to 128*1024 blocks, which uses 128KB. By default,
|
|
||||||
* this allows the user to store (128*1024)*(8*1024*1024) = 1TB of data
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define DEFAULT_MAX_SEGBC 128*1024
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief error associated with metadata
|
* \brief error associated with metadata
|
||||||
*/
|
*/
|
||||||
|
@ -36,10 +21,7 @@ typedef enum {
|
||||||
} MetaError;
|
} MetaError;
|
||||||
|
|
||||||
/* ---------------- External variables -----------------------*/
|
/* ---------------- External variables -----------------------*/
|
||||||
|
|
||||||
int CACHE_SYSTEM_INIT = 0;
|
int CACHE_SYSTEM_INIT = 0;
|
||||||
int DATA_BLK_SZ = 0;
|
|
||||||
int MAX_SEGBC = DEFAULT_MAX_SEGBC;
|
|
||||||
char *META_DIR;
|
char *META_DIR;
|
||||||
|
|
||||||
/* ----------------- Static variables ----------------------- */
|
/* ----------------- Static variables ----------------------- */
|
||||||
|
@ -156,10 +138,6 @@ void CacheSystem_init(const char *path, int url_supplied)
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DATA_BLK_SZ) {
|
|
||||||
DATA_BLK_SZ = DEFAULT_DATA_BLK_SZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
CACHE_SYSTEM_INIT = 1;
|
CACHE_SYSTEM_INIT = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,12 +180,12 @@ blksz: %d, segbc: %ld\n", cf->path, cf->content_length, cf->blksz, cf->segbc);
|
||||||
return EZERO;
|
return EZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cf->blksz != DATA_BLK_SZ) {
|
if (cf->blksz != CONFIG.data_blksz) {
|
||||||
fprintf(stderr, "Meta_read(): Warning: cf->blksz != DATA_BLK_SZ\n");
|
fprintf(stderr, "Meta_read(): Warning: cf->blksz != CONFIG.data_blksz\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate some memory for the segment */
|
/* Allocate some memory for the segment */
|
||||||
if (cf->segbc > MAX_SEGBC) {
|
if (cf->segbc > CONFIG.max_segbc) {
|
||||||
fprintf(stderr, "Meta_read(): Error: segbc: %ld\n", cf->segbc);
|
fprintf(stderr, "Meta_read(): Error: segbc: %ld\n", cf->segbc);
|
||||||
return EMEM;
|
return EMEM;
|
||||||
}
|
}
|
||||||
|
@ -671,7 +649,7 @@ int Cache_create(Link *this_link)
|
||||||
cf->path = strndup(fn, MAX_PATH_LEN);
|
cf->path = strndup(fn, MAX_PATH_LEN);
|
||||||
cf->time = this_link->time;
|
cf->time = this_link->time;
|
||||||
cf->content_length = this_link->content_length;
|
cf->content_length = this_link->content_length;
|
||||||
cf->blksz = DATA_BLK_SZ;
|
cf->blksz = CONFIG.data_blksz;
|
||||||
cf->segbc = (cf->content_length / cf->blksz) + 1;
|
cf->segbc = (cf->content_length / cf->blksz) + 1;
|
||||||
cf->seg = CALLOC(cf->segbc, sizeof(Seg));
|
cf->seg = CALLOC(cf->segbc, sizeof(Seg));
|
||||||
|
|
||||||
|
|
10
src/cache.h
10
src/cache.h
|
@ -70,16 +70,6 @@ struct Cache {
|
||||||
*/
|
*/
|
||||||
extern int CACHE_SYSTEM_INIT;
|
extern int CACHE_SYSTEM_INIT;
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief The size of each download segment
|
|
||||||
*/
|
|
||||||
extern int DATA_BLK_SZ;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief The maximum segment count for a single cache file
|
|
||||||
*/
|
|
||||||
extern int MAX_SEGBC;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief The metadata directory
|
* \brief The metadata directory
|
||||||
*/
|
*/
|
||||||
|
|
32
src/link.c
32
src/link.c
|
@ -49,9 +49,9 @@ LinkTable *LinkSystem_init(const char *url)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------- Enable cache system --------------------*/
|
/* ----------- Enable cache system --------------------*/
|
||||||
if (NETWORK_CONFIG.cache_enabled) {
|
if (CONFIG.cache_enabled) {
|
||||||
if (NETWORK_CONFIG.cache_dir) {
|
if (CONFIG.cache_dir) {
|
||||||
CacheSystem_init(NETWORK_CONFIG.cache_dir, 0);
|
CacheSystem_init(CONFIG.cache_dir, 0);
|
||||||
} else {
|
} else {
|
||||||
CacheSystem_init(url, 1);
|
CacheSystem_init(url, 1);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ LinkTable *LinkSystem_init(const char *url)
|
||||||
return ROOT_LINK_TBL;
|
return ROOT_LINK_TBL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LinkTable_add(LinkTable *linktbl, Link *link)
|
void LinkTable_add(LinkTable *linktbl, Link *link)
|
||||||
{
|
{
|
||||||
linktbl->num++;
|
linktbl->num++;
|
||||||
linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *));
|
linktbl->links = realloc(linktbl->links, linktbl->num * sizeof(Link *));
|
||||||
|
@ -139,7 +139,7 @@ static CURL *Link_to_curl(Link *link)
|
||||||
fprintf(stderr, "Link_to_curl(): curl_easy_init() failed!\n");
|
fprintf(stderr, "Link_to_curl(): curl_easy_init() failed!\n");
|
||||||
}
|
}
|
||||||
/* set up some basic curl stuff */
|
/* set up some basic curl stuff */
|
||||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, NETWORK_CONFIG.user_agent);
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, CONFIG.user_agent);
|
||||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||||
/* for following directories without the '/' */
|
/* for following directories without the '/' */
|
||||||
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2);
|
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 2);
|
||||||
|
@ -151,26 +151,26 @@ static CURL *Link_to_curl(Link *link)
|
||||||
|
|
||||||
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
// curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
|
|
||||||
if (NETWORK_CONFIG.username) {
|
if (CONFIG.http_username) {
|
||||||
curl_easy_setopt(curl, CURLOPT_USERNAME, NETWORK_CONFIG.username);
|
curl_easy_setopt(curl, CURLOPT_USERNAME, CONFIG.http_username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NETWORK_CONFIG.password) {
|
if (CONFIG.http_password) {
|
||||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, NETWORK_CONFIG.password);
|
curl_easy_setopt(curl, CURLOPT_PASSWORD, CONFIG.http_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NETWORK_CONFIG.proxy) {
|
if (CONFIG.proxy) {
|
||||||
curl_easy_setopt(curl, CURLOPT_PROXY, NETWORK_CONFIG.proxy);
|
curl_easy_setopt(curl, CURLOPT_PROXY, CONFIG.proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NETWORK_CONFIG.proxy_user) {
|
if (CONFIG.proxy_username) {
|
||||||
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME,
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERNAME,
|
||||||
NETWORK_CONFIG.proxy_user);
|
CONFIG.proxy_username);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NETWORK_CONFIG.proxy_pass) {
|
if (CONFIG.proxy_password) {
|
||||||
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD,
|
curl_easy_setopt(curl, CURLOPT_PROXYPASSWORD,
|
||||||
NETWORK_CONFIG.proxy_pass);
|
CONFIG.proxy_password);
|
||||||
}
|
}
|
||||||
|
|
||||||
return curl;
|
return curl;
|
||||||
|
@ -355,7 +355,7 @@ DataStruct Link_to_DataStruct(Link *head_link)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"LinkTable_new(): URL: %s, HTTP %ld, retrying later.\n",
|
"LinkTable_new(): URL: %s, HTTP %ld, retrying later.\n",
|
||||||
url, http_resp);
|
url, http_resp);
|
||||||
sleep(HTTP_WAIT_SEC);
|
sleep(CONFIG.http_wait_sec);
|
||||||
} else if (http_resp != HTTP_OK) {
|
} else if (http_resp != HTTP_OK) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"LinkTable_new(): cannot retrieve URL: %s, HTTP %ld\n",
|
"LinkTable_new(): cannot retrieve URL: %s, HTTP %ld\n",
|
||||||
|
|
|
@ -159,4 +159,8 @@ void LinkTable_free(LinkTable *linktbl);
|
||||||
*/
|
*/
|
||||||
void LinkTable_print(LinkTable *linktbl);
|
void LinkTable_print(LinkTable *linktbl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief add a Link to a LinkTable
|
||||||
|
*/
|
||||||
|
void LinkTable_add(LinkTable *linktbl, Link *link);
|
||||||
#endif
|
#endif
|
||||||
|
|
40
src/main.c
40
src/main.c
|
@ -36,7 +36,7 @@ int main(int argc, char **argv)
|
||||||
add_arg(&fuse_argv, &fuse_argc, argv[0]);
|
add_arg(&fuse_argv, &fuse_argc, argv[0]);
|
||||||
|
|
||||||
/* initialise network configuration struct */
|
/* initialise network configuration struct */
|
||||||
NetworkConfig_init();
|
Config_init();
|
||||||
|
|
||||||
/* initialise network subsystem */
|
/* initialise network subsystem */
|
||||||
NetworkSystem_init();
|
NetworkSystem_init();
|
||||||
|
@ -140,7 +140,10 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
||||||
{"max-conns", required_argument, NULL, 'L'}, /* 11 */
|
{"max-conns", required_argument, NULL, 'L'}, /* 11 */
|
||||||
{"user-agent", required_argument, NULL, 'L'}, /* 12 */
|
{"user-agent", required_argument, NULL, 'L'}, /* 12 */
|
||||||
{"retry-wait", required_argument, NULL, 'L'}, /* 13 */
|
{"retry-wait", required_argument, NULL, 'L'}, /* 13 */
|
||||||
{"cache-location", required_argument, NULL, 'L'}, /* 14 */
|
{"cache-location", required_argument, NULL, 'L'}, /* 14 */
|
||||||
|
{"sonic-username", required_argument, NULL, 'L'}, /* 15 */
|
||||||
|
{"sonic-password", required_argument, NULL, 'L'}, /* 16 */
|
||||||
|
{"sonic", no_argument, NULL, 'L'}, /* 17 */
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
while ((c =
|
while ((c =
|
||||||
|
@ -170,43 +173,52 @@ parse_arg_list(int argc, char **argv, char ***fuse_argv, int *fuse_argc)
|
||||||
add_arg(fuse_argv, fuse_argc, "-s");
|
add_arg(fuse_argv, fuse_argc, "-s");
|
||||||
break;
|
break;
|
||||||
case 'u':
|
case 'u':
|
||||||
NETWORK_CONFIG.username = strdup(optarg);
|
CONFIG.http_username = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
NETWORK_CONFIG.password = strdup(optarg);
|
CONFIG.http_password = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'P':
|
case 'P':
|
||||||
NETWORK_CONFIG.proxy = strdup(optarg);
|
CONFIG.proxy = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
/* Long options */
|
/* Long options */
|
||||||
switch (long_index) {
|
switch (long_index) {
|
||||||
case 6:
|
case 6:
|
||||||
NETWORK_CONFIG.proxy_user = strdup(optarg);
|
CONFIG.proxy_username = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
NETWORK_CONFIG.proxy_pass = strdup(optarg);
|
CONFIG.proxy_password = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
NETWORK_CONFIG.cache_enabled = 1;
|
CONFIG.cache_enabled = 1;
|
||||||
break;
|
break;
|
||||||
case 9:
|
case 9:
|
||||||
DATA_BLK_SZ = atoi(optarg) * 1024 * 1024;
|
CONFIG.data_blksz = atoi(optarg) * 1024 * 1024;
|
||||||
break;
|
break;
|
||||||
case 10:
|
case 10:
|
||||||
MAX_SEGBC = atoi(optarg);
|
CONFIG.max_segbc = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 11:
|
case 11:
|
||||||
NETWORK_CONFIG.max_conns = atoi(optarg);
|
CONFIG.max_conns = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 12:
|
||||||
NETWORK_CONFIG.user_agent = strdup(optarg);
|
CONFIG.user_agent = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
HTTP_WAIT_SEC = atoi(optarg);
|
CONFIG.http_wait_sec = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
NETWORK_CONFIG.cache_dir = strdup(optarg);
|
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_mode = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "see httpdirfs -h for usage\n");
|
fprintf(stderr, "see httpdirfs -h for usage\n");
|
||||||
|
|
|
@ -9,13 +9,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define DEFAULT_NETWORK_MAX_CONNS 10
|
|
||||||
#define DEFAULT_HTTP_WAIT_SEC 5
|
|
||||||
|
|
||||||
/* ----------------- External variables ---------------------- */
|
/* ----------------- External variables ---------------------- */
|
||||||
CURLSH *CURL_SHARE;
|
CURLSH *CURL_SHARE;
|
||||||
NetworkConfigStruct NETWORK_CONFIG;
|
|
||||||
int HTTP_WAIT_SEC = DEFAULT_HTTP_WAIT_SEC;
|
|
||||||
|
|
||||||
/* ----------------- Static variable ----------------------- */
|
/* ----------------- Static variable ----------------------- */
|
||||||
/** \brief curl multi interface handle */
|
/** \brief curl multi interface handle */
|
||||||
|
@ -123,8 +119,8 @@ static void curl_process_msgs(CURLMsg *curl_msg, int n_running_curl,
|
||||||
if (!slept) {
|
if (!slept) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
|
"curl_process_msgs(): HTTP %ld, sleeping for %d sec\n",
|
||||||
http_resp, HTTP_WAIT_SEC);
|
http_resp, CONFIG.http_wait_sec);
|
||||||
sleep(HTTP_WAIT_SEC);
|
sleep(CONFIG.http_wait_sec);
|
||||||
slept = 1;
|
slept = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -231,19 +227,6 @@ int curl_multi_perform_once(void)
|
||||||
return n_running_curl;
|
return n_running_curl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkConfig_init(void)
|
|
||||||
{
|
|
||||||
NETWORK_CONFIG.username = NULL;
|
|
||||||
NETWORK_CONFIG.password = NULL;
|
|
||||||
NETWORK_CONFIG.proxy = NULL;
|
|
||||||
NETWORK_CONFIG.proxy_user = NULL;
|
|
||||||
NETWORK_CONFIG.proxy_pass = NULL;
|
|
||||||
NETWORK_CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
|
|
||||||
NETWORK_CONFIG.user_agent = DEFAULT_USER_AGENT;
|
|
||||||
NETWORK_CONFIG.cache_enabled = 0;
|
|
||||||
NETWORK_CONFIG.cache_dir = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void NetworkSystem_init(void)
|
void NetworkSystem_init(void)
|
||||||
{
|
{
|
||||||
/* ------- Global related ----------*/
|
/* ------- Global related ----------*/
|
||||||
|
@ -277,9 +260,9 @@ void NetworkSystem_init(void)
|
||||||
exit_failure();
|
exit_failure();
|
||||||
}
|
}
|
||||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
curl_multi_setopt(curl_multi, CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||||
NETWORK_CONFIG.max_conns);
|
CONFIG.max_conns);
|
||||||
curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS,
|
curl_multi_setopt(curl_multi, CURLMOPT_MAX_HOST_CONNECTIONS,
|
||||||
NETWORK_CONFIG.max_conns);
|
CONFIG.max_conns);
|
||||||
|
|
||||||
/* ------------ Initialise locks ---------*/
|
/* ------------ Initialise locks ---------*/
|
||||||
if (pthread_mutex_init(&transfer_lock, NULL)) {
|
if (pthread_mutex_init(&transfer_lock, NULL)) {
|
||||||
|
|
|
@ -8,24 +8,6 @@
|
||||||
|
|
||||||
#include "link.h"
|
#include "link.h"
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief the default user agent string
|
|
||||||
*/
|
|
||||||
#define DEFAULT_USER_AGENT "HTTPDirFS-" VERSION
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *username;
|
|
||||||
char *password;
|
|
||||||
char *proxy;
|
|
||||||
char *proxy_user;
|
|
||||||
char *proxy_pass;
|
|
||||||
long max_conns;
|
|
||||||
char *user_agent;
|
|
||||||
int http_429_wait;
|
|
||||||
char *cache_dir;
|
|
||||||
int cache_enabled;
|
|
||||||
} NetworkConfigStruct;
|
|
||||||
|
|
||||||
/** \brief HTTP response codes */
|
/** \brief HTTP response codes */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
HTTP_OK = 200,
|
HTTP_OK = 200,
|
||||||
|
@ -36,21 +18,12 @@ typedef enum {
|
||||||
HTTP_CLOUDFLARE_TIMEOUT = 524
|
HTTP_CLOUDFLARE_TIMEOUT = 524
|
||||||
} HTTPResponseCode;
|
} HTTPResponseCode;
|
||||||
|
|
||||||
/** \brief The waiting time after getting HTTP 429 */
|
|
||||||
extern int HTTP_WAIT_SEC;
|
|
||||||
|
|
||||||
/** \brief CURL configuration */
|
|
||||||
extern NetworkConfigStruct NETWORK_CONFIG;
|
|
||||||
|
|
||||||
/** \brief curl shared interface */
|
/** \brief curl shared interface */
|
||||||
extern CURLSH *CURL_SHARE;
|
extern CURLSH *CURL_SHARE;
|
||||||
|
|
||||||
/** \brief perform one transfer cycle */
|
/** \brief perform one transfer cycle */
|
||||||
int curl_multi_perform_once(void);
|
int curl_multi_perform_once(void);
|
||||||
|
|
||||||
/** \brief initialise network config struct */
|
|
||||||
void NetworkConfig_init(void);
|
|
||||||
|
|
||||||
/** \brief initialise the network module */
|
/** \brief initialise the network module */
|
||||||
void NetworkSystem_init(void);
|
void NetworkSystem_init(void);
|
||||||
|
|
||||||
|
|
130
src/sonic.c
130
src/sonic.c
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *server;
|
char *server;
|
||||||
|
@ -31,8 +33,8 @@ void sonic_config_init(const char *server, const char *username,
|
||||||
if (SONIC_CONFIG.server[server_url_len] == '/') {
|
if (SONIC_CONFIG.server[server_url_len] == '/') {
|
||||||
SONIC_CONFIG.server[server_url_len] = '\0';
|
SONIC_CONFIG.server[server_url_len] = '\0';
|
||||||
}
|
}
|
||||||
SONIC_CONFIG.username = strndup(username, MAX_FILENAME_LEN);
|
SONIC_CONFIG.http_username = strndup(username, MAX_FILENAME_LEN);
|
||||||
SONIC_CONFIG.password = strndup(password, MAX_FILENAME_LEN);
|
SONIC_CONFIG.http_password = strndup(password, MAX_FILENAME_LEN);
|
||||||
SONIC_CONFIG.client = DEFAULT_USER_AGENT;
|
SONIC_CONFIG.client = DEFAULT_USER_AGENT;
|
||||||
/*
|
/*
|
||||||
* API 1.13.0 is the minimum version that supports
|
* API 1.13.0 is the minimum version that supports
|
||||||
|
@ -47,16 +49,16 @@ void sonic_config_init(const char *server, const char *username,
|
||||||
static char *sonic_gen_auth_str()
|
static char *sonic_gen_auth_str()
|
||||||
{
|
{
|
||||||
char *salt = generate_salt();
|
char *salt = generate_salt();
|
||||||
size_t password_len = strnlen(SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
size_t password_len = strnlen(SONIC_CONFIG.http_password, MAX_FILENAME_LEN);
|
||||||
size_t password_salt_len = password_len + strnlen(salt, MAX_FILENAME_LEN);
|
size_t password_salt_len = password_len + strnlen(salt, MAX_FILENAME_LEN);
|
||||||
char *password_salt = CALLOC(password_salt_len + 1, sizeof(char));
|
char *password_salt = CALLOC(password_salt_len + 1, sizeof(char));
|
||||||
strncat(password_salt, SONIC_CONFIG.password, MAX_FILENAME_LEN);
|
strncat(password_salt, SONIC_CONFIG.http_password, MAX_FILENAME_LEN);
|
||||||
strncat(password_salt + password_len, salt, MAX_FILENAME_LEN);
|
strncat(password_salt + password_len, salt, MAX_FILENAME_LEN);
|
||||||
char *token = generate_md5sum(password_salt);
|
char *token = generate_md5sum(password_salt);
|
||||||
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
char *auth_str = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||||
snprintf(auth_str, MAX_PATH_LEN,
|
snprintf(auth_str, MAX_PATH_LEN,
|
||||||
".view?u=%s&t=%s&s=%s&v=%s&c=%s",
|
".view?u=%s&t=%s&s=%s&v=%s&c=%s",
|
||||||
SONIC_CONFIG.username, token, salt,
|
SONIC_CONFIG.http_username, token, salt,
|
||||||
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
|
SONIC_CONFIG.api_version, SONIC_CONFIG.client);
|
||||||
free(salt);
|
free(salt);
|
||||||
free(token);
|
free(token);
|
||||||
|
@ -76,27 +78,54 @@ static char *sonic_gen_url_first_part(char *method)
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief generate a getMusicDirectory request URL
|
||||||
|
*/
|
||||||
|
static char *sonic_getMusicDirectory_link(const int 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=%d", first_part, id);
|
||||||
|
free(first_part);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief generate a download request URL
|
||||||
|
*/
|
||||||
|
static char *sonic_download_link(const int id)
|
||||||
|
{
|
||||||
|
char *first_part = sonic_gen_url_first_part("download");
|
||||||
|
char *url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
||||||
|
snprintf(url, MAX_PATH_LEN, "%s&id=%d", first_part, id);
|
||||||
|
free(first_part);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Process a single element output by the parser
|
* \brief Process a single element output by the parser
|
||||||
* \details This is the callback function called by the the XML parser.
|
* \details This is the callback function called by the the XML parser.
|
||||||
* \param[in] data user supplied data, in this case it is the pointer to the
|
* \param[in] data user supplied data, in this case it is the pointer to the
|
||||||
* LinkTable.
|
* LinkTable.
|
||||||
* \param[in] element the name of this element, it should be either "child" or
|
* \param[in] elem the name of this element, it should be either "child" or
|
||||||
* "artist"
|
* "artist"
|
||||||
* \param[in] attributes Each attribute seen in a start (or empty) tag occupies
|
* \param[in] attr Each attribute seen in a start (or empty) tag occupies
|
||||||
* 2 consecutive places in this vector: the attribute name followed by the
|
* 2 consecutive places in this vector: the attribute name followed by the
|
||||||
* attribute value. These pairs are terminated by a null pointer.
|
* attribute value. These pairs are terminated by a null pointer.
|
||||||
|
* \note we are using strcmp rather than strncmp, because we are assuming the
|
||||||
|
* parser terminates the strings properly, which is a fair assumption,
|
||||||
|
* considering how mature expat is.
|
||||||
*/
|
*/
|
||||||
static void XMLCALL XML_process_single_element(void *data, const char *element,
|
static void XMLCALL XML_process_single_element(void *data, const char *elem,
|
||||||
const char **attributes)
|
const char **attr)
|
||||||
{
|
{
|
||||||
LinkTable *linktbl = (LinkTable *) data;
|
LinkTable *linktbl = (LinkTable *) data;
|
||||||
Link *link;
|
Link *link;
|
||||||
if (!strncmp(element, "child", 5)) {
|
if (!strcmp(elem, "child")) {
|
||||||
/* Return from getMusicDirectory */
|
/* Return from getMusicDirectory */
|
||||||
link = CALLOC(1, sizeof(Link));
|
link = CALLOC(1, sizeof(Link));
|
||||||
link->type = LINK_INVALID;
|
link->type = LINK_INVALID;
|
||||||
} else if (!strncmp(element, "artist", 6)){
|
} else if (!strcmp(elem, "artist")){
|
||||||
/* Return from getIndexes */
|
/* Return from getIndexes */
|
||||||
link = CALLOC(1, sizeof(Link));
|
link = CALLOC(1, sizeof(Link));
|
||||||
link->type = LINK_DIR;
|
link->type = LINK_DIR;
|
||||||
|
@ -105,9 +134,78 @@ static void XMLCALL XML_process_single_element(void *data, const char *element,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; attributes[i]; i += 2) {
|
int id_set = 0;
|
||||||
|
int linkname_set = 0;
|
||||||
|
|
||||||
|
for (int i = 0; attr[i]; i += 2) {
|
||||||
|
if (!strcmp("id", attr[i])) {
|
||||||
|
link->sonic_id = atoi(attr[i+1]);
|
||||||
|
id_set = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp("name", attr[i]) || !strcmp("title", attr[i])) {
|
||||||
|
strncpy(link->linkname, attr[i+1], MAX_FILENAME_LEN);
|
||||||
|
linkname_set = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp("isDir", attr[i])) {
|
||||||
|
if (!strcmp("true", attr[i+1])) {
|
||||||
|
link->type = LINK_DIR;
|
||||||
|
} else if (!strcmp("false", attr[i+1])) {
|
||||||
|
link->type = LINK_FILE;
|
||||||
|
} else {
|
||||||
|
link->type = LINK_DIR;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clean up if linkname is not set */
|
||||||
|
if (!linkname_set) {
|
||||||
|
free(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up if id is not set */
|
||||||
|
if (!id_set) {
|
||||||
|
if (linkname_set) {
|
||||||
|
free(link->linkname);
|
||||||
|
}
|
||||||
|
free(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (link->type == LINK_DIR) {
|
||||||
|
char *url = sonic_getMusicDirectory_link(link->sonic_id);
|
||||||
|
strncpy(link->f_url, url, MAX_PATH_LEN);
|
||||||
|
free(url);
|
||||||
|
} else if (link->type == LINK_FILE) {
|
||||||
|
char *url = sonic_download_link(link->sonic_id);
|
||||||
|
strncpy(link->f_url, url, MAX_PATH_LEN);
|
||||||
|
free(url);
|
||||||
|
} else {
|
||||||
|
/* Invalid link */
|
||||||
|
free(link->linkname);
|
||||||
|
free(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkTable_add(linktbl, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,14 +225,12 @@ static void sonic_XML_to_LinkTable(DataStruct ds, LinkTable *linktbl)
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
LinkTable *sonic_LinkTable_new(const int id)
|
LinkTable *sonic_LinkTable_new(const int id)
|
||||||
{
|
{
|
||||||
char *url;
|
char *url;
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
char *first_part = sonic_gen_url_first_part("getMusicDirectory");
|
url = sonic_getMusicDirectory_link(id);
|
||||||
url = CALLOC(MAX_PATH_LEN + 1, sizeof(char));
|
|
||||||
snprintf(url, MAX_PATH_LEN, "%s&id=%d", first_part, id);
|
|
||||||
free(first_part);
|
|
||||||
} else {
|
} else {
|
||||||
url = sonic_gen_url_first_part("getIndexes");
|
url = sonic_gen_url_first_part("getIndexes");
|
||||||
}
|
}
|
||||||
|
@ -166,7 +262,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
sonic_config_init(argv[1], argv[2], argv[3]);
|
sonic_config_init(argv[1], argv[2], argv[3]);
|
||||||
|
|
||||||
NetworkConfig_init();
|
Config_init();
|
||||||
NetworkSystem_init();
|
NetworkSystem_init();
|
||||||
|
|
||||||
sonic_LinkTable_new(0);
|
sonic_LinkTable_new(0);
|
||||||
|
|
77
src/util.c
77
src/util.c
|
@ -9,10 +9,86 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Backtrace buffer size
|
||||||
|
*/
|
||||||
#define BT_BUF_SIZE 100
|
#define BT_BUF_SIZE 100
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The length of a MD5SUM string
|
||||||
|
*/
|
||||||
#define MD5_HASH_LEN 32
|
#define MD5_HASH_LEN 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The length of the salt
|
||||||
|
* \details This is basically the length of a UUID
|
||||||
|
*/
|
||||||
#define SALT_LEN 36
|
#define SALT_LEN 36
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The default maximum number of network connections
|
||||||
|
*/
|
||||||
|
#define DEFAULT_NETWORK_MAX_CONNS 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The default HTTP 429 (too many requests) wait time
|
||||||
|
*/
|
||||||
|
#define DEFAULT_HTTP_WAIT_SEC 5
|
||||||
|
/**
|
||||||
|
* \brief Data file block size
|
||||||
|
* \details We set it to 1024*1024*8 = 8MiB
|
||||||
|
*/
|
||||||
|
#define DEFAULT_DATA_BLKSZ 8*1024*1024
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Maximum segment block count
|
||||||
|
* \details This is set to 128*1024 blocks, which uses 128KB. By default,
|
||||||
|
* this allows the user to store (128*1024)*(8*1024*1024) = 1TB of data
|
||||||
|
*/
|
||||||
|
#define DEFAULT_MAX_SEGBC 128*1024
|
||||||
|
|
||||||
|
ConfigStruct CONFIG;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \note The opening curly bracket should be at line 39, so the code lines up
|
||||||
|
* with the definition code in util.h.
|
||||||
|
*/
|
||||||
|
void Config_init(void)
|
||||||
|
{
|
||||||
|
/*---------------- Network related --------------*/
|
||||||
|
CONFIG.http_username = NULL;
|
||||||
|
|
||||||
|
CONFIG.http_password = NULL;
|
||||||
|
|
||||||
|
CONFIG.proxy = NULL;
|
||||||
|
|
||||||
|
CONFIG.proxy_username = NULL;
|
||||||
|
|
||||||
|
CONFIG.proxy_password = NULL;
|
||||||
|
|
||||||
|
CONFIG.max_conns = DEFAULT_NETWORK_MAX_CONNS;
|
||||||
|
|
||||||
|
CONFIG.user_agent = DEFAULT_USER_AGENT;
|
||||||
|
|
||||||
|
CONFIG.http_wait_sec = DEFAULT_HTTP_WAIT_SEC;
|
||||||
|
|
||||||
|
/*--------------- Cache related ---------------*/
|
||||||
|
CONFIG.cache_enabled = 0;
|
||||||
|
|
||||||
|
CONFIG.cache_dir = NULL;
|
||||||
|
|
||||||
|
CONFIG.data_blksz = DEFAULT_DATA_BLKSZ;
|
||||||
|
|
||||||
|
CONFIG.max_segbc = DEFAULT_MAX_SEGBC;
|
||||||
|
|
||||||
|
/*-------------- Subsonic related -------------*/
|
||||||
|
CONFIG.sonic_mode = 0;
|
||||||
|
|
||||||
|
CONFIG.sonic_username = NULL;
|
||||||
|
|
||||||
|
CONFIG.sonic_password = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
char *path_append(const char *path, const char *filename)
|
char *path_append(const char *path, const char *filename)
|
||||||
{
|
{
|
||||||
int needs_separator = 0;
|
int needs_separator = 0;
|
||||||
|
@ -123,3 +199,4 @@ void *CALLOC(size_t nmemb, size_t size)
|
||||||
}
|
}
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
60
src/util.h
60
src/util.h
|
@ -21,6 +21,61 @@
|
||||||
*/
|
*/
|
||||||
#define MAX_FILENAME_LEN 255
|
#define MAX_FILENAME_LEN 255
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief the default user agent string
|
||||||
|
*/
|
||||||
|
#define DEFAULT_USER_AGENT "HTTPDirFS-" VERSION
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief configuration data structure
|
||||||
|
* \note The opening curly bracket should be at line 39, so the code belong
|
||||||
|
* lines up with the initialisation code in util.c
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
/** \brief HTTP username */
|
||||||
|
char *http_username;
|
||||||
|
/** \brief HTTP password */
|
||||||
|
char *http_password;
|
||||||
|
/** \brief HTTP proxy URL */
|
||||||
|
char *proxy;
|
||||||
|
/** \brief HTTP proxy username */
|
||||||
|
char *proxy_username;
|
||||||
|
/** \brief HTTP proxy password */
|
||||||
|
char *proxy_password;
|
||||||
|
/** \brief HTTP maximum connection count */
|
||||||
|
long max_conns;
|
||||||
|
/** \brief HTTP user agent*/
|
||||||
|
char *user_agent;
|
||||||
|
/** \brief The waiting time after getting HTTP 429 (too many requests) */
|
||||||
|
int http_wait_sec;
|
||||||
|
|
||||||
|
/** \brief Whether cache mode is enabled */
|
||||||
|
int cache_enabled;
|
||||||
|
/** \brief The cache location*/
|
||||||
|
char *cache_dir;
|
||||||
|
/** \brief The size of each download segment for cache mode */
|
||||||
|
int data_blksz;
|
||||||
|
/** \brief The maximum segment count for a single cache file */
|
||||||
|
int max_segbc;
|
||||||
|
|
||||||
|
/** \brief Whether we are using the Subsonic mode */
|
||||||
|
int sonic_mode;
|
||||||
|
/** \brief The Subsonic server username */
|
||||||
|
char *sonic_username;
|
||||||
|
/** \brief The Subsonic server password */
|
||||||
|
char *sonic_password;
|
||||||
|
} ConfigStruct;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief The Configuration data structure
|
||||||
|
*/
|
||||||
|
extern ConfigStruct CONFIG;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief append a path
|
* \brief append a path
|
||||||
* \details This function appends a path with the next level, while taking the
|
* \details This function appends a path with the next level, while taking the
|
||||||
|
@ -74,4 +129,9 @@ char *generate_md5sum(const char *str);
|
||||||
*/
|
*/
|
||||||
void *CALLOC(size_t nmemb, size_t size);
|
void *CALLOC(size_t nmemb, size_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief initialise the configuration data structure
|
||||||
|
*/
|
||||||
|
void Config_init(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue