📄 net_udp.c
字号:
/* * FILE: net_udp.c * AUTHOR: Colin Perkins * MODIFIED: Orion Hodson & Piers O'Hanlon * * Copyright (c) 1998-2000 University College London * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Science * Department at University College London * 4. Neither the name of the University nor of the Department may be used * to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* If this machine supports IPv6 the symbol HAVE_IPv6 should *//* be defined in either config_unix.h or config_win32.h. The *//* appropriate system header files should also be included *//* by those files. */#include "config_unix.h"#include "config_win32.h"#include "debug.h"#include "memory.h"#include "inet_pton.h"#include "inet_ntop.h"#include "vsnprintf.h"#include "net_udp.h"#ifdef NEED_ADDRINFO_H#include "addrinfo.h"#endif#define IPv4 4#define IPv6 6#ifdef WIN2K_IPV6const struct in6_addr in6addr_any = {IN6ADDR_ANY_INIT};#endif/* This is pretty nasty but it's the simplest way to get round *//* the Detexis bug that means their MUSICA IPv6 stack uses *//* IPPROTO_IP instead of IPPROTO_IPV6 in setsockopt calls *//* We also need to define in6addr_any */#ifdef MUSICA_IPV6#define IPPROTO_IPV6 IPPROTO_IPstruct in6_addr in6addr_any = {IN6ADDR_ANY_INIT};/* These DEF's are required as MUSICA's winsock6.h causes a clash with some of the * standard ws2tcpip.h definitions (eg struct in_addr6). * Note: winsock6.h defines AF_INET6 as 24 NOT 23 as in winsock2.h - I have left it * set to the MUSICA value as this is used in some of their function calls. *///#define AF_INET6 23#define IP_MULTICAST_LOOP 11 /*set/get IP multicast loopback */#define IP_MULTICAST_IF 9 /* set/get IP multicast i/f */#define IP_MULTICAST_TTL 10 /* set/get IP multicast ttl */#define IP_MULTICAST_LOOP 11 /*set/get IP multicast loopback */#define IP_ADD_MEMBERSHIP 12 /* add an IP group membership */#define IP_DROP_MEMBERSHIP 13/* drop an IP group membership */#define IN6_IS_ADDR_UNSPECIFIED(a) (((a)->s6_addr32[0] == 0) && \ ((a)->s6_addr32[1] == 0) && \ ((a)->s6_addr32[2] == 0) && \ ((a)->s6_addr32[3] == 0))struct ip_mreq { struct in_addr imr_multiaddr; /* IP multicast address of group */ struct in_addr imr_interface; /* local IP address of interface */};#endif#ifndef INADDR_NONE#define INADDR_NONE 0xffffffff#endifstruct _socket_udp { int mode; /* IPv4 or IPv6 */ char *addr; uint16_t rx_port; uint16_t tx_port; ttl_t ttl; fd_t fd; struct in_addr addr4;#ifdef HAVE_IPv6 struct in6_addr addr6;#endif /* HAVE_IPv6 */};#ifdef WIN32/* Want to use both Winsock 1 and 2 socket options, but since* IPv6 support requires Winsock 2 we have to add own backwards* compatibility for Winsock 1.*/#define SETSOCKOPT winsock_versions_setsockopt#else#define SETSOCKOPT setsockopt#endif /* WIN32 *//*****************************************************************************//* Support functions... *//*****************************************************************************/static voidsocket_error(const char *msg, ...){ char buffer[255]; uint32_t blen = sizeof(buffer) / sizeof(buffer[0]); va_list ap;#ifdef WIN32#define WSERR(x) {#x,x} struct wse { char errname[20]; int my_errno; }; struct wse ws_errs[] = { WSERR(WSANOTINITIALISED), WSERR(WSAENETDOWN), WSERR(WSAEACCES), WSERR(WSAEINVAL), WSERR(WSAEINTR), WSERR(WSAEINPROGRESS), WSERR(WSAEFAULT), WSERR(WSAENETRESET), WSERR(WSAENOBUFS), WSERR(WSAENOTCONN), WSERR(WSAENOTSOCK), WSERR(WSAEOPNOTSUPP), WSERR(WSAESHUTDOWN), WSERR(WSAEWOULDBLOCK), WSERR(WSAEMSGSIZE), WSERR(WSAEHOSTUNREACH), WSERR(WSAECONNABORTED), WSERR(WSAECONNRESET), WSERR(WSAEADDRNOTAVAIL), WSERR(WSAEAFNOSUPPORT), WSERR(WSAEDESTADDRREQ), WSERR(WSAENETUNREACH), WSERR(WSAETIMEDOUT), WSERR(0) }; int i, e = WSAGetLastError(); i = 0; while(ws_errs[i].my_errno && ws_errs[i].my_errno != e) { i++; } va_start(ap, msg); _vsnprintf(buffer, blen, msg, ap); va_end(ap); printf("ERROR: %s, (%d - %s)\n", msg, e, ws_errs[i].errname);#else uint32_t retlen; va_start(ap, msg); retlen = vsnprintf(buffer, blen, msg, ap); va_end(ap); blen -= retlen; snprintf(buffer + retlen, blen, ":%s", strerror(errno)); rtp_message(LOG_ALERT, buffer);#endif}#ifdef WIN32/* ws2tcpip.h defines these constants with different values from* winsock.h so files that use winsock 2 values but try to use * winsock 1 fail. So what was the motivation in changing the* constants ?*/#define WS1_IP_MULTICAST_IF 2 /* set/get IP multicast interface */#define WS1_IP_MULTICAST_TTL 3 /* set/get IP multicast timetolive */#define WS1_IP_MULTICAST_LOOP 4 /* set/get IP multicast loopback */#define WS1_IP_ADD_MEMBERSHIP 5 /* add an IP group membership */#define WS1_IP_DROP_MEMBERSHIP 6 /* drop an IP group membership *//* winsock_versions_setsockopt tries 1 winsock version of option * optname and then winsock 2 version if that failed.*/static intwinsock_versions_setsockopt(SOCKET s, int level, int optname, const char FAR * optval, int optlen){ int success = -1; switch (optname) { case IP_MULTICAST_IF: success = setsockopt(s, level, WS1_IP_MULTICAST_IF, optval, optlen); break; case IP_MULTICAST_TTL: success = setsockopt(s, level, WS1_IP_MULTICAST_TTL, optval, optlen); break; case IP_MULTICAST_LOOP: success = setsockopt(s, level, WS1_IP_MULTICAST_LOOP, optval, optlen); break; case IP_ADD_MEMBERSHIP: success = setsockopt(s, level, WS1_IP_ADD_MEMBERSHIP, optval, optlen); break; case IP_DROP_MEMBERSHIP: success = setsockopt(s, level, WS1_IP_DROP_MEMBERSHIP, optval, optlen); break; } if (success != -1) { return success; } return setsockopt(s, level, optname, optval, optlen);}#endif#ifdef NEED_INET_ATON#ifdef NEED_INET_ATON_STATICstatic #endifint inet_aton(const char *name, struct in_addr *addr){ addr->s_addr = inet_addr(name); return (addr->s_addr != (in_addr_t) INADDR_NONE);}#endif#ifdef NEED_IN6_IS_ADDR_MULTICAST#define IN6_IS_ADDR_MULTICAST(addr) ((addr)->s6_addr[0] == 0xffU)#endif#if defined(NEED_IN6_IS_ADDR_UNSPECIFIED) && defined(MUSICA_IPV6)#define IN6_IS_ADDR_UNSPECIFIED(addr) IS_UNSPEC_IN6_ADDR(*addr)#endif/*****************************************************************************//* IPv4 specific functions... *//*****************************************************************************/static int udp_addr_valid4(const char *dst){ struct in_addr addr4; struct hostent *h; if (inet_pton(AF_INET, dst, &addr4)) { return TRUE; } h = gethostbyname(dst); if (h != NULL) { return TRUE; } socket_error("Can't resolve IP address for %s", dst); return FALSE;}static socket_udp *udp_init4(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl){ int reuse = 1; struct sockaddr_in s_in; struct in_addr iface_addr;#ifdef WIN32 int recv_buf_size = 65536;#endif socket_udp *s = (socket_udp *)malloc(sizeof(socket_udp)); s->mode = IPv4; s->addr = NULL; s->rx_port = rx_port; s->tx_port = tx_port; s->ttl = ttl; if (inet_pton(AF_INET, addr, &s->addr4) != 1) { struct hostent *h = gethostbyname(addr); if (h == NULL) { socket_error("Can't resolve IP address for %s", addr); free(s); return NULL; } memcpy(&(s->addr4), h->h_addr_list[0], sizeof(s->addr4)); } if (iface != NULL) { if (inet_pton(AF_INET, iface, &iface_addr) != 1) { rtp_message(LOG_ERR, "Illegal interface specification"); free(s); return NULL; } } else { iface_addr.s_addr = 0; } s->fd = socket(AF_INET, SOCK_DGRAM, 0); if (s->fd < 0) { socket_error("socket"); return NULL; }#ifdef WIN32 if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_RCVBUF, (char *)&recv_buf_size, sizeof(int)) != 0) { socket_error("setsockopt SO_RCVBUF"); return NULL; }#endif if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse, sizeof(reuse)) != 0) { socket_error("setsockopt SO_REUSEADDR"); return NULL; }#ifdef SO_REUSEPORT if (SETSOCKOPT(s->fd, SOL_SOCKET, SO_REUSEPORT, (char *) &reuse, sizeof(reuse)) != 0) { socket_error("setsockopt SO_REUSEPORT"); return NULL; }#endif s_in.sin_family = AF_INET; s_in.sin_addr.s_addr = INADDR_ANY; s_in.sin_port = htons(rx_port); if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) { socket_error("bind: port %d", rx_port); return NULL; } if (IN_MULTICAST(ntohl(s->addr4.s_addr))) { char loop = 1; struct ip_mreq imr; imr.imr_multiaddr.s_addr = s->addr4.s_addr; imr.imr_interface.s_addr = iface_addr.s_addr; if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) { socket_error("setsockopt IP_ADD_MEMBERSHIP"); return NULL; }#ifndef WIN32 if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) != 0) { socket_error("setsockopt IP_MULTICAST_LOOP"); return NULL; }#endif if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &s->ttl, sizeof(s->ttl)) != 0) { socket_error("setsockopt IP_MULTICAST_TTL"); return NULL; } if (iface_addr.s_addr != 0) { if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_MULTICAST_IF, (char *) &iface_addr, sizeof(iface_addr)) != 0) { socket_error("setsockopt IP_MULTICAST_IF"); return NULL; } } } s->addr = strdup(addr); return s;}static void udp_exit4(socket_udp *s){ if (IN_MULTICAST(ntohl(s->addr4.s_addr))) { struct ip_mreq imr; imr.imr_multiaddr.s_addr = s->addr4.s_addr; imr.imr_interface.s_addr = INADDR_ANY; if (SETSOCKOPT(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ip_mreq)) != 0) { socket_error("setsockopt IP_DROP_MEMBERSHIP"); abort(); } rtp_message(LOG_INFO, "Dropped membership of multicast group"); } close(s->fd); free(s->addr); free(s);}static int udp_send4(socket_udp *s, uint8_t *buffer, int buflen){ struct sockaddr_in s_in; ASSERT(s != NULL); ASSERT(s->mode == IPv4); ASSERT(buffer != NULL); ASSERT(buflen > 0); s_in.sin_family = AF_INET; s_in.sin_addr.s_addr = s->addr4.s_addr; s_in.sin_port = htons(s->tx_port); return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));}#ifndef _WIN32static int udp_send_iov4(socket_udp *s, struct iovec *iov, int count){ struct sockaddr_in s_in; struct msghdr msg; ASSERT(s != NULL); ASSERT(s->mode == IPv4); ASSERT(iov != NULL); ASSERT(count > 0); s_in.sin_family = AF_INET; s_in.sin_addr.s_addr = s->addr4.s_addr; s_in.sin_port = htons(s->tx_port); memset(&msg, 0, sizeof(msg)); msg.msg_name = (void *)&s_in; msg.msg_namelen = sizeof(s_in); msg.msg_iov = iov; msg.msg_iovlen = count; return sendmsg(s->fd, &msg, 0);}#endifstatic char *udp_host_addr4(void){ char hname[MAXHOSTNAMELEN]; struct hostent *hent; struct in_addr iaddr; if (gethostname(hname, MAXHOSTNAMELEN) != 0) { rtp_message(LOG_ERR, "Cannot get hostname!"); abort(); } hent = gethostbyname(hname); if (hent == NULL) { socket_error("Can't resolve IP address for %s", hname); return NULL; } ASSERT(hent->h_addrtype == AF_INET); memcpy(&iaddr.s_addr, hent->h_addr, sizeof(iaddr.s_addr)); strncpy(hname, inet_ntoa(iaddr), MAXHOSTNAMELEN); return xstrdup(hname);}/*****************************************************************************//* IPv6 specific functions... *//*****************************************************************************/static int udp_addr_valid6(const char *dst){#ifdef HAVE_IPv6 struct in6_addr addr6; switch (inet_pton(AF_INET6, dst, &addr6)) { case 1: return TRUE; break; case 0: return FALSE; break; case -1: rtp_message(LOG_ERR, "inet_pton failed"); errno = 0; }#endif /* HAVE_IPv6 */ UNUSED(dst); return FALSE;}static socket_udp *udp_init6(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl){#ifdef HAVE_IPv6 int reuse = 1; struct sockaddr_in6 s_in; socket_udp *s = (socket_udp *) malloc(sizeof(socket_udp)); s->mode = IPv6; s->addr = NULL; s->rx_port = rx_port; s->tx_port = tx_port; s->ttl = ttl; if (iface != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -