udp_recv: Close receiver after 5 seconds of inactivitly.
authorAndre Noll <maan@systemlinux.org>
Sun, 21 Mar 2010 13:13:18 +0000 (14:13 +0100)
committerAndre Noll <maan@systemlinux.org>
Sun, 21 Mar 2010 13:13:18 +0000 (14:13 +0100)
There is no way  for the UDP receiver to tell that para_server won't send any more
data, e.g. because the UDP target has been deleted. Currently,  in this case the UDP
receiver listens on its socket indefinitely and the buffer tree stays active as well. This
can be fatal if para_server starts sending data for another audio format much later.

So close the UDP socket if no data has been received for 5 seconds.

error.h
udp_recv.c

diff --git a/error.h b/error.h
index 731387c..2cca4c2 100644 (file)
--- a/error.h
+++ b/error.h
@@ -234,6 +234,7 @@ extern const char **para_errlist[];
 #define UDP_RECV_ERRORS \
        PARA_ERROR(UDP_SYNTAX, "udp_recv syntax error"), \
        PARA_ERROR(UDP_OVERRUN, "output buffer overrun"), \
+       PARA_ERROR(UDP_TIMEOUT, "timeout reading on UDP socket"), \
 
 
 #define HTTP_RECV_ERRORS \
index 8dc8edc..4f363cc 100644 (file)
@@ -32,6 +32,7 @@ struct private_udp_recv_data {
        /** The socket file descriptor. */
        int fd;
        struct btr_pool *btrp;
+       struct timeval last_read_time;
 };
 
 static void udp_recv_pre_select(struct sched *s, struct task *t)
@@ -77,8 +78,15 @@ static void udp_recv_post_select(__a_unused struct sched *s, struct task *t)
                goto err;
        if (ret == 0)
                return;
-       if (!FD_ISSET(purd->fd, &s->rfds))
+       if (!FD_ISSET(purd->fd, &s->rfds)) {
+               struct timeval tmp;
+               tv_add(&purd->last_read_time, &(struct timeval)EMBRACE(5, 0),
+                       &tmp);
+               ret = -E_UDP_TIMEOUT;
+               if (tv_diff(now, &tmp, NULL) > 0)
+                       goto err;
                return;
+       }
        iovcnt = btr_pool_get_buffers(purd->btrp, iov);
        ret = -E_UDP_OVERRUN;
        if (iovcnt == 0)
@@ -92,6 +100,7 @@ static void udp_recv_post_select(__a_unused struct sched *s, struct task *t)
        ret = udp_check_eof(packet_size, iov);
        if (ret < 0)
                goto err;
+       purd->last_read_time = *now;
        if (iov[0].iov_len >= packet_size)
                btr_add_output_pool(purd->btrp, packet_size, btrn);
        else { /* both buffers contain data */
@@ -220,6 +229,7 @@ static int udp_recv_open(struct receiver_node *rn)
        PARA_INFO_LOG("receiving from %s:%d, fd=%d\n", c->host_arg,
                c->port_arg, purd->fd);
        purd->btrp = btr_pool_new("udp_recv", 320 * 1024);
+       purd->last_read_time = *now;
        return purd->fd;
 err:
        free(rn->private_data);