udp_connection_t * udp_bind ( int subsystem, const char *name, const char *bindaddr, int port, const char *multicast_src, const char *ifname, int rxsize, int txsize ) { int fd, ifindex, reuse = 1; udp_connection_t *uc; char buf[256]; socklen_t addrlen; uc = calloc(1, sizeof(udp_connection_t)); uc->fd = -1; uc->host = bindaddr ? strdup(bindaddr) : NULL; uc->port = port; uc->ifname = ifname ? strdup(ifname) : NULL; uc->subsystem = subsystem; uc->name = name ? strdup(name) : NULL; uc->rxtxsize = rxsize; if (udp_resolve(uc, &uc->ip, uc->host, port, &uc->multicast, 1)) { udp_close(uc); return UDP_FATAL_ERROR; } /* Open socket */ if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) { tvherror(subsystem, "%s - failed to create socket [%s]", name, strerror(errno)); udp_close(uc); return UDP_FATAL_ERROR; } uc->fd = fd; /* Mark reuse address */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))) { tvherror(subsystem, "%s - failed to reuse address for socket [%s]", name, strerror(errno)); udp_close(uc); return UDP_FATAL_ERROR; } /* Bind to interface */ ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0; if (ifindex < 0) { tvherror(subsystem, "%s - could not find interface %s", name, ifname); goto error; } /* IPv4 */ if (uc->ip.ss_family == AF_INET) { /* Bind */ if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in))) { inet_ntop(AF_INET, &IP_AS_V4(uc->ip, addr), buf, sizeof(buf)); tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]", name, buf, ntohs(IP_AS_V4(uc->ip, port)), strerror(errno)); goto error; } if (uc->multicast) { /* Join multicast group */ if (multicast_src && *multicast_src) { /* Join with specific source address (SSM) */ struct ip_mreq_source ms; memset(&ms, 0, sizeof(ms)); ms.imr_multiaddr = IP_AS_V4(uc->ip, addr); /* Note, ip_mreq_source does not support the ifindex parameter, so we have to resolve to the ip of the interface on all platforms. */ if (udp_get_ifaddr(fd, ifname, &ms.imr_interface) == -1) { tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]", name, ifname, strerror(errno)); goto error; } if (inet_pton(AF_INET, multicast_src, &ms.imr_sourceaddr) < 1) { tvherror(subsystem, "%s - invalid ipv4 address '%s' specified as multicast source [e=%s]", name, multicast_src, strerror(errno)); goto error; } if (setsockopt(fd, udp_get_solip(), IP_ADD_SOURCE_MEMBERSHIP, &ms, sizeof(ms)) < 0) { tvherror(subsystem, "%s - setsockopt IP_ADD_SOURCE_MEMBERSHIP failed [e=%s]", name, strerror(errno)); goto error; } } else { /* Standard multicast join (non-SSM) */ #if defined(PLATFORM_DARWIN) struct ip_mreq m; #else struct ip_mreqn m; #endif memset(&m, 0, sizeof(m)); m.imr_multiaddr = IP_AS_V4(uc->ip, addr); #if !defined(PLATFORM_DARWIN) m.imr_address.s_addr = 0; m.imr_ifindex = ifindex; #else if (udp_get_ifaddr(fd, ifname, &m.imr_interface) == -1) { tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]", name, ifname, strerror(errno)); goto error; } #endif if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) { inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf)); tvhwarn(subsystem, "%s - cannot join %s [%s]", name, buf, strerror(errno)); } } } /* Bind to IPv6 group */ } else { struct ipv6_mreq m; memset(&m, 0, sizeof(m)); /* Bind */ if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6))) { inet_ntop(AF_INET6, &IP_AS_V6(uc->ip, addr), buf, sizeof(buf)); tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]", name, buf, ntohs(IP_AS_V6(uc->ip, port)), strerror(errno)); goto error; } if (uc->multicast) { /* Join group */ m.ipv6mr_multiaddr = IP_AS_V6(uc->ip, addr); m.ipv6mr_interface = ifindex; #ifdef SOL_IPV6 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m, sizeof(m))) { inet_ntop(AF_INET, &m.ipv6mr_multiaddr, buf, sizeof(buf)); tvhwarn(subsystem, "%s - cannot join %s [%s]", name, buf, strerror(errno)); } #else tvherror(subsystem, "IPv6 multicast not supported"); goto error; #endif } } addrlen = sizeof(uc->ip); if (getsockname(fd, (struct sockaddr *)&uc->ip, &addrlen)) { tvherror(subsystem, "%s - cannot obtain socket name [%s]", name, strerror(errno)); goto error; } /* Increase/Decrease RX buffer size */ if (rxsize > 0 && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize)) == -1) tvhwarn(subsystem, "%s - cannot change UDP rx buffer size [%s]", name, strerror(errno)); /* Increase/Decrease TX buffer size */ if (txsize > 0 && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &txsize, sizeof(txsize)) == -1) tvhwarn(subsystem, "%s - cannot change UDP tx buffer size [%s]", name, strerror(errno)); return uc; error: udp_close(uc); return NULL; }
udp_connection_t * udp_sendinit ( int subsystem, const char *name, const char *ifname, int txsize ) { int fd, ifindex; udp_connection_t *uc; uc = calloc(1, sizeof(udp_connection_t)); uc->fd = -1; uc->ifname = ifname ? strdup(ifname) : NULL; uc->subsystem = subsystem; uc->name = name ? strdup(name) : NULL; uc->rxtxsize = txsize; /* Open socket */ if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) { tvherror(subsystem, "%s - failed to create socket [%s]", name, strerror(errno)); udp_close(uc); return UDP_FATAL_ERROR; } uc->fd = fd; /* Bind to interface */ ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0; if (ifindex < 0) { tvherror(subsystem, "%s - could not find interface %s", name, ifname); goto error; } if (uc->multicast) { if (uc->ip.ss_family == AF_INET) { #if !defined(PLATFORM_DARWIN) struct ip_mreqn m; memset(&m, 0, sizeof(m)); m.imr_ifindex = ifindex; #else struct in_addr m; if (udp_get_ifaddr(fd, ifname, &m) == -1) { tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]", name, ifname, strerror(errno)); goto error; } #endif if (setsockopt(fd, udp_get_solip(), IP_MULTICAST_IF, &m, sizeof(m))) tvhwarn(subsystem, "%s - cannot set source interface %s [%s]", name, ifname, strerror(errno)); } else { struct ipv6_mreq m; memset(&m, 0, sizeof(m)); m.ipv6mr_interface = ifindex; #ifdef SOL_IPV6 if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &m, sizeof(m))) { tvhwarn(subsystem, "%s - cannot set source interface %s [%s]", name, ifname, strerror(errno)); } #else tvherror(subsystem, "IPv6 multicast not supported"); goto error; #endif } } /* Increase TX buffer size */ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &txsize, sizeof(txsize)) == -1) tvhwarn(subsystem, "%s - cannot increase UDP tx buffer size [%s]", name, strerror(errno)); return uc; error: udp_close(uc); return NULL; }
udp_connection_t * udp_bind ( const char *subsystem, const char *name, const char *bindaddr, int port, const char *ifname, int rxsize ) { int fd, ifindex, reuse = 1; udp_connection_t *uc; char buf[256]; socklen_t addrlen; uc = calloc(1, sizeof(udp_connection_t)); uc->fd = -1; uc->host = bindaddr ? strdup(bindaddr) : NULL; uc->port = port; uc->ifname = ifname ? strdup(ifname) : NULL; uc->subsystem = subsystem ? strdup(subsystem) : NULL; uc->name = name ? strdup(name) : NULL; uc->rxtxsize = rxsize; if (udp_resolve(uc, 1) < 0) { udp_close(uc); return UDP_FATAL_ERROR; } /* Open socket */ if ((fd = tvh_socket(uc->ip.ss_family, SOCK_DGRAM, 0)) == -1) { tvherror(subsystem, "%s - failed to create socket [%s]", name, strerror(errno)); udp_close(uc); return UDP_FATAL_ERROR; } /* Mark reuse address */ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); /* Bind to interface */ ifindex = udp_ifindex_required(uc) ? udp_get_ifindex(ifname) : 0; if (ifindex < 0) { tvherror(subsystem, "%s - could not find interface %s", name, ifname); goto error; } /* IPv4 */ if (uc->ip.ss_family == AF_INET) { #if defined(PLATFORM_DARWIN) struct ip_mreq m; #else struct ip_mreqn m; #endif memset(&m, 0, sizeof(m)); /* Bind */ if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in)) == -1) { inet_ntop(AF_INET, &IP_AS_V4(uc->ip, addr), buf, sizeof(buf)); tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]", name, buf, ntohs(IP_AS_V4(uc->ip, port)), strerror(errno)); goto error; } if (uc->multicast) { /* Join group */ m.imr_multiaddr = IP_AS_V4(uc->ip, addr); #if !defined(PLATFORM_DARWIN) m.imr_address.s_addr = 0; m.imr_ifindex = ifindex; #else if (udp_get_ifaddr(fd, ifname, &m.imr_interface) == -1) { tvherror(subsystem, "%s - cannot find ip address for interface %s [e=%s]", name, ifname, strerror(errno)); goto error; } #endif if (setsockopt(fd, udp_get_solip(), IP_ADD_MEMBERSHIP, &m, sizeof(m))) { inet_ntop(AF_INET, &m.imr_multiaddr, buf, sizeof(buf)); tvhwarn(subsystem, "%s - cannot join %s [%s]", name, buf, strerror(errno)); } } /* Bind to IPv6 group */ } else { struct ipv6_mreq m; memset(&m, 0, sizeof(m)); /* Bind */ if (bind(fd, (struct sockaddr *)&uc->ip, sizeof(struct sockaddr_in6)) == -1) { inet_ntop(AF_INET6, &IP_AS_V6(uc->ip, addr), buf, sizeof(buf)); tvherror(subsystem, "%s - cannot bind %s:%hu [e=%s]", name, buf, ntohs(IP_AS_V6(uc->ip, port)), strerror(errno)); goto error; } if (uc->multicast) { /* Join group */ m.ipv6mr_multiaddr = IP_AS_V6(uc->ip, addr); m.ipv6mr_interface = ifindex; #ifdef SOL_IPV6 if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &m, sizeof(m))) { inet_ntop(AF_INET, &m.ipv6mr_multiaddr, buf, sizeof(buf)); tvhwarn(subsystem, "%s - cannot join %s [%s]", name, buf, strerror(errno)); } #else tvherror(subsystem, "IPv6 multicast not supported"); goto error; #endif } } addrlen = sizeof(uc->ip); getsockname(fd, (struct sockaddr *)&uc->ip, &addrlen); /* Increase RX buffer size */ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rxsize, sizeof(rxsize)) == -1) tvhwarn(subsystem, "%s - cannot increase UDP rx buffer size [%s]", name, strerror(errno)); uc->fd = fd; return uc; error: udp_close(uc); return NULL; }