From 91baab1e9bbf957d139d64741db02be6490da45a Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sat, 28 Feb 2009 13:40:01 +0100 Subject: [PATCH] URL/UDPv6 support for the UDP sender. This adds support for URL strings to support IPv4/IPv6 addresses, hostnames, and optional port numbers to the UDP sender. The syntax is based on RFC 3986, example URL strings to be used with the 'add'/'delete' commands are: 10.10.1.2:8000 # host:port 10.10.1.2 # host with default port 8000 localhost # hostname (for IPv4 or IPv6 host) localhost:8001 # hostname with port [::1]:8000 # same, but different syntax [badc0de::1] # IPv6 host with default port 8000 The 'delete' command now also supports port-wildcarding, i.e. not specifying the port in the 'delete' command removes all targets whose host names match. The UDP sender has been tested to function with IPv6, including multicasting: * server: para_server --udp_target=[ff05::beef]:8000 --udp_mcast_iface=eth1 * client: para_audiod -F -D -r 'ogg:udp -i ff05::beef -I eth0' --- command.c | 11 ++----- ggo/server.m4 | 21 ++++++++----- server.h | 8 ++--- udp_send.c | 82 ++++++++++++++++++++++----------------------------- 4 files changed, 56 insertions(+), 66 deletions(-) diff --git a/command.c b/command.c index 988eae64..deb21a6f 100644 --- a/command.c +++ b/command.c @@ -204,16 +204,9 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman break; case SENDER_ADD: case SENDER_DELETE: - if (argc != 4 && argc != 5) - return -E_COMMAND_SYNTAX; - if (!inet_pton(AF_INET, argv[3], &scd->addr)) + if (argc != 4 || parse_url(argv[3], scd->host, + sizeof(scd->host), &scd->port) == NULL) return -E_COMMAND_SYNTAX; - scd->port = -1; - if (argc == 5) { - scd->port = atoi(argv[4]); - if (scd->port < 0 || scd->port > 65535) - return -E_COMMAND_SYNTAX; - } break; default: return -E_COMMAND_SYNTAX; diff --git a/ggo/server.m4 b/ggo/server.m4 index 8aa753b9..f2738d37 100644 --- a/ggo/server.m4 +++ b/ggo/server.m4 @@ -243,16 +243,23 @@ section "udp sender" option "udp_target" - #~~~~~~~~~~~~~~~~~~~~ -"add udp target" -string typestr="a.b.c.d:p" +"add udp target with optional port" +string typestr="host[:port]" optional multiple details=" - Add given host/port to the list of targets. This option - can be given multiple times. Example: '224.0.1.38:1500' - instructs the udp sender to send to udp port 1500 on host - 224.0.1.38 (unassigned ip in the Local Network Control Block - 224.0.0/24). This is useful for multicast streaming. + Add given host/port to the list of targets. The 'host' argument + can be either an IPv4/v6 address or hostname (RFC 3986 syntax). + The 'port' argument is an optional port number. If the 'port' + part is absent, the 'udp_default_port' value is used. + + The following examples are possible targets: + '10.10.1.2:8000' (host:port); '10.10.1.2' (with default port); + '224.0.1.38:1500' (IPv4 multicast); 'localhost:8001' (hostname + with port); '[::1]:8001' (IPv6 localhost); '[badc0de::1]' (IPv6 + host with default port); '[FF00::beef]:1500' (IPv6 multicast). + + This option can be given multiple times, for multiple targets. " option "udp_no_autostart" - diff --git a/server.h b/server.h index 8d1d6752..a0dfd2da 100644 --- a/server.h +++ b/server.h @@ -6,10 +6,12 @@ /** \file server.h Common server data structures. */ - /** Size of the selector_info and audio_file info strings of struct misc_meta_data. */ #define MMD_INFO_SIZE 16384 +/** The maximum length of the host component in an URL */ +#define MAX_HOSTLEN 256 + /** * Defines one command of para_server. */ @@ -35,9 +37,7 @@ struct sender_command_data{ /** The number of the sender in question. */ int sender_num; /** Used for the allow/deny/add/remove subcommands. */ - struct in_addr addr; - /** Used for the allow/deny/add/remove subcommands. */ - char host[256]; + char host[MAX_HOSTLEN]; /** Used for allow/deny. */ int netmask; /** The port number for add/remove. */ diff --git a/udp_send.c b/udp_send.c index 140458e7..ca4d8cf2 100644 --- a/udp_send.c +++ b/udp_send.c @@ -28,15 +28,12 @@ #include "close_on_fork.h" #include "chunk_queue.h" -/** Convert in_addr to ascii. */ -#define TARGET_ADDR(oc) inet_ntoa((oc)->addr) - /** Describes one entry in the list of targets for the udp sender. */ struct udp_target { - /** Address info. */ - struct in_addr addr; /** The position of this target in the list of targets. */ struct list_head node; + /** The hostname (DNS name or IPv4/v6 address string). */ + char host[MAX_HOSTLEN]; /** The UDP port. */ int port; /** The socket fd. */ @@ -61,7 +58,7 @@ static void udp_close_target(struct udp_target *ut) static void udp_delete_target(struct udp_target *ut, const char *msg) { - PARA_NOTICE_LOG("deleting %s:%d (%s) from list\n", TARGET_ADDR(ut), + PARA_NOTICE_LOG("deleting %s#%d (%s) from list\n", ut->host, ut->port, msg); udp_close_target(ut); list_del(&ut->node); @@ -155,7 +152,7 @@ static int udp_init_session(struct udp_target *ut) if (ut->fd >= 0) /* nothing to do */ return 0; - ret = makesock(AF_UNSPEC, IPPROTO_UDP, 0, TARGET_ADDR(ut), ut->port); + ret = makesock(AF_UNSPEC, IPPROTO_UDP, 0, ut->host, ut->port); if (ret < 0) return ret; ut->fd = ret; @@ -176,7 +173,7 @@ static int udp_init_session(struct udp_target *ut) } add_close_on_fork_list(ut->fd); ut->cq = cq_new(UDP_CQ_BYTES); - PARA_NOTICE_LOG("sending to udp %s:%d\n", TARGET_ADDR(ut), ut->port); + PARA_NOTICE_LOG("sending to udp %s#%d\n", ut->host, ut->port); return 1; } @@ -306,33 +303,34 @@ static int udp_com_off(__a_unused struct sender_command_data *scd) static int udp_com_delete(struct sender_command_data *scd) { - char *a = para_strdup(inet_ntoa(scd->addr)); struct udp_target *ut, *tmp; + list_for_each_entry_safe(ut, tmp, &targets, node) { - if (scd->port != ut->port) + /* Unspecified port means wildcard port match */ + if (scd->port > 0 && scd->port != ut->port) continue; - if (strcmp(TARGET_ADDR(ut), a)) + if (strcmp(ut->host, scd->host)) continue; udp_delete_target(ut, "com_delete"); } return 1; } -static void udp_add_target(int port, struct in_addr *addr) +static void udp_add_target(const char *host, int port) { struct udp_target *ut = para_calloc(sizeof(struct udp_target)); - ut->port = port; - ut->addr = *addr; + + strncpy(ut->host, host, sizeof(ut->host)); + ut->port = port > 0 ? port : conf.udp_default_port_arg; ut->fd = -1; /* not yet connected */ - PARA_INFO_LOG("adding to target list (%s:%d)\n", - TARGET_ADDR(ut), ut->port); + PARA_INFO_LOG("adding to target list (%s#%d)\n", + ut->host, ut->port); para_list_add(&ut->node, &targets); } static int udp_com_add(struct sender_command_data *scd) { - int port = (scd->port > 0)? scd->port : conf.udp_default_port_arg; - udp_add_target(port, &scd->addr); + udp_add_target(scd->host, scd->port); return 1; } @@ -342,8 +340,10 @@ static char *udp_info(void) char *ret, *tgts = NULL; list_for_each_entry(ut, &targets, node) { - char *tmp = make_message("%s%s:%d ", tgts? tgts : "", - TARGET_ADDR(ut), ut->port); + bool is_v6 = strchr(ut->host, ':') != NULL; + char *tmp = make_message("%s%s%s%s:%d ", tgts ? : "", + is_v6 ? "[" : "", ut->host, + is_v6 ? "]" : "", ut->port); free(tgts); tgts = tmp; } @@ -362,40 +362,30 @@ static char *udp_info(void) static void udp_init_target_list(void) { - int i; + char host[MAX_HOSTLEN]; + int port, i; INIT_LIST_HEAD(&targets); - for (i = 0; i < conf.udp_target_given; i++) { - char *arg = para_strdup(conf.udp_target_arg[i]); - char *p = strchr(arg, ':'); - int port; - struct in_addr addr; - - if (!p) - goto err; - *p = '\0'; - if (!inet_pton(AF_INET, arg, &addr)) - goto err; - port = atoi(++p); - if (port < 0 || port > 65535) - port = conf.udp_default_port_arg; - udp_add_target(port, &addr); - goto success; -err: - PARA_CRIT_LOG("syntax error for udp target option " - "#%d, ignoring\n", i); -success: - free(arg); - continue; - } + for (i = 0; i < conf.udp_target_given; i++) + if (parse_url(conf.udp_target_arg[i], host, + sizeof(host), &port) == NULL) + PARA_CRIT_LOG("syntax error for udp target option " + "#%d, ignoring\n", i); + else + udp_add_target(host, port); } static char *udp_help(void) { return make_message( "usage: {on|off}\n" - "usage: {add|delete} IP port\n" - "example: add 224.0.1.38 8000 (multicast streaming)\n" + "usage: {add|delete} host[:port]\n" + "examples: add 224.0.1.38:1500 (IPv4 multicast)\n" + " add 10.10.1.42 (using default port)\n" + " add [FF05::42]:1500 (IPv6 multicast)\n" + " add [::1] (IPv6 localhost/default port)\n" + " delete myhost.net (host with port wildcard)\n" + " delete [badc0de::1] (IPv6 with port wildcard)\n" ); } -- 2.39.2