0.4.9 (to be announced) "hybrid causality"
------------------------------------------
+ - Fix for an endless loop in the mp3 decoder for certain
+ (corrupt) mp3 files.
+ - autogen.sh now detects a distcc setup and adjusts the
+ parameter for the -j option of make accordingly.
+ - Shared memory areas are no longer restricted to 64K. We now
+ detect the maximal size of a shared memory area at runtime.
+ - cleanup of the internal uptime API.
+
--------------------------------------
0.4.8 (2011-08-19) "nested assignment"
--------------------------------------
{
float tmp = mp4ASC->sbr_present_flag == 1? 2047 : 1023;
struct timeval total;
- long unsigned ms = 1000.0 * afhi->chunks_total * tmp
- / mp4ASC->samplingFrequency;
+ long unsigned ms;
if (!mp4ASC->samplingFrequency)
return -E_MP4ASC;
* command. This function allows to pass such a structure together with a list
* of further arguments (often a list of audio files) to the parent process.
*
+ * \return The return value of the underlying call to \ref
+ * send_callback_request().
+ *
* \sa send_standard_callback_request(), send_callback_request().
*/
int send_option_arg_callback_request(struct osl_object *options,
static void com_select_callback(int fd, const struct osl_object *query)
{
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
* \param pb Unused.
* \param data Unused.
*
- * This table does not honor events.
+ * \return The images table does not honor events, so this handler always
+ * returns success.
*/
__a_const int images_event_handler(__a_unused enum afs_events event,
__a_unused struct para_buffer *pb, __a_unused void *data)
* \param pb Unused.
* \param data Unused.
*
- * This table does not honor events.
+ * \return The lyrics table does not honor events, so this handler always
+ * returns success.
*/
__a_const int lyrics_event_handler(__a_unused enum afs_events event,
__a_unused struct para_buffer *pb, __a_unused void *data)
.flags = LS_FLAG_FULL_PATH | LS_FLAG_ADMISSIBLE_ONLY,
.mode = LS_MODE_VERBOSE,
};
- struct para_buffer pb = {.max_size = SHMMAX - 1};
+ struct para_buffer pb = {.max_size = shm_get_shmmax() - 1};
time_t current_time;
int ret;
free(status_items);
status_items = pb.buf;
memset(&pb, 0, sizeof(pb));
- pb.max_size = SHMMAX - 1;
+ pb.max_size = shm_get_shmmax() - 1;
pb.flags = PBF_SIZE_PREFIX;
ret = print_list_item(&d, &opts, &pb, current_time);
if (ret < 0) {
{
struct ls_options *opts = query->data;
char *p, *pattern_start = (char *)query->data + sizeof(*opts);
- struct para_buffer b = {.max_size = SHMMAX,
+ struct para_buffer b = {.max_size = shm_get_shmmax(),
.flags = (opts->mode == LS_MODE_PARSER)? PBF_SIZE_PREFIX : 0,
.max_size_handler = pass_buffer_as_shm, .private_data = &fd};
int i = 0, ret;
char afsi_buf[AFSI_SIZE];
uint32_t flags = read_u32(buf + CAB_FLAGS_OFFSET);
struct afs_info default_afsi = {.last_played = 0};
- struct para_buffer msg = {.max_size = SHMMAX,
+ struct para_buffer msg = {.max_size = shm_get_shmmax(),
.max_size_handler = pass_buffer_as_shm, .private_data = &fd};
uint16_t afhi_offset, chunks_offset;
{
struct touch_action_data tad = {.cto = query->data,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
{
struct com_rm_action_data crd = {.flags = *(uint32_t *)query->data,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
struct cpsi_action_data cad = {
.flags = *(unsigned *)query->data,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
* up-to-date afs status items directly. Therefore the usual callback mechanism
* is used to pass the status items from the afs process to the command handler
* via a shared memory area and a pipe.
+ *
+ * \return The return value of the underyling call to \ref send_callback_request().
*/
int send_afs_status(struct stream_cipher_context *scc, int parser_friendly)
{
void aft_check_callback(int fd, __a_unused const struct osl_object *query)
{
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
struct lsatt_action_data laad = {
.flags = *(unsigned *) query->data,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
char *p;
int ret = 1, ret2 = 0;
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
struct osl_object obj = {.data = old, .size = size};
struct osl_row *row;
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
struct remove_attribute_action_data raad = {
.num_removed = 0,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
exit(EXIT_FAILURE);
}
log_welcome("para_audiod");
- server_uptime(UPTIME_SET);
+ set_server_start_time(NULL);
set_initial_status();
FOR_EACH_SLOT(i)
clear_slot(i);
free(new);
}
- new = uptime_str();
+ new = get_server_uptime_str(now);
old = stat_item_values[SI_AUDIOD_UPTIME];
if (!old || strcmp(old, new)) {
free(old);
DEFINE_BLOB_TABLE_DESC(table_name); \
DEFINE_BLOB_TABLE_PTR(table_name);
-/** \cond doxygen isn't smart enough to recognize these */
+/* doxygen isn't smart enough to recognize these */
+/** \cond blob_table */
INIT_BLOB_TABLE(lyrics);
INIT_BLOB_TABLE(images);
INIT_BLOB_TABLE(moods);
INIT_BLOB_TABLE(playlists);
-/** \endcond */
+/** \endcond blob_table */
/** Flags that may be passed to the \p ls functions of each blob type. */
enum blob_ls_flags {
struct lsblob_action_data lbad = {
.flags = *(uint32_t *)query->data,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
struct rmblob_data rmbd = {
.num_removed = 0,
.pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
}
DEFINE_GET_DEF_BY_NAME(table_name, cmd_prefix); \
DEFINE_GET_NAME_AND_DEF_BY_ROW(table_name, cmd_prefix); \
-/** \cond doxygen isn't smart enough to recognize these */
+/* doxygen isn't smart enough to recognize these */
+/** \cond blob_function */
DEFINE_BLOB_FUNCTIONS(lyrics, lyr);
DEFINE_BLOB_FUNCTIONS(images, img);
DEFINE_BLOB_FUNCTIONS(moods, mood);
DEFINE_BLOB_FUNCTIONS(playlists, pl);
-/** \endcond */
+/** \endcond blob_function */
{
char mtime[30] = "";
char *status, *flags; /* vss status info */
- char *ut = uptime_str();
+ /* nobody updates our version of "now" */
+ char *ut = get_server_uptime_str(NULL);
long offset = (nmmd->offset + 500) / 1000;
struct timeval current_time;
struct tm mtime_tm;
sender_info = para_strcat(sender_info, info);
free(info);
}
- ut = uptime_str();
+ ut = get_server_uptime_str(now);
ret = sc_send_va_buffer(scc, "version: " GIT_VERSION "\n"
"up: %s\nplayed: %u\n"
"server_pid: %d\n"
ret = -E_AUTH_REQUEST;
goto net_err;
}
- numbytes = ret;
ret = -E_AUTH_REQUEST;
if (strncmp(buf, AUTH_REQUEST_MSG, strlen(AUTH_REQUEST_MSG)))
goto net_err;
p = buf + strlen(AUTH_REQUEST_MSG);
PARA_DEBUG_LOG("received auth request for user %s\n", p);
- ret = -E_BAD_USER;
u = lookup_user(p);
if (u) {
get_random_bytes_or_die(rand_buf, sizeof(rand_buf));
PARA_INFO_LOG("decoding public rsa-ssh key %s\n", key_file);
ret = -ERRNO_TO_PARA_ERROR(EOVERFLOW);
if (map_size > INT_MAX / 4)
- goto out;
+ goto out_unmap;
blob_size = 2 * map_size;
blob = para_malloc(blob_size);
ret = uudecode(cp, blob, blob_size);
if (ret < 0)
- goto out;
+ goto out_unmap;
decoded_size = ret;
ret = check_ssh_key_header(blob, decoded_size);
if (ret < 0)
- goto out;
+ goto out_unmap;
ret = read_rsa_bignums(blob + ret, decoded_size - ret, &key->rsa);
if (ret < 0)
- goto out;
+ goto out_unmap;
ret = RSA_size(key->rsa);
-out:
+out_unmap:
ret2 = para_munmap(map, map_size);
if (ret >= 0 && ret2 < 0)
ret = ret2;
+out:
if (ret < 0) {
free(key);
*result = NULL;
/** \file crypt.h Public crypto interface. */
-/** \cond used to distinguish between loading of private/public key */
+/* These are used to distinguish between loading of private/public key. */
+
+/** The key to load is a public key. */
#define LOAD_PUBLIC_KEY 0
+/** The key to load is a private key. */
#define LOAD_PRIVATE_KEY 1
+/** The size of the challenge sent to the client. */
#define CHALLENGE_SIZE 64
-/** \endcond **/
-
-/* asymetric (public key) crypto */
/** Opaque structure for public and private keys. */
struct asymmetric_key;
char *logfile_name;
/** Current loglevel, see \ref daemon_set_loglevel(). */
int loglevel;
-
/** Used by \ref server_uptime() and \ref uptime_str(). */
time_t startuptime;
/** The file pointer if the logfile is open. */
}
/**
- * Set/get the server uptime.
+ * Set the server startup time.
+ *
+ * \param startuptime The value to store as the server start time.
*
- * \param set_or_get Chose one of the two modes.
+ * This should be called once on startup with \a startuptime either NULL or a
+ * pointer to a struct timeval which contains the current time. If \a
+ * startuptime is NULL, the server start time is set to the current time.
*
- * This should be called at startup time with \a set_or_get equal to \p
- * UPTIME_SET which sets the uptime to zero. Subsequent calls with \a
- * set_or_get equal to \p UPTIME_GET return the uptime.
+ * \sa time(2), difftime(3) \ref get_server_uptime(), \ref
+ * get_server_uptime_str().
+ */
+void set_server_start_time(const struct timeval *startuptime)
+{
+ if (startuptime)
+ me->startuptime = startuptime->tv_sec;
+ else
+ time(&me->startuptime);
+}
- * \return Zero if called with \a set_or_get equal to \p UPTIME_SET, the number
- * of seconds elapsed since the last reset otherwise.
+/**
+ * Get the server uptime.
+ *
+ * \param current_time The current time.
+ *
+ * The \a current_time pointer may be \p NULL. In this case the function
+ * obtains the current time from the system.
*
- * \sa time(2), difftime(3).
+ * \return This returns the server uptime in seconds, i.e. the difference
+ * between the current time and the value stored previously via \ref
+ * set_server_start_time().
*/
-time_t server_uptime(enum uptime set_or_get)
+time_t get_server_uptime(const struct timeval *current_time)
{
- time_t now;
- double diff;
+ time_t t;
- if (set_or_get == UPTIME_SET) {
- time(&me->startuptime);
- return 0;
- }
- time(&now);
- diff = difftime(now, me->startuptime);
- return (time_t) diff;
+ if (current_time)
+ return current_time->tv_sec - me->startuptime;
+ time(&t);
+ return difftime(t, me->startuptime);
}
/**
- * Construct string containing uptime.
+ * Construct a string containing the current uptime.
+ *
+ * \param current_time See a \ref get_server_uptime().
*
* \return A dynamically allocated string of the form "days:hours:minutes".
*
* \sa server_uptime.
*/
-__malloc char *uptime_str(void)
+__malloc char *get_server_uptime_str(const struct timeval *current_time)
{
- long t = server_uptime(UPTIME_GET);
+ long t = get_server_uptime(current_time);
return make_message("%li:%02li:%02li", t / 86400,
(t / 3600) % 24, (t / 60) % 60);
}
void log_welcome(const char *whoami);
void drop_privileges_or_die(const char *username, const char *groupname);
/** used for server_uptime() */
-enum uptime {UPTIME_SET, UPTIME_GET};
-time_t server_uptime(enum uptime set_or_get);
-__malloc char *uptime_str(void);
+void set_server_start_time(const struct timeval *startuptime);
+time_t get_server_uptime(const struct timeval *current_time);
+__malloc char *get_server_uptime_str(const struct timeval *current_time);
void daemon_set_logfile(char *logfile_name);
void daemon_set_flag(unsigned flag);
void daemon_clear_flag(unsigned flag);
static void dccp_recv_close(struct receiver_node *rn)
{
-
struct private_dccp_recv_data *pdd = rn->private_data;
- if (pdd && pdd->fd > 0)
+ if (!pdd)
+ return;
+ if (pdd->fd > 0)
close(pdd->fd);
btr_pool_free(pdd->btrp);
- free(rn->private_data);
+ free(pdd);
rn->private_data = NULL;
}
/** \file error.h List of error messages for all subsystems. */
-/** \cond */
+/** \cond errors */
/* List of all subsystems that use paraslash's error facility. */
DEFINE_ERRLIST_OBJECT_ENUM;
PARA_ERROR(QUEUE, "packet queue overrun"), \
-/** \endcond */
+/** \endcond errors */
/**
* The subsystem shift.
fft(&s->fft, z);
/* post rotation + reordering */
- output += n4;
for (k = 0; k < n8; k++) {
fftsample_t r0, i0, r1, i1;
CMUL(r0, i1, z[n8 - k - 1].im, z[n8 - k - 1].re,
#include "para.h"
#include "error.h"
#include "ipc.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
int ret = shmdt(addr);
return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : 1;
}
+
+# if defined __FreeBSD__ || defined __NetBSD__
+# define SYSCTL_SHMMAX_VARIABLE "kern.ipc.shmmax"
+# elif defined __APPLE__
+# define SYSCTL_SHMMAX_VARIABLE "kern.sysv.shmmax"
+# else
+# undef SYSCTL_SHMMAX_VARIABLE
+# endif
+
+/**
+ * Get the maximal size of a shared memory area.
+ *
+ * The value is only computed once when the function is called for the first
+ * time. Subsequent calls return the number which was computed during the
+ * first call.
+ *
+ * \return A number suitable as an argument to \ref shm_new().
+ */
+size_t shm_get_shmmax(void)
+{
+ static size_t shmmax;
+
+ if (shmmax > 0) /* only dance once */
+ return shmmax;
+#ifdef __linux__ /* get it from proc fs */
+ {
+ int fd = open("/proc/sys/kernel/shmmax", O_RDONLY);
+ if (fd >= 0) {
+ char buf[100] = "";
+ int ret = read(fd, buf, sizeof(buf) - 1);
+ if (ret > 0) {
+ buf[ret] = '\0';
+ shmmax = strtoul(buf, NULL, 10);
+ }
+ }
+ }
+#elif defined SYSCTL_SHMMAX_VARIABLE
+ {
+ size_t len = sizeof(shmmax);
+ sysctlbyname(SYSCTL_SHMMAX_VARIABLE, &shmmax, &len, NULL, 0);
+ }
+#elif defined SHMMAX
+ shmmax = SHMMAX;
+#endif
+ if (shmmax == 0) {
+ PARA_WARNING_LOG("unable to determine shmmax\n");
+ shmmax = 65535; /* last ressort */
+ }
+ PARA_INFO_LOG("shmmax: %zu\n", shmmax);
+ return shmmax;
+}
int shm_attach(int id, enum shm_attach_mode mode, void **result);
int shm_detach(void *addr);
int shm_destroy(int id);
-
-#ifndef SHMMAX
-#define SHMMAX 65535
-#endif
+size_t shm_get_shmmax(void);
void mood_check_callback(int fd, __a_unused const struct osl_object *query)
{
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
#include "afh.h"
#include "string.h"
-/** \cond some defines and structs which are only used in this file */
-
/*
* MIN_CONSEC_GOOD_FRAMES defines how many consecutive valid MP3 frames we need
* to see before we decide we are looking at a real MP3 file
unsigned int emphasis;
};
-/** \endcond */
static const int frequencies[3][4] = {
{22050,24000,16000,50000}, /* MPEG 2.0 */
{44100,48000,32000,50000}, /* MPEG 1.0 */
/**
* Get the maximum transport-layer message size (MMS_S).
*
- * The socket must be connected. See RFC 1122, 3.3.3.
+ * \param sockfd The socket file descriptor.
*
- * \return If the protocol familiy could not be determined, \p AF_INET is
- * assumed.
+ * The socket must be connected. See RFC 1122, 3.3.3. If the protocol familiy
+ * could not be determined, \p AF_INET is assumed.
+ *
+ * \return The maximum message size of the address family type.
*/
int generic_max_transport_msg_size(int sockfd)
{
return 0;
if (packet_num == 0) {
ogg_stream_init(&vghd->os, serial);
- ret = -E_OGG_PACKET_IN;
ret = ogg_stream_packetin(&vghd->os, packet);
if (ret < 0)
goto out;
pod->converted = 0;
fn->min_iqs = 0;
pod->vf = vf;
+ pod->have_more = true;
}
return ret;
}
SAMPLE_FORMAT(SF_U16_LE, "16 bit unsigned, little endian"), \
SAMPLE_FORMAT(SF_U16_BE, "16 bit unsigned, big endian"), \
-/** \cond */
+/** \cond sample_format */
#define SAMPLE_FORMAT(a, b) a
enum sample_format {SAMPLE_FORMATS};
#undef SAMPLE_FORMAT
#define SAMPLE_FORMAT(a, b) b
-/** \endcond */
+/** \endcond sample_format */
/** Debug loglevel, gets really noisy. */
#define LL_DEBUG 0
/** Log messages with lower priority than that will not be compiled in. */
#define COMPILE_TIME_LOGLEVEL 0
-/** \cond */
+/** \cond log */
#if LL_DEBUG >= COMPILE_TIME_LOGLEVEL
#define PARA_DEBUG_LOG(f,...) para_log(LL_DEBUG, "%s: " f, __FUNCTION__, ## __VA_ARGS__)
#else
#else
#define PARA_EMERG_LOG(...)
#endif
-/** \endcond */
+/** \endcond log */
void playlist_check_callback(int fd, __a_unused const struct osl_object *query)
{
struct para_buffer pb = {
- .max_size = SHMMAX,
+ .max_size = shm_get_shmmax(),
.private_data = &fd,
.max_size_handler = pass_buffer_as_shm
};
void print_receiver_helps(int detailed);
int generic_recv_pre_select(struct sched *s, struct task *t);
-/** \cond */
+/** \cond receiver */
extern void http_recv_init(struct receiver *r);
#define HTTP_RECEIVER {.name = "http", .init = http_recv_init},
extern void dccp_recv_init(struct receiver *r);
#define UDP_RECEIVER {.name = "udp", .init = udp_recv_init},
extern struct receiver receivers[];
-/** \endcond */
+/** \endcond receiver */
* \param barrier Absolute time before select() should return.
* \param s Pointer to the scheduler struct.
*
- * If \a barrier is in the past, this function requests a minimal timeout and
- * returns zero. Otherwise it returns one.
+ * \return If \a barrier is in the past, this function requests a minimal
+ * timeout and returns zero. Otherwise it returns one.
*
* \sa sched_min_delay(), sched_request_barrier().
*/
init_ipc_or_die(); /* init mmd struct and mmd->lock */
/* make sure, the global now pointer is uptodate */
gettimeofday(now, NULL);
- server_uptime(UPTIME_SET); /* reset server uptime */
+ set_server_start_time(now);
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
static void status_refresh(void)
{
static int prev_uptime = -1, prev_events = -1;
- int uptime = server_uptime(UPTIME_GET), ret = 1;
+ int uptime = get_server_uptime(now);
if (prev_events != mmd->events)
goto out;
prev_uptime = uptime;
prev_events = mmd->events;
mmd->vss_status_flags = mmd->new_vss_status_flags;
- if (ret) {
- PARA_DEBUG_LOG("%d events, forcing status update\n",
- mmd->events);
- killpg(0, SIGUSR1);
- }
+ PARA_DEBUG_LOG("%d events, forcing status update\n", mmd->events);
+ killpg(0, SIGUSR1);
}
static int server_select(int max_fileno, fd_set *readfds, fd_set *writefds,
}
}
-/** \cond LLONG_MAX and LLONG_MIN might not be defined. */
+/** \cond llong_minmax */
+/* LLONG_MAX and LLONG_MIN might not be defined. */
#ifndef LLONG_MAX
#define LLONG_MAX 9223372036854775807LL
#endif
#ifndef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#endif
-/** \endcond */
+/** \endcond llong_minmax */
/**
* Convert a string to a 64-bit signed integer value.
*
* \param a First addend.
* \param b Second addend.
- * \param sum Contains the sum \a + \a b on return.
+ * \param sum Contains the sum \a a + \a b on return.
*/
void tv_add(const struct timeval *a, const struct timeval *b,
struct timeval *sum)
* \param stream_start When the first chunk was sent.
* \param result The time when to send chunk number \a chunk_num.
*
- * This function computes stream_start + chunk_num * chunk_time.
+ * This function computes \a stream_start + \a chunk_num * \a chunk_time.
*/
void compute_chunk_time(long unsigned chunk_num,
struct timeval *chunk_tv, struct timeval *stream_start,
uint16_t slice_bytes;
};
+/** A FEC client is always in one of these states. */
enum fec_client_state {
FEC_STATE_NONE = 0, /**< not initialized and not enabled */
FEC_STATE_DISABLED, /**< temporarily disabled */
* \param pattern_len The length of the pattern in bytes.
* \param buf The buffer to search for the pattern.
* \param buf_size The number of bytes in \a buf.
+ *
+ * \return A pointer into \a buf or \p NULL if the pattern was not found.
*/
const char *search_pattern(const char *pattern, int pattern_len,
const char *buf, int buf_size)
*coefs++ = 0.0;
continue;
}
- mult1 = mult;
n1 = pwd->exponent_high_sizes[bsize];
/* compute power of high bands */
exponents = pwd->exponents[ch] +
mult1 = sqrt(exp_power[j]
/ exp_power[last_high_band]);
/* XXX: use a table */
- mult1 = mult1 * pow(10,
- pwd->high_band_values[ch][j] * 0.05);
+ mult1 *= pow(10, pwd->high_band_values[ch][j] * 0.05);
mult1 /= (pwd->max_exponent[ch] * pwd->noise_mult);
mult1 *= mdct_norm;
for (i = 0; i < n; i++) {
for (ch = 0; ch < pwd->ahi.channels; ch++) {
int n4, idx;
- n = pwd->block_len;
n4 = pwd->block_len / 2;
if (pwd->channel_coded[ch])
imdct(pwd->mdct_ctx[bsize], pwd->output, pwd->coefs[ch]);