Commit 3c59c90e authored by Michael Smith's avatar Michael Smith

Fileserving that might actually work for > 1 user.

cleanups for the base64 decoder.

svn path=/trunk/icecast/; revision=3856
parent b048ecc1
...@@ -533,13 +533,7 @@ static void _handle_get_request(connection_t *con, ...@@ -533,13 +533,7 @@ static void _handle_get_request(connection_t *con,
} }
else if(config_get_config()->fileserve && else if(config_get_config()->fileserve &&
stat(fullpath, &statbuf) == 0) { stat(fullpath, &statbuf) == 0) {
client->respcode = 200; fserve_client_create(client, fullpath);
bytes = sock_write(client->con->sock,
"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n",
fserve_content_type(fullpath));
if(bytes > 0) client->con->sent_bytes = bytes;
if(fserve_client_create(client, fullpath) < 0)
client_destroy(client);
free(fullpath); free(fullpath);
return; return;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/poll.h>
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
...@@ -41,6 +42,11 @@ static avl_tree *pending_tree; ...@@ -41,6 +42,11 @@ static avl_tree *pending_tree;
static cond_t fserv_cond; static cond_t fserv_cond;
static thread_t *fserv_thread; static thread_t *fserv_thread;
static int run_fserv; static int run_fserv;
static int fserve_clients;
static int client_tree_changed=0;
static struct pollfd *ufds = NULL;
static int ufdssize = 0;
/* avl tree helper */ /* avl tree helper */
static int _compare_clients(void *compare_arg, void *a, void *b); static int _compare_clients(void *compare_arg, void *a, void *b);
...@@ -77,6 +83,42 @@ void fserve_shutdown(void) ...@@ -77,6 +83,42 @@ void fserve_shutdown(void)
avl_tree_free(pending_tree, _free_client); avl_tree_free(pending_tree, _free_client);
} }
static void wait_for_fds() {
avl_node *client_node;
fserve_t *client;
int i;
while(run_fserv) {
if(client_tree_changed) {
client_tree_changed = 0;
i = 0;
ufdssize = fserve_clients;
ufds = realloc(ufds, ufdssize * sizeof(struct pollfd));
avl_tree_rlock(client_tree);
client_node = avl_get_first(client_tree);
while(client_node) {
client = client_node->key;
ufds[i].fd = client->client->con->sock;
ufds[i].events = POLLOUT;
client_node = avl_get_next(client_node);
}
avl_tree_unlock(client_tree);
}
if(poll(ufds, ufdssize, 200) > 0) {
return;
}
else {
avl_tree_rlock(pending_tree);
client_node = avl_get_first(pending_tree);
avl_tree_unlock(pending_tree);
if(client_node)
return;
}
}
}
void *fserv_thread_function(void *arg) void *fserv_thread_function(void *arg)
{ {
avl_node *client_node, *pending_node; avl_node *client_node, *pending_node;
...@@ -88,15 +130,25 @@ void *fserv_thread_function(void *arg) ...@@ -88,15 +130,25 @@ void *fserv_thread_function(void *arg)
client_node = avl_get_first(client_tree); client_node = avl_get_first(client_tree);
if(!client_node) { if(!client_node) {
avl_tree_rlock(pending_tree);
pending_node = avl_get_first(pending_tree); pending_node = avl_get_first(pending_tree);
if(!pending_node) { if(!pending_node) {
/* There are no current clients. Wait until there are... */ /* There are no current clients. Wait until there are... */
avl_tree_unlock(pending_tree);
avl_tree_unlock(client_tree); avl_tree_unlock(client_tree);
thread_cond_wait(&fserv_cond); thread_cond_wait(&fserv_cond);
continue; continue;
} }
avl_tree_unlock(pending_tree);
} }
/* This isn't hugely efficient, but it'll do for now */
avl_tree_unlock(client_tree);
wait_for_fds();
avl_tree_rlock(client_tree);
client_node = avl_get_first(client_tree);
while(client_node) { while(client_node) {
avl_node_wlock(client_node); avl_node_wlock(client_node);
...@@ -145,8 +197,10 @@ void *fserv_thread_function(void *arg) ...@@ -145,8 +197,10 @@ void *fserv_thread_function(void *arg)
while(client_node) { while(client_node) {
client = (fserve_t *)client_node->key; client = (fserve_t *)client_node->key;
if(client->client->con->error) { if(client->client->con->error) {
fserve_clients--;
client_node = avl_get_next(client_node); client_node = avl_get_next(client_node);
avl_delete(client_tree, (void *)client, _free_client); avl_delete(client_tree, (void *)client, _free_client);
client_tree_changed = 1;
continue; continue;
} }
client_node = avl_get_next(client_node); client_node = avl_get_next(client_node);
...@@ -159,6 +213,9 @@ void *fserv_thread_function(void *arg) ...@@ -159,6 +213,9 @@ void *fserv_thread_function(void *arg)
while(client_node) { while(client_node) {
client = (fserve_t *)client_node->key; client = (fserve_t *)client_node->key;
avl_insert(client_tree, client); avl_insert(client_tree, client);
client_tree_changed = 1;
fserve_clients++;
stats_event_inc(NULL, "clients");
client_node = avl_get_next(client_node); client_node = avl_get_next(client_node);
} }
...@@ -191,7 +248,7 @@ void *fserv_thread_function(void *arg) ...@@ -191,7 +248,7 @@ void *fserv_thread_function(void *arg)
return NULL; return NULL;
} }
char *fserve_content_type(char *path) static char *fserve_content_type(char *path)
{ {
char *ext = util_get_extension(path); char *ext = util_get_extension(path);
...@@ -225,17 +282,43 @@ static void fserve_client_destroy(fserve_t *client) ...@@ -225,17 +282,43 @@ static void fserve_client_destroy(fserve_t *client)
int fserve_client_create(client_t *httpclient, char *path) int fserve_client_create(client_t *httpclient, char *path)
{ {
fserve_t *client = calloc(1, sizeof(fserve_t)); fserve_t *client = calloc(1, sizeof(fserve_t));
int bytes;
client->client = httpclient;
client->file = fopen(path, "rb"); client->file = fopen(path, "rb");
if(!client->file) { if(!client->file) {
fserve_client_destroy(client); client_send_404(httpclient, "File not readable");
return -1; return -1;
} }
client->client = httpclient;
client->offset = 0; client->offset = 0;
client->datasize = 0; client->datasize = 0;
client->buf = malloc(BUFSIZE); client->buf = malloc(BUFSIZE);
global_lock();
if(global.clients >= config_get_config()->client_limit) {
httpclient->respcode = 504;
bytes = sock_write(httpclient->con->sock,
"HTTP/1.0 504 Server Full\r\n"
"Content-Type: text/html\r\n\r\n"
"<b>Server is full, try again later.</b>\r\n");
if(bytes > 0) httpclient->con->sent_bytes = bytes;
fserve_client_destroy(client);
global_unlock();
return -1;
}
global.clients++;
global_unlock();
httpclient->respcode = 200;
bytes = sock_write(httpclient->con->sock,
"HTTP/1.0 200 OK\r\n"
"Content-Type: %s\r\n\r\n",
fserve_content_type(path));
if(bytes > 0) httpclient->con->sent_bytes = bytes;
sock_set_blocking(client->client->con->sock, SOCK_NONBLOCK);
avl_tree_wlock(pending_tree); avl_tree_wlock(pending_tree);
avl_insert(pending_tree, client); avl_insert(pending_tree, client);
avl_tree_unlock(pending_tree); avl_tree_unlock(pending_tree);
...@@ -266,6 +349,11 @@ static int _free_client(void *key) ...@@ -266,6 +349,11 @@ static int _free_client(void *key)
fserve_t *client = (fserve_t *)key; fserve_t *client = (fserve_t *)key;
fserve_client_destroy(client); fserve_client_destroy(client);
global_lock();
global.clients--;
global_unlock();
stats_event_dec(NULL, "clients");
return 1; return 1;
} }
......
...@@ -15,7 +15,6 @@ typedef struct ...@@ -15,7 +15,6 @@ typedef struct
void fserve_initialize(void); void fserve_initialize(void);
void fserve_shutdown(void); void fserve_shutdown(void);
char *fserve_content_type(char *path);
int fserve_client_create(client_t *httpclient, char *path); int fserve_client_create(client_t *httpclient, char *path);
......
...@@ -43,6 +43,12 @@ static void _print_usage() ...@@ -43,6 +43,12 @@ static void _print_usage()
printf("\n"); printf("\n");
} }
static void _stop_logging(void)
{
log_close(errorlog);
log_close(accesslog);
}
static void _initialize_subsystems(void) static void _initialize_subsystems(void)
{ {
log_initialize(); log_initialize();
...@@ -54,7 +60,6 @@ static void _initialize_subsystems(void) ...@@ -54,7 +60,6 @@ static void _initialize_subsystems(void)
global_initialize(); global_initialize();
refbuf_initialize(); refbuf_initialize();
xslt_initialize(); xslt_initialize();
DEBUG0("Calling fserve_initialize()");
fserve_initialize(); fserve_initialize();
} }
...@@ -65,6 +70,10 @@ static void _shutdown_subsystems(void) ...@@ -65,6 +70,10 @@ static void _shutdown_subsystems(void)
refbuf_shutdown(); refbuf_shutdown();
stats_shutdown(); stats_shutdown();
slave_shutdown(); slave_shutdown();
/* Now that these are done, we can stop the loggers. */
_stop_logging();
global_shutdown(); global_shutdown();
connection_shutdown(); connection_shutdown();
config_shutdown(); config_shutdown();
...@@ -127,12 +136,6 @@ static int _start_logging(void) ...@@ -127,12 +136,6 @@ static int _start_logging(void)
return 0; return 0;
} }
static void _stop_logging(void)
{
log_close(errorlog);
log_close(accesslog);
}
static int _setup_socket(void) static int _setup_socket(void)
{ {
ice_config_t *config; ice_config_t *config;
...@@ -345,8 +348,6 @@ int main(int argc, char **argv) ...@@ -345,8 +348,6 @@ int main(int argc, char **argv)
INFO0("Shutting down"); INFO0("Shutting down");
_stop_logging();
_shutdown_subsystems(); _shutdown_subsystems();
return 0; return 0;
......
...@@ -275,6 +275,25 @@ static char base64table[64] = { ...@@ -275,6 +275,25 @@ static char base64table[64] = {
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
}; };
static signed char base64decode[256] = {
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -1, -2, -2,
-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
-2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
-2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};
/* This isn't efficient, but it doesn't need to be */ /* This isn't efficient, but it doesn't need to be */
char *util_base64_encode(char *data) char *util_base64_encode(char *data)
{ {
...@@ -309,25 +328,7 @@ char *util_base64_encode(char *data) ...@@ -309,25 +328,7 @@ char *util_base64_encode(char *data)
return result; return result;
} }
static int base64chartoval(char input) char *util_base64_decode(unsigned char *input)
{
if(input >= 'A' && input <= 'Z')
return input - 'A';
else if(input >= 'a' && input <= 'z')
return input - 'a' + 26;
else if(input >= '0' && input <= '9')
return input - '0' + 52;
else if(input == '+')
return 62;
else if(input == '/')
return 63;
else if(input == '=')
return -1;
else
return -2;
}
char *util_base64_decode(char *input)
{ {
int len = strlen(input); int len = strlen(input);
char *out = malloc(len*3/4 + 5); char *out = malloc(len*3/4 + 5);
...@@ -341,10 +342,10 @@ char *util_base64_decode(char *input) ...@@ -341,10 +342,10 @@ char *util_base64_decode(char *input)
return NULL; /* Invalid Base64 data */ return NULL; /* Invalid Base64 data */
} }
vals[0] = base64chartoval(*input++); vals[0] = base64decode[*input++];
vals[1] = base64chartoval(*input++); vals[1] = base64decode[*input++];
vals[2] = base64chartoval(*input++); vals[2] = base64decode[*input++];
vals[3] = base64chartoval(*input++); vals[3] = base64decode[*input++];
if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) { if(vals[0] < 0 || vals[1] < 0 || vals[2] < -1 || vals[3] < -1) {
continue; continue;
......
...@@ -12,6 +12,6 @@ char *util_get_path_from_uri(char *uri); ...@@ -12,6 +12,6 @@ char *util_get_path_from_uri(char *uri);
char *util_get_path_from_normalised_uri(char *uri); char *util_get_path_from_normalised_uri(char *uri);
char *util_normalise_uri(char *uri); char *util_normalise_uri(char *uri);
char *util_base64_encode(char *data); char *util_base64_encode(char *data);
char *util_base64_decode(char *input); char *util_base64_decode(unsigned char *input);
#endif /* __UTIL_H__ */ #endif /* __UTIL_H__ */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment