/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-2009 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
if (ut->fd < 0)
continue;
ret = write_all(ut->fd, buf, &written);
- if (ret < 0)
+ if (ret < 0) /* TODO: Use chunk queueing */
return udp_delete_target(ut, "send error");
if (written != len)
PARA_WARNING_LOG("short write %zu/%zu\n", written, len);
}
}
-static void udp_init_session(struct udp_target *ut)
+static int udp_init_session(struct udp_target *ut)
{
+ int ret;
+
+ if (ut->fd >= 0) /* nothing to do */
+ return 0;
PARA_NOTICE_LOG("sending to udp %s:%d\n", TARGET_ADDR(ut), ut->port);
- ut->fd = create_udp_send_socket(TARGET_ADDR(ut), ut->port, 10);
+ /* TODO: Make ttl configurable. */
+ ret = create_udp_send_socket(TARGET_ADDR(ut), ut->port, 10);
+ if (ret < 0)
+ return ret;
+ ut->fd = ret;
+ return mark_fd_nonblocking(ut->fd);
}
static void udp_shutdown_targets(void)
struct udp_target *ut, *tmp;
udp_write_packet_type(buf, UDP_EOF_PACKET);
+ udp_write_magic(buf);
list_for_each_entry_safe(ut, tmp, &targets, node) {
if (ut->fd < 0)
continue;
- PARA_INFO_LOG("sending eof to udp target %s:%d\n",
- TARGET_ADDR(ut), ut->port);
write(ut->fd, buf, UDP_AUDIO_HEADER_LEN);
+ close(ut->fd);
+ ut->fd = -1;
}
}
{
struct udp_target *ut, *tmp;
size_t sendbuf_len;
- int packet_type = UDP_DATA_PACKET;
+ uint8_t packet_type = UDP_DATA_PACKET;
+ int ret;
char *sendbuf;
struct timeval *chunk_tv;
uint8_t stream_type = header_len? UDP_HEADER_STREAM : UDP_PLAIN_STREAM;
if (list_empty(&targets))
return;
list_for_each_entry_safe(ut, tmp, &targets, node) {
- if (ut->fd < 0)
- udp_init_session(ut);
+ ret = udp_init_session(ut);
+ if (ret < 0)
+ udp_delete_target(ut, para_strerror(-ret));
}
if (!need_extra_header(current_chunk))
header_len = 0;