Merge branch 'dbtool_preselect'
authorAndre <maan@p133.(none)>
Tue, 21 Feb 2006 08:22:36 +0000 (09:22 +0100)
committerAndre <maan@p133.(none)>
Tue, 21 Feb 2006 08:22:36 +0000 (09:22 +0100)
16 files changed:
Doxyfile
FEATURES
INSTALL
README
README.mysql
configure.ac
db.h
dopey.c [deleted file]
error.h
ipc.c [new file with mode: 0644]
ipc.h [new file with mode: 0644]
mysql.c
plm_dbtool.c [new file with mode: 0644]
random_dbtool.c [new file with mode: 0644]
server.c
server.ggo

index 090e120..37c9cec 100644 (file)
--- a/Doxyfile
+++ b/Doxyfile
@@ -452,8 +452,6 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories 
 # with spaces.
 
-#INPUT                  = net.c signal.c db.h db.c ringbuffer.c ringbuffer.h stat.c afs.c afs.h string.c net.h filter.h filter_chain.c error.h recv.h http_recv.c ortp_recv.c recv_common.c http.h mp3dec.c oggdec.c ortp.h wav.c compress.c daemon.c daemon.h grab_client.c grab_client.h close_on_fork.c close_on_fork.h audiod.c audiod.h time.c mysql.c server.h command.c server.c send.h http_send.c ortp_send.c http.h ortp.h mp3.c ogg.c dopey.c string.h exec.c
-
 INPUT = .
 
 # If the value of the INPUT tag contains directories, you can use the 
index 3dde8e9..b567f11 100644 (file)
--- a/FEATURES
+++ b/FEATURES
@@ -32,7 +32,7 @@ mysql-based audio file selector:
 small memory footprint:
 ~~~~~~~~~~~~~~~~~~~~~~~
        paraslash is lightweight. The stripped binary of para_server
-       with all its features compiled in (mysql/dopey dbtool,
+       with all its features compiled in (mysql/random dbtool,
        mp3/ogg support, http/ortp support) is about 100K on i386
        under Linux. para_audiod is even smaller.
 
@@ -53,7 +53,7 @@ authentication/encryption via openssl:
 various user interfaces and utilities:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        o para_gui. Curses based interface, displays information in a
-        curses window and can be used to easily control para_server
+       curses window and can be used to easily control para_server
        and para_audiod.
 
        o para_sdl_gui. Shows pictures (on a per song basis) and
diff --git a/INSTALL b/INSTALL
index 3b37318..9d82c9b 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -78,24 +78,19 @@ to retrieve the list of available commands and some server info.
 
 Choose your database tool (dbtool)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-You have three options:
+You have two options:
 
        1. Use the mysql dbtool which comes with paraslash and requires
-       mysql. This is recommended.
+       mysql.
 
-       2. Use your own database tool. If you have that already,
-       skip this step.
-
-       3. If you can not use the mysql dbtool and you just want
-       to quickly make paraslash working, use the dopey dbtool.
+       2. If you can not use the mysql dbtool and you just want
+       to quickly make paraslash working, use the random dbtool.
        The directory which is searched for audio files can be given
-       via the server option --dopey_dir.
-
-       Note, however, that dopey is _really_ dopey. It scans
-       $dopey_dir on every audio file change and chooses one
-       randomly. You get the idea. Have a look at its source code
-       and feel free to modify.
+       via the server option --random_dbtool_dir.
 
+       Note, however, that this database tool is really dopey. It
+       scans the given directory on every audio file change and
+       chooses one randomly. There is no further functionality.
 
 The current database tool can be changed at runtime via
 
diff --git a/README b/README
index 967655f..2c0dc76 100644 (file)
--- a/README
+++ b/README
@@ -27,9 +27,10 @@ It contains the following programs:
 
        para_server needs a database tool to work, mainly to determine
        which song to stream next. There are two database tools
-       available: mysql and dopey. The former is recommended as dopey
-       is only meant as a fallback and as a starting point for people
-       that want to write their own database tool for paraslash.
+       available: mysql and random. The former is recommended as
+       the random database tool is only meant as a fallback and
+       as a starting point for people that want to write their own
+       database tool for paraslash.
 
        The mysql database tool connects to a mysql server which
        holds information on your audio files. It has several unusual
index d2a27e7..7af8280 100644 (file)
@@ -50,8 +50,8 @@ indeed activated, type
 
        para_client cdt
 
-which prints the name of the current database tool. If the dopey
-dbtool is still selected, try
+which prints the name of the current database tool. If the mysql
+dbtool is not selected, try
 
        para_client cdt mysql
 
index da35350..0e93aa2 100644 (file)
@@ -72,8 +72,8 @@ audiod_errlist_objs="audiod exec close_on_fork signal string daemon stat net
 audiod_ldflags=""
 
 server_cmdline_objs="server.cmdline"
-server_errlist_objs="server mp3 afs command net string signal dopey time daemon stat
-       crypt http_send db close_on_fork"
+server_errlist_objs="server mp3 afs command net string signal random_dbtool time daemon stat
+       crypt http_send db close_on_fork plm_dbtool ipc"
 server_ldflags=""
 
 ########################################################################### ssl
diff --git a/db.h b/db.h
index 328f7de..69d4d9e 100644 (file)
--- a/db.h
+++ b/db.h
@@ -115,5 +115,6 @@ void (*post_select)(fd_set *rfds, fd_set *wfds);
 };
 
 int mysql_dbtool_init(struct dbtool*);
-int dopey_dbtool_init(struct dbtool*);
+int plm_dbtool_init(struct dbtool*);
+int random_dbtool_init(struct dbtool*);
 
diff --git a/dopey.c b/dopey.c
deleted file mode 100644 (file)
index 91e1368..0000000
--- a/dopey.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2004-2006 Andre Noll <maan@systemlinux.org>
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
- */
-
-/** \file dopey.c Simple database tool implementation. Feel free to modify.  */
-
-#include <sys/time.h> /* gettimeofday */
-#include "server.cmdline.h"
-#include "server.h"
-#include "db.h"
-#include "error.h"
-#include "net.h"
-#include "string.h"
-
-static int com_dopey(int, int, char **);
-extern struct gengetopt_args_info conf;
-extern struct misc_meta_data *mmd;
-
-static unsigned int num_audio_files, audio_file_count;
-static char **audio_file_list;
-
-static int count_audio_files(__unused const char *dir, __unused const char *name)
-{
-       num_audio_files++;
-       return 1;
-}
-
-static int remember_file(const char *dir, const char *name)
-{
-       if (audio_file_count >= num_audio_files)
-               return -E_FILE_COUNT;
-       audio_file_list[audio_file_count] = make_message("%s/%s", dir, name);
-       audio_file_count++;
-       return 1;
-}
-
-/* array of commands that are supported by this database tool */
-static struct server_command cmds[] = {
-{
-.name = "dopey",
-.handler = com_dopey,
-.perms = 0,
-.description = "about the dopey database tool",
-.synopsis = "dopey",
-.help =
-
-"It's so dumb. It hurts. Don't use it; switch to the mysql database\n"
-"tool instead. OTOH: You typed 'help dopey', so if you serious about\n"
-"that and you really intend to help the dopey database tool, look at\n"
-"my source code, dopey.c, and modify it to make it something useful.\n"
-
-}, {
-.name = NULL,
-}
-};
-
-static int com_dopey(int fd, __unused int argc, __unused char *argv[])
-{
-       return send_buffer(fd, "Please do not use me. I'm too sick to do "
-               "anything for you. Switch me off. Now!\n");
-}
-
-/*
- * Load a list of all audio files into memory and chose num of them randomly.
- * Called by server to determine next audio file to be streamed.
- */
-static char **dopey_get_audio_file_list(unsigned int num)
-{
-       int i, ret;
-       unsigned int len;
-       char **ret_list = NULL; /* what we are going to return */
-
-       audio_file_list = NULL;
-       num_audio_files = 0;
-       /* first run, just count all audio files. dopey */
-       ret = find_audio_files(conf.dopey_dir_arg, count_audio_files);
-       if (ret < 0)
-               goto out;
-       ret = -E_NOTHING_FOUND;
-       if (!num_audio_files)
-               goto out;
-       /* yeah, that doesn't scale, also dopey */
-       audio_file_list = para_malloc(num_audio_files * sizeof(char *));
-       audio_file_count = 0;
-       /* second run (hot dentry cache, hopefully), fill audio_file_list */
-       ret = find_audio_files(conf.dopey_dir_arg, remember_file);
-       if (ret < 0)
-               goto out;
-       /* careful, files might got deleted underneath */
-       num_audio_files = audio_file_count; /* can only decrease */
-       len = MIN(num, num_audio_files);
-       ret = -E_NOTHING_FOUND;
-       if (!len) /* nothing found, return NULL */
-               goto out;
-       /* success, return NULL-terminated list */
-       ret_list = para_calloc((len + 1) * sizeof(char *));
-       for (i = 0; i < len; i++) { /* choose randomly */
-               int r = (int) ((num_audio_files + 0.0) * (rand()
-                       / (RAND_MAX + 1.0)));
-               ret_list[i] = para_strdup(audio_file_list[r]);
-       }
-out:
-       if (audio_file_list) {
-               for (i = 0; i < num_audio_files; i++)
-                       free(audio_file_list[i]);
-               free(audio_file_list);
-       }
-//     if (ret < 0)
-//             PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
-       return ret_list;
-}
-
-static void dopey_shutdown(void)
-{
-       PARA_DEBUG_LOG("%s", "thanks for using another dbtool.\n");
-}
-
-/** dopey's (constant) database info text */
-#define DBINFO "dbinfo1:database info? You're kidding. I'm dopey!\ndbinfo2:\ndbinfo3:\n"
-
-/** the dopey init function
- *
- * Init all function pointers of \a db, init the dbinfo text and seed the
- * PRNG.
- *
- * \sa struct dbtool, misc_meta_data::dbinfo, mysql.c
- */
-int dopey_dbtool_init(struct dbtool *db)
-{
-       struct timeval now;
-
-       PARA_INFO_LOG("%s", "registering dopey handlers\n");
-       sprintf(mmd->dbinfo, DBINFO);
-       gettimeofday(&now, NULL);
-       srand(now.tv_usec);
-       db->cmd_list = cmds;
-       db->get_audio_file_list = dopey_get_audio_file_list;
-       db->shutdown = dopey_shutdown;
-       return 1;
-}
diff --git a/error.h b/error.h
index bc8475e..0c4a05f 100644 (file)
--- a/error.h
+++ b/error.h
@@ -23,8 +23,8 @@ enum para_subsystem {SS_RECV,
        SS_NET, SS_ORTP_RECV, SS_AUDIOD, SS_EXEC, SS_CLOSE_ON_FORK, SS_SIGNAL,
        SS_STRING, SS_DAEMON, SS_STAT, SS_TIME, SS_GRAB_CLIENT, SS_HTTP_RECV,
        SS_RECV_COMMON, SS_FILTER_CHAIN, SS_WAV, SS_COMPRESS, SS_OGGDEC, SS_FILTER,
-       SS_COMMAND, SS_DOPEY, SS_CRYPT, SS_HTTP_SEND, SS_ORTP_SEND, SS_DB, SS_OGG,
-       SS_MP3, SS_MP3DEC, SS_SERVER, SS_AFS, SS_MYSQL, SS_RINGBUFFER};
+       SS_COMMAND, SS_RANDOM_DBTOOL, SS_PLM_DBTOOL, SS_CRYPT, SS_HTTP_SEND, SS_ORTP_SEND, SS_DB, SS_OGG,
+       SS_MP3, SS_MP3DEC, SS_SERVER, SS_AFS, SS_MYSQL, SS_IPC, SS_RINGBUFFER};
 #define NUM_SS (SS_RINGBUFFER + 1)
 extern const char **para_errlist[];
 /** \endcond */
@@ -185,7 +185,7 @@ extern const char **para_errlist[];
        PARA_ERROR(WRITE_OK, "can not check whether fd is writable"), \
 
 
-#define DOPEY_ERRORS \
+#define RANDOM_DBTOOL_ERRORS \
        PARA_ERROR(FILE_COUNT, "audio file count exceeded"), \
        PARA_ERROR(NOTHING_FOUND, "no audio files found"), \
 
@@ -224,6 +224,16 @@ extern const char **para_errlist[];
        PARA_ERROR(LOCK, "lock error"), \
        PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
 
+#define PLM_DBTOOL_ERRORS \
+       PARA_ERROR(LOAD_PLAYLIST, "failed to load playlist"), \
+
+
+#define IPC_ERRORS \
+       PARA_ERROR(SEM_GET, "failed to create semaphore"), \
+       PARA_ERROR(SEM_REMOVE, "can not remove semaphore"), \
+       PARA_ERROR(SHM_GET, "failed to allocate shared memory area"), \
+       PARA_ERROR(SHM_DESTROY, "failed to destroy shared memory area"), \
+       PARA_ERROR(SHM_DETACH, "can not detach shared memory area"), \
 
 /* these do not need error handling (yet) */
 #define SERVER_ERRORS
@@ -331,12 +341,14 @@ SS_ENUM(OGG);
 SS_ENUM(SERVER);
 SS_ENUM(AFS);
 SS_ENUM(COMMAND);
-SS_ENUM(DOPEY);
+SS_ENUM(RANDOM_DBTOOL);
+SS_ENUM(PLM_DBTOOL);
 SS_ENUM(CRYPT);
 SS_ENUM(HTTP_SEND);
 SS_ENUM(ORTP_SEND);
 SS_ENUM(DB);
 SS_ENUM(MYSQL);
+SS_ENUM(IPC);
 SS_ENUM(RINGBUFFER);
 /** \endcond */
 #undef PARA_ERROR
diff --git a/ipc.c b/ipc.c
new file mode 100644 (file)
index 0000000..9ae2b3a
--- /dev/null
+++ b/ipc.c
@@ -0,0 +1,105 @@
+#include "para.h"
+#include "error.h"
+#include "ipc.h"
+#include <sys/ipc.h>
+#include <sys/shm.h>
+
+
+int mutex_new(void)
+{
+       int ret = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
+       return ret < 0?  -E_SEM_GET : ret;
+}
+
+int mutex_remove(int id)
+{
+       int ret = semctl(id, 0, IPC_RMID);
+       return ret < 0? -E_SEM_REMOVE : 1;
+}
+
+static void para_semop(int id, struct sembuf *sops, int num)
+{
+       if (semop(id, sops, num) >= 0)
+               return;
+       PARA_WARNING_LOG("semop failed (%s), retrying\n", strerror(errno));
+       while (semop(id, sops, num) < 0)
+               ; /* nothing */
+}
+
+/**
+ * lock the given mutex
+ *
+ * \sa semop(2), struct misc_meta_data
+ */
+void mutex_lock(int id)
+{
+       struct sembuf sops[2] = {
+               {
+                       .sem_num = 0,
+                       .sem_op = 0,
+                       .sem_flg = SEM_UNDO
+               },
+               {
+                       .sem_num = 0,
+                       .sem_op = 1,
+                       .sem_flg = SEM_UNDO
+               }
+       };
+       para_semop(id, sops, 2);
+}
+
+/**
+ * unlock a mutex
+ *
+ * \sa semop(2), struct misc_meta_data
+ */
+void mutex_unlock(int id)
+{
+       struct sembuf sops[1] = {
+               {
+                       .sem_num = 0,
+                       .sem_op = -1,
+                       .sem_flg = SEM_UNDO
+               },
+       };
+       para_semop(id, sops, 1);
+}
+
+/**
+ * create a new shared memory area of given size
+ * 
+ * \sa shmget(2)
+ */
+int shm_new(size_t size)
+{
+       int ret = shmget(IPC_PRIVATE, size, IPC_CREAT | IPC_EXCL | 0600);
+       return ret < 0 ? -E_SHM_GET : ret;
+}
+
+/**
+ * destroy the given shared memory area
+ * \sa shmctl(2)
+ **/
+int shm_destroy(int id)
+{
+       struct shmid_ds shm_desc;
+       int ret = shmctl(id, IPC_RMID, &shm_desc);
+       return ret < 0? -E_SHM_DESTROY : ret;
+}
+
+/**
+ * attach a shared memory area
+ *
+ * \sa semop(2)
+ */
+void *shm_attach(int id, enum shm_attach_mode mode)
+{
+       if (mode == ATTACH_RW)
+               return shmat(id, NULL, 0);
+       return shmat(id, NULL, SHM_RDONLY);
+}
+int shm_detach(void *addr)
+{
+       int ret = shmdt(addr);
+       return ret < 0? -E_SHM_DETACH : 1;
+}
diff --git a/ipc.h b/ipc.h
new file mode 100644 (file)
index 0000000..25c56d2
--- /dev/null
+++ b/ipc.h
@@ -0,0 +1,7 @@
+/** \file ipc.h inter process communication and shared memory routines */
+
+enum shm_attach_mode {ATTACH_RO, ATTACH_RW};
+
+int mutex_new(void);
+void mutex_lock(int id);
+void mutex_unlock(int id);
diff --git a/mysql.c b/mysql.c
index b8fa02d..9760f08 100644 (file)
--- a/mysql.c
+++ b/mysql.c
@@ -2514,7 +2514,7 @@ static void shutdown_connection(void)
  * Check the command line options and initialize all function pointers of \a db.
  * Connect to the mysql server and initialize the dbinfo string.
  *
- * \sa struct dbtool, misc_meta_data::dbinfo, dopey.c
+ * \sa struct dbtool, misc_meta_data::dbinfo, random_dbtool.c
  */
 int mysql_dbtool_init(struct dbtool *db)
 {
diff --git a/plm_dbtool.c b/plm_dbtool.c
new file mode 100644 (file)
index 0000000..fd18f25
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2006 Andre Noll <maan@systemlinux.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ */
+
+/** \file plm_dbtool.c Simple playlist manager for paraslash  */
+
+#include <sys/time.h> /* gettimeofday */
+#include "server.cmdline.h"
+#include "server.h"
+#include "db.h"
+#include "error.h"
+#include "net.h"
+#include "string.h"
+
+#define MAX_PLAYLIST_LEN 10000
+#define MAX_PLAYLIST_BYTES (1024 * 1024)
+
+static unsigned playlist_len, playlist_size, current_playlist_entry;
+static char **playlist;
+
+static int com_ppl(int, int, char **);
+static int com_lpl(int, int, char **);
+extern struct misc_meta_data *mmd;
+
+/* array of commands that are supported by this database tool */
+static struct server_command cmds[] = {
+{
+.name = "ppl",
+.handler = com_ppl,
+.perms = DB_READ,
+.description = "print playlist",
+.synopsis = "ppl",
+.help =
+"Print out the current playlist"
+}, {
+.name = "lpl",
+.handler = com_lpl,
+.perms = DB_WRITE,
+.description = "load playlist",
+.synopsis = "lpl",
+.help =
+"Read a new playlist from stdin"
+
+}, {
+.name = NULL,
+}
+};
+
+static void playlist_add(char *path)
+{
+       if (playlist_len >= playlist_size) {
+               if (playlist_size >= MAX_PLAYLIST_LEN)
+                       return;
+               playlist_size *= 2;
+               playlist = para_realloc(playlist, playlist_size * sizeof(char *));
+       }
+       PARA_DEBUG_LOG("adding #%d: %s\n", playlist_len, path);
+       playlist[playlist_len] = para_strdup(path);
+       playlist_len++;
+}
+
+static int com_lpl(int fd, __unused int argc, __unused char *argv[])
+{
+       unsigned i, loaded = 0;
+       char buf[_POSIX_PATH_MAX];
+       ssize_t ret;
+
+       PARA_DEBUG_LOG("freeing playlist (%d entries)\n", playlist_len);
+       for (i = 0; i < playlist_len; i++)
+               free(playlist[i]);
+       current_playlist_entry = 0;
+       playlist_len = 0;
+       ret = send_buffer(fd, AWAITING_DATA_MSG);
+       if (ret < 0)
+               return ret;
+again:
+       ret = recv_bin_buffer(fd, buf + loaded, sizeof(buf) - loaded);
+       if (ret < 0)
+               goto err_out;
+       if (!ret) {
+               PARA_DEBUG_LOG("loaded playlist (%d entries)\n", playlist_len);
+               return playlist_len;
+       }
+       loaded += ret;
+       loaded = for_each_line(buf, loaded, &playlist_add, 0);
+       if (loaded >= sizeof(buf))
+               goto err_out;
+       goto again;
+err_out:
+       return -E_LOAD_PLAYLIST;
+}
+
+static int com_ppl(int fd, __unused int argc, __unused char *argv[])
+{
+       unsigned i;
+
+       PARA_DEBUG_LOG("sending playlist (%d entries)\n", playlist_len);
+       for (i = 0; i < playlist_len; i++) {
+               int ret = send_buffer(fd, playlist[i]);
+               if (ret < 0)
+                       return ret;
+       }
+       return 1;
+}
+
+static char **plm_get_audio_file_list(unsigned int num)
+{
+       char **file_list;
+       unsigned i;
+
+       return NULL;
+       num = MIN(num, playlist_len);
+       if (!num)
+               return NULL;
+       file_list = para_malloc((num + 1) * sizeof(char *));
+       for (i = 0; i < num; i++) {
+               unsigned j = (current_playlist_entry + i) % playlist_len;
+               file_list[i] = para_strdup(playlist[j]);
+       }
+       file_list[i] = NULL;
+       return file_list;
+}
+
+static void plm_shutdown(void)
+{
+       /* free the playlist */
+}
+
+/**
+ *  the init function for the plm database tool
+ *
+ * Init all function pointers of \a db
+ *
+ * \sa struct dbtool, misc_meta_data::dbinfo, mysql.c random_dbtool.c
+ */
+int plm_dbtool_init(struct dbtool *db)
+{
+       playlist = para_calloc(100 * sizeof(char *)); /* guess 100 is enough */
+       playlist_size = 100;
+       sprintf(mmd->dbinfo, "plm initialized");
+       db->cmd_list = cmds;
+       db->get_audio_file_list = plm_get_audio_file_list;
+       db->shutdown = plm_shutdown;
+       return 1;
+}
diff --git a/random_dbtool.c b/random_dbtool.c
new file mode 100644 (file)
index 0000000..d970bd7
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2004-2006 Andre Noll <maan@systemlinux.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ */
+
+/** \file random_dbtool. Simple database tool implementation. Feel free to modify.  */
+
+#include <sys/time.h> /* gettimeofday */
+#include "server.cmdline.h"
+#include "server.h"
+#include "db.h"
+#include "error.h"
+#include "net.h"
+#include "string.h"
+
+static int com_random_info(int, int, char **);
+extern struct gengetopt_args_info conf;
+extern struct misc_meta_data *mmd;
+
+static unsigned int num_audio_files, audio_file_count;
+static char **audio_file_list;
+
+static int count_audio_files(__unused const char *dir, __unused const char *name)
+{
+       num_audio_files++;
+       return 1;
+}
+
+static int remember_file(const char *dir, const char *name)
+{
+       if (audio_file_count >= num_audio_files)
+               return -E_FILE_COUNT;
+       audio_file_list[audio_file_count] = make_message("%s/%s", dir, name);
+       audio_file_count++;
+       return 1;
+}
+
+/* array of commands that are supported by this database tool */
+static struct server_command cmds[] = {
+{
+.name = "random_info",
+.handler = com_random_info,
+.perms = 0,
+.description = "about the random database tool",
+.synopsis = "random_info",
+.help =
+
+"Select a random file under the given directory"
+}, {
+.name = NULL,
+}
+};
+
+static int com_random_info(int fd, __unused int argc, __unused char *argv[])
+{
+       return send_buffer(fd, "Don't use for huge directories as it is "
+               "very inefficient in this case.\n");
+}
+
+/*
+ * Load a list of all audio files into memory and chose num of them randomly.
+ * Called by server to determine next audio file to be streamed.
+ */
+static char **random_get_audio_file_list(unsigned int num)
+{
+       int i, ret;
+       unsigned int len;
+       char **ret_list = NULL; /* what we are going to return */
+
+       audio_file_list = NULL;
+       num_audio_files = 0;
+       /* first run, just count all audio files. dopey */
+       ret = find_audio_files(conf.random_dbtool_dir_arg, count_audio_files);
+       if (ret < 0)
+               goto out;
+       ret = -E_NOTHING_FOUND;
+       if (!num_audio_files)
+               goto out;
+       /* yeah, that doesn't scale, also dopey */
+       audio_file_list = para_malloc(num_audio_files * sizeof(char *));
+       audio_file_count = 0;
+       /* second run (hot dentry cache, hopefully), fill audio_file_list */
+       ret = find_audio_files(conf.random_dbtool_dir_arg, remember_file);
+       if (ret < 0)
+               goto out;
+       /* careful, files might got deleted underneath */
+       num_audio_files = audio_file_count; /* can only decrease */
+       len = MIN(num, num_audio_files);
+       ret = -E_NOTHING_FOUND;
+       if (!len) /* nothing found, return NULL */
+               goto out;
+       /* success, return NULL-terminated list */
+       ret_list = para_calloc((len + 1) * sizeof(char *));
+       for (i = 0; i < len; i++) { /* choose randomly */
+               int r = (int) ((num_audio_files + 0.0) * (rand()
+                       / (RAND_MAX + 1.0)));
+               ret_list[i] = para_strdup(audio_file_list[r]);
+       }
+out:
+       if (audio_file_list) {
+               for (i = 0; i < num_audio_files; i++)
+                       free(audio_file_list[i]);
+               free(audio_file_list);
+       }
+//     if (ret < 0)
+//             PARA_ERROR_LOG("%s\n", PARA_STRERROR(-ret));
+       return ret_list;
+}
+
+static void random_shutdown(void)
+{
+       PARA_DEBUG_LOG("%s", "thanks for using another dbtool.\n");
+}
+
+/** random's (constant) database info text */
+#define DBINFO "dbinfo1:database info? You're kidding. I'm still dopey!\ndbinfo2:\ndbinfo3:\n"
+
+/**
+ *  the init function for the random database tool
+ *
+ * Init all function pointers of \a db, init the dbinfo text and seed the
+ * PRNG.
+ *
+ * \sa struct dbtool, misc_meta_data::dbinfo, mysql.c
+ */
+int random_dbtool_init(struct dbtool *db)
+{
+       struct timeval now;
+
+       PARA_INFO_LOG("%s", "registering random handlers ;)\n");
+       sprintf(mmd->dbinfo, DBINFO);
+       gettimeofday(&now, NULL);
+       srand(now.tv_usec);
+       db->cmd_list = cmds;
+       db->get_audio_file_list = random_get_audio_file_list;
+       db->shutdown = random_shutdown;
+       return 1;
+}
index 8d94353..c185b3e 100644 (file)
--- a/server.c
+++ b/server.c
@@ -63,8 +63,13 @@ extern struct audio_format afl[];
 /** the list of supported database tools */
 struct dbtool dblist[] = {
        {
-               .name = "dopey",
-               .init = dopey_dbtool_init,
+               .name = "random",
+               .init = random_dbtool_init,
+               .update_audio_file = NULL,
+       },
+       {
+               .name = "plm",
+               .init = plm_dbtool_init,
                .update_audio_file = NULL,
                .pre_select = NULL,
                .post_select = NULL,
@@ -306,7 +311,7 @@ static void init_dbtool(void)
 
        mmd->dbt_change = -1; /* no change nec., set to new dbt num by com_cdt */
        if (!dblist[1].name)
-               goto dopey;
+               goto random;
        if (conf.dbtool_given) {
                for (i = 0; dblist[i].name; i++) {
                        if (strcmp(dblist[i].name, conf.dbtool_arg))
@@ -316,16 +321,16 @@ static void init_dbtool(void)
                        if (dblist[i].init(&dblist[i]) < 0) {
                                PARA_WARNING_LOG("init %s failed",
                                        dblist[i].name);
-                               goto dopey;
+                               goto random;
                        }
                        mmd->dbt_num = i;
                        return;
                }
-               PARA_WARNING_LOG("%s", "no such dbtool, switching to dopey\n");
-               goto dopey;
+               PARA_WARNING_LOG("%s", "no such dbtool, switching to random\n");
+               goto random;
        }
        /* use the first dbtool that works
-        * (assuming that dopey always works)
+        * (assuming that random always works)
         */
        for (i = 1; dblist[i].name; i++) {
                int ret = dblist[i].init(&dblist[i]);
@@ -337,7 +342,7 @@ static void init_dbtool(void)
                PARA_CRIT_LOG("%s init failed: %s\n", dblist[i].name,
                        PARA_STRERROR(-ret));
        }
-dopey:
+random:
        mmd->dbt_num = 0;
        dblist[0].init(&dblist[0]); /* always successful */
 }
@@ -421,7 +426,7 @@ static void handle_dbt_change(void)
                return;
        }
        /* init failed */
-       PARA_ERROR_LOG("%s -- switching to dopey\n", PARA_STRERROR(-ret));
+       PARA_ERROR_LOG("%s -- switching to the random dbtool\n", PARA_STRERROR(-ret));
        dblist[0].init(&dblist[0]);
        mmd->dbt_num = 0;
 }
index 52dc90b..a7db080 100644 (file)
@@ -25,8 +25,8 @@ option "mysql_default_score" - "scoring rule to use if stream definition does no
 
 
 
-section "Dopey database tool options"
-option "dopey_dir" - "dir to search for files to be streamed" string default="/home/music" no
+section "Random database tool options"
+option "random_dbtool_dir" - "dir to search for files to be streamed" string default="/home/music" no
 
 section "Http sender options"
 option "http_port" - "tcp port for http streaming" int typestr="portnumber" default="8000" no
@@ -40,4 +40,3 @@ option "ortp_target" - "Add given host/port to the list of targets. This option
 option "ortp_no_autostart" - "do not start to send automatically" flag off
 option "ortp_default_port" - "default udp port if not specified" int typestr="portnumber" default="1500" no
 option "ortp_header_interval" H "time between extra header sends" int typestr="milliseconds" default="2000" no
-