build_date = $(shell date)
system = $(shell uname -rs)
cc_version = $(shell $(CC) --version | head -n 1)
-codename = oriented abstraction
+codename = transient singularity
DEBUG_CPPFLAGS += -Wno-sign-compare -g -Wunused -Wundef -W
NEWS
====
--------------------------------------------
-0.?.? (to be announced) "sonic convolution"
--------------------------------------------
+------------------------------------------------
+0.?.? (to be announced) "transient singularity"
+------------------------------------------------
+
+---------------------------------------
+0.2.13 (2006-07-14) "sonic convolution"
+---------------------------------------
A bunch of new features and core changes.
handler/filter (requires libfaad).
- each writer has its own command line parser, just like
para_recv and para_filter.
- - new writer: osxplay (thanks to Gerd Becker)
- para_client and para_audioc use the error subsystem
- - writers are integrated in para_audiod
+ - writers are integrated in para_audiod (currently linux-only)
- para_client is integrated in para_audiod
- random/playlist selector: improved info strings
- new audiod commands: tasks, kill
}
static int chk_barrier(const char *bname, const struct timeval *now,
- const struct timeval *barrier, struct timeval *diff, int log)
+ const struct timeval *barrier, struct timeval *diff,
+ int print_log)
{
long ms;
if (tv_diff(now, barrier, diff) > 0)
return 1;
ms = tv2ms(diff);
- if (log && ms)
+ if (print_log && ms)
PARA_DEBUG_LOG("%s barrier: %lims left\n", bname, ms);
return -1;
}
{
int i;
struct timeval diff;
+ char *audio_format = stat_task->stat_item_values[SI_FORMAT];
- if (!stat_task->af_status || !stat_task->pcd)
+ if (!audio_format || !stat_task->pcd)
return 0;
- i = get_audio_format_num(stat_task->af_status);
+ i = get_audio_format_num(audio_format + strlen(
+ status_item_list[SI_FORMAT]) + 1);
if (i < 0)
return 0;
if (receiver_running(i))
case SI_STATUS:
stat_task->playing = strstr(line, "playing")? 1 : 0;
break;
- case SI_FORMAT:
- free(stat_task->af_status);
- stat_task->af_status = para_strdup(line + ilen + 1);
- break;
case SI_OFFSET:
stat_task->offset_seconds = atoi(line + ilen + 1);
break;
if (!sl->fc || !*sl->fc->out_loaded || sl->wng)
continue;
if (tv_diff(now, &initial_delay_barrier, &diff) > 0) {
- PARA_INFO_LOG("barrier: %lu:%lu, now: %lu, %lu\n",
- initial_delay_barrier.tv_sec,
- initial_delay_barrier.tv_usec,
- now->tv_sec, now->tv_usec);
open_writers(i);
s->timeout = min_delay;
continue;
static void status_post_select(__a_unused struct sched *s, struct task *t)
{
struct status_task *st = t->private_data;
+ unsigned bytes_left;
t->ret = 1;
- if (!st->pcd || !st->pcd->loaded
- || st->pcd->status != CL_RECEIVING)
+ if (!st->pcd || st->pcd->status != CL_RECEIVING)
return;
- st->pcd->loaded = for_each_line(st->pcd->buf, st->pcd->loaded,
+ bytes_left = for_each_line(st->pcd->buf, st->pcd->loaded,
&check_stat_line);
+ if (st->pcd->loaded != bytes_left) {
+ st->last_status_read = *now;
+ st->pcd->loaded = bytes_left;
+ } else {
+ struct timeval diff;
+ tv_diff(now, &st->last_status_read, &diff);
+ if (diff.tv_sec > 61)
+ close_stat_pipe();
+ }
}
static void init_status_task(struct status_task *st)
char *stat_item_values[NUM_STAT_ITEMS];
/** do not restart client command until this time */
struct timeval restart_barrier;
+ /** last time we received status data from para_server */
+ struct timeval last_status_read;
/** the offset value announced by para_server */
int offset_seconds;
/** the length of the current audio file as announced by para_server */
struct timeval sa_time_diff;
/** whether client time is ahead of server time */
int sa_time_diff_sign;
- /** the audio format announced in server status */
- char *af_status;
/** non-zero if \a af_status is "playing" */
int playing;
};
struct hostent *he;
struct sockaddr_in their_addr;
+ pcd->fd = -1;
ret = get_host_info(pcd->conf.hostname_arg, &he);
if (ret < 0)
- goto out;
+ goto err_out;
/* get new socket */
ret = get_socket();
if (ret < 0)
- goto out;
+ goto err_out;
pcd->fd = ret;
/* init their_addr */
init_sockaddr(&their_addr, pcd->conf.server_port_arg, he);
ret = para_connect(pcd->fd, &their_addr);
if (ret < 0)
- goto out;
+ goto err_out;
pcd->status = CL_CONNECTED;
ret = mark_fd_nonblock(pcd->fd);
if (ret < 0)
- goto out;
+ goto err_out;
pcd->task.pre_select = client_pre_select;
pcd->task.post_select = client_post_select;
pcd->task.private_data = pcd;
sprintf(pcd->task.status, "client");
register_task(&pcd->task);
- ret = 1;
-out:
+ return 1;
+err_out:
+ if (pcd->fd >= 0)
+ close(pcd->fd);
return ret;
}
ret = 1;
if (num == 1)
goto out;
- usleep(500000 * 100);
+ sleep(50);
+ if (getppid() == 1)
+ return -E_SERVER_CRASH;
}
out:
return ret;
int para_decrypt_challenge(char *key_file, long unsigned *challenge_nr,
unsigned char *inbuf, int rsa_inlen)
{
- unsigned char *rsa_out = OPENSSL_malloc(128);
+ unsigned char *rsa_out = OPENSSL_malloc(rsa_inlen + 1);
int ret = para_decrypt_buffer(key_file, rsa_out, inbuf, rsa_inlen);
- if (ret >= 0)
+ if (ret >= 0) {
+ rsa_out[ret] = '\0';
ret = sscanf((char *)rsa_out, "%lu", challenge_nr) == 1?
1 : -E_CHALLENGE;
+ }
OPENSSL_free(rsa_out);
return ret;
}
if (ret < 0) {
if (errno != EAGAIN || !retries++ > DCCP_RETRIES)
goto err_out;
- PARA_DEBUG_LOG("EAGAIN #%d@%d/%d\n", retries, written, len);
+ PARA_DEBUG_LOG("EAGAIN #%d@%zd/%zd\n", retries, written, len);
goto again;
}
retries = 0;
PARA_ERROR(BAD_USER, "you don't exist. Go away."), \
PARA_ERROR(LOCK, "lock error"), \
PARA_ERROR(SENDER_CMD, "command not supported by this sender"), \
+ PARA_ERROR(SERVER_CRASH, "para_server crashed -- can not live without it"), \
#define PLAYLIST_SELECTOR_ERRORS \
static unsigned scroll_position;
-static int external_cmd_died, curses_active;
-static pid_t external_cmd_pid;
+static int cmd_died, curses_active;
+static pid_t cmd_pid;
static int command_pipe = -1;
static int audiod_pipe = -1;
pid = para_reap_child();
if (pid <= 0)
return;
- if (pid == external_cmd_pid) {
- external_cmd_pid = 0;
- external_cmd_died = 1;
+ if (pid == cmd_pid) {
+ cmd_pid = 0;
+ cmd_died = 1;
}
goto reap_next_child;
}
*
* EXTERNAL_MODE: Check only signal pipe. Used when an external command
* is running. During that thime curses is disabled. Returns when
- * external_cmd_pid == 0.
+ * cmd_pid == 0.
*/
static int do_select(int mode)
{
if (cp_numread <= 0)
cbo = 0;
wrefresh(bot.win);
+ ret = wgetch(top.win);
+ if (ret != ERR && ret != KEY_RESIZE) {
+ if (command_pipe) {
+ close(command_pipe);
+ command_pipe = -1;
+ }
+ if (cmd_pid)
+ kill(cmd_pid, SIGTERM);
+ return -1;
+ }
break;
case GETCH_MODE:
ret = wgetch(top.win);
return ret;
break;
case EXTERNAL_MODE:
- if (external_cmd_died) {
- external_cmd_died = 0;
+ if (cmd_died) {
+ cmd_died = 0;
return 0;
}
}
static int client_cmd_cmdline(char *cmd)
{
- pid_t pid;
int ret, fds[3] = {0, 1, 0};
char *c = make_message(BINDIR "/para_client %s", cmd);
outputf(COLOR_COMMAND, "%s", c);
- print_in_bar(COLOR_MSG, "executing client command, hit q to abort\n");
- ret = para_exec_cmdline_pid(&pid, c, fds);
+ print_in_bar(COLOR_MSG, "executing client command, hit any key to abort\n");
+ ret = para_exec_cmdline_pid(&cmd_pid, c, fds);
free(c);
if (ret < 0)
return -1;
*/
static int display_cmd(char *cmd)
{
- pid_t pid;
int fds[3] = {0, 1, 0};
- print_in_bar(COLOR_MSG, "executing display command, hit q to abort");
+ print_in_bar(COLOR_MSG, "executing display command, hit any key to abort");
outputf(COLOR_COMMAND, "%s", cmd);
- if (para_exec_cmdline_pid(&pid, cmd, fds) < 0)
+ if (para_exec_cmdline_pid(&cmd_pid, cmd, fds) < 0)
return -1;
command_pipe = fds[1];
return send_output();
{
int fds[3] = {-1, -1, -1};
- if (external_cmd_pid)
+ if (cmd_pid)
return -1;
shutdown_curses();
- para_exec_cmdline_pid(&external_cmd_pid, cmd, fds);
+ para_exec_cmdline_pid(&cmd_pid, cmd, fds);
+ cmd_died = 0;
do_select(EXTERNAL_MODE);
init_curses();
return 0;
PARA_NOTICE_LOG("connecting to %s:%d\n", conf->host_arg,
conf->port_arg);
ret = para_connect(phd->fd, &their_addr);
- if (ret < 0)
+ if (ret < 0) {
+ close(phd->fd);
goto err_out;
+ }
mark_fd_nonblock(phd->fd);
phd->status = HTTP_CONNECTED;
return 1;
goto out;
ret = -E_MYSQL_SYNTAX;
if (!strcmp(ebn1, ebn2))
- goto out;
+ goto update_dir;
remove_entry(argv[2]); /* no need to escape, ignore error */
q = make_message("update data set name = '%s' where name = '%s'",
ebn2, ebn1);
free(q);
if (ret < 0)
goto out;
+update_dir:
ret = 1;
dn = para_dirname(argv[2]);
if (!dn)
/**
* paraslash's wrapper around the accept system call
*
- * @param fd the listening socket
- * @param addr structure which is filled in with the address of the peer socket
- * @param size should contain the size of the structure pointed to by \a addr
+ * \param fd the listening socket
+ * \param addr structure which is filled in with the address of the peer socket
+ * \param size should contain the size of the structure pointed to by \a addr
*
* \sa accept(2).
*/
{
int new_fd;
- new_fd = accept(fd, (struct sockaddr *) addr, &size);
- return new_fd == -1? -E_ACCEPT : new_fd;
+ do
+ new_fd = accept(fd, (struct sockaddr *) addr, &size);
+ while (new_fd < 0 && errno == EINTR);
+ return new_fd < 0? -E_ACCEPT : new_fd;
}
static int setserversockopts(int socket_fd)
client_conf="$dir/client.conf"
audioc_conf="$dir/audioc.conf"
server=www.paraslash.org
-proj=paraslash-0.2.12
+proj=paraslash-0.2.13
df=$proj.tar.bz2 # download file
url=http://$server/versions/$df
kf="$dir/key.anonymous" # key file
--- /dev/null
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.4 (GNU/Linux)
+
+iD8DBQBEt6wNWto1QDEAkw8RAlwOAJ9LyZP8oKHWLeKBujynpL7MJelegACdGW5l
+/93tWtJYKMp2GrRCx2UQh6o=
+=KLcm
+-----END PGP SIGNATURE-----
<h1>Events</h1>
<hr>
<ul>
+ <li>2007-07-14: <a href="versions/paraslash-0.2.13.tar.bz2">paraslash-0.2.13</a>
+ <a href="versions/paraslash-0.2.13.tar.bz2.asc">(sig)</a>
+ "sonic convolution"
+ </li>
<li>2006-05-12: <a href="versions/paraslash-0.2.12.tar.bz2">paraslash-0.2.12</a>
<a href="versions/paraslash-0.2.12.tar.bz2.asc">(sig)</a>
"oriented abstraction"