📄 net_udp.c
字号:
debug_msg("Not yet implemented\n"); abort(); } if (inet_pton(AF_INET6, addr, &s->addr6) != 1) { /* We should probably try to do a DNS lookup on the name */ /* here, but I'm trying to get the basics going first... */ debug_msg("IPv6 address conversion failed\n"); free(s); return NULL; } s->fd = socket(AF_INET6, SOCK_DGRAM, 0); if (s->fd < 0) { socket_error("socket"); return NULL; } 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 memset((char *)&s_in, 0, sizeof(s_in)); s_in.sin6_family = AF_INET6; s_in.sin6_port = htons(rx_port);#ifdef HAVE_SIN6_LEN s_in.sin6_len = sizeof(s_in);#endif s_in.sin6_addr = in6addr_any; if (bind(s->fd, (struct sockaddr *) &s_in, sizeof(s_in)) != 0) { socket_error("bind"); return NULL; } if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) { unsigned int loop = 1; struct ipv6_mreq imr;#ifdef MUSICA_IPV6 imr.i6mr_interface = 1; imr.i6mr_multiaddr = s->addr6;#else imr.ipv6mr_multiaddr = s->addr6; imr.ipv6mr_interface = 0;#endif if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) { socket_error("setsockopt IPV6_ADD_MEMBERSHIP"); return NULL; } if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &loop, sizeof(loop)) != 0) { socket_error("setsockopt IPV6_MULTICAST_LOOP"); return NULL; } if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttl, sizeof(ttl)) != 0) { socket_error("setsockopt IPV6_MULTICAST_HOPS"); return NULL; } } ASSERT(s != NULL); s->addr = strdup(addr); return s;#else UNUSED(addr); UNUSED(iface); UNUSED(rx_port); UNUSED(tx_port); UNUSED(ttl); return NULL;#endif}static void udp_exit6(socket_udp *s){#ifdef HAVE_IPv6 if (IN6_IS_ADDR_MULTICAST(&(s->addr6))) { struct ipv6_mreq imr;#ifdef MUSICA_IPV6 imr.i6mr_interface = 1; imr.i6mr_multiaddr = s->addr6;#else imr.ipv6mr_multiaddr = s->addr6; imr.ipv6mr_interface = 0;#endif if (SETSOCKOPT(s->fd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, (char *) &imr, sizeof(struct ipv6_mreq)) != 0) { socket_error("setsockopt IPV6_DROP_MEMBERSHIP"); abort(); } } close(s->fd); free(s->addr); free(s);#else UNUSED(s);#endif /* HAVE_IPv6 */}static int udp_send6(socket_udp *s, uint8_t *buffer, int buflen){#ifdef HAVE_IPv6 struct sockaddr_in6 s_in; ASSERT(s != NULL); ASSERT(s->mode == IPv6); ASSERT(buffer != NULL); ASSERT(buflen > 0); memset((char *)&s_in, 0, sizeof(s_in)); s_in.sin6_family = AF_INET6; s_in.sin6_addr = s->addr6; s_in.sin6_port = htons(s->tx_port);#ifdef HAVE_SIN6_LEN s_in.sin6_len = sizeof(s_in);#endif return sendto(s->fd, buffer, buflen, 0, (struct sockaddr *) &s_in, sizeof(s_in));#else UNUSED(s); UNUSED(buffer); UNUSED(buflen); return -1;#endif}#ifndef _WIN32static int udp_send_iov6(socket_udp *s, struct iovec *iov, int count){#ifdef HAVE_IPv6 struct sockaddr_in6 s_in; struct msghdr msg; ASSERT(s != NULL); ASSERT(s->mode == IPv6); memset((char *)&s_in, 0, sizeof(s_in)); s_in.sin6_family = AF_INET6; s_in.sin6_addr = s->addr6; s_in.sin6_port = htons(s->tx_port);#ifdef HAVE_SIN6_LEN s_in.sin6_len = sizeof(s_in);#endif msg.msg_name = &s_in; msg.msg_namelen = sizeof(s_in); msg.msg_iov = iov; msg.msg_iovlen = count; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; return sendmsg(s->fd, &msg, 0);#else UNUSED(s); UNUSED(iov); UNUSED(count); return -1;#endif}#endifstatic char *udp_host_addr6(socket_udp *s){#ifdef HAVE_IPv6 char hname[MAXHOSTNAMELEN]; int gai_err, newsock; struct addrinfo hints, *ai; struct sockaddr_in6 local, addr6; int len = sizeof(local), result = 0; newsock=socket(AF_INET6, SOCK_DGRAM,0); memset ((char *)&addr6, 0, len); addr6.sin6_family = AF_INET6;#ifdef HAVE_SIN6_LEN addr6.sin6_len = len;#endif bind (newsock, (struct sockaddr *) &addr6, len); addr6.sin6_addr = s->addr6; addr6.sin6_port = htons (s->rx_port); connect (newsock, (struct sockaddr *) &addr6, len); memset ((char *)&local, 0, len); if ((result = getsockname(newsock,(struct sockaddr *)&local, &len)) < 0){ local.sin6_addr = in6addr_any; local.sin6_port = 0; debug_msg("getsockname failed\n"); } close (newsock); if (IN6_IS_ADDR_UNSPECIFIED(&local.sin6_addr) || IN6_IS_ADDR_MULTICAST(&local.sin6_addr)) { if (gethostname(hname, MAXHOSTNAMELEN) != 0) { debug_msg("gethostname failed\n"); abort(); } hints.ai_protocol = 0; hints.ai_flags = 0; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_addrlen = 0; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if ((gai_err = getaddrinfo(hname, NULL, &hints, &ai))) { debug_msg("getaddrinfo: %s: %s\n", hname, gai_strerror(gai_err)); abort(); } if (inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr), hname, MAXHOSTNAMELEN) == NULL) { debug_msg("inet_ntop: %s: \n", hname); abort(); } freeaddrinfo(ai); return xstrdup(hname); } if (inet_ntop(AF_INET6, &local.sin6_addr, hname, MAXHOSTNAMELEN) == NULL) { debug_msg("inet_ntop: %s: \n", hname); abort(); } return xstrdup(hname);#else /* HAVE_IPv6 */ UNUSED(s); return xstrdup("::"); /* The unspecified address... */#endif /* HAVE_IPv6 */} /*****************************************************************************//* Generic functions, which call the appropriate protocol specific routines. *//*****************************************************************************//** * udp_addr_valid: * @addr: string representation of IPv4 or IPv6 network address. * * Returns TRUE if @addr is valid, FALSE otherwise. **/int udp_addr_valid(const char *addr){ return udp_addr_valid4(addr) | udp_addr_valid6(addr);}/** * udp_init: * @addr: character string containing an IPv4 or IPv6 network address. * @rx_port: receive port. * @tx_port: transmit port. * @ttl: time-to-live value for transmitted packets. * * Creates a session for sending and receiving UDP datagrams over IP * networks. * * Returns: a pointer to a valid socket_udp structure on success, NULL otherwise. **/socket_udp *udp_init(const char *addr, uint16_t rx_port, uint16_t tx_port, int ttl){ return udp_init_if(addr, NULL, rx_port, tx_port, ttl);}/** * udp_init_if: * @addr: character string containing an IPv4 or IPv6 network address. * @iface: character string containing an interface name. * @rx_port: receive port. * @tx_port: transmit port. * @ttl: time-to-live value for transmitted packets. * * Creates a session for sending and receiving UDP datagrams over IP * networks. The session uses @iface as the interface to send and * receive datagrams on. * * Return value: a pointer to a socket_udp structure on success, NULL otherwise. **/socket_udp *udp_init_if(const char *addr, const char *iface, uint16_t rx_port, uint16_t tx_port, int ttl){ socket_udp *res; if (strchr(addr, ':') == NULL) { res = udp_init4(addr, iface, rx_port, tx_port, ttl); } else { res = udp_init6(addr, iface, rx_port, tx_port, ttl); } return res;}/** * udp_exit: * @s: UDP session to be terminated. * * Closes UDP session. * **/void udp_exit(socket_udp *s){ switch(s->mode) { case IPv4 : udp_exit4(s); break; case IPv6 : udp_exit6(s); break; default : abort(); }}/** * udp_send: * @s: UDP session. * @buffer: pointer to buffer to be transmitted. * @buflen: length of @buffer. * * Transmits a UDP datagram containing data from @buffer. * * Return value: 0 on success, -1 on failure. **/int udp_send(socket_udp *s, uint8_t *buffer, int buflen){ switch (s->mode) { case IPv4 : return udp_send4(s, buffer, buflen); case IPv6 : return udp_send6(s, buffer, buflen); default : abort(); /* Yuk! */ } return -1;}#ifndef _WIN32int udp_send_iov(socket_udp *s, struct iovec *iov, int count){ switch (s->mode) { case IPv4 : return udp_send_iov4(s, iov, count); case IPv6 : return udp_send_iov6(s, iov, count); default : abort(); } return -1;}#endif/** * udp_recv: * @s: UDP session. * @buffer: buffer to read data into. * @buflen: length of @buffer. * * Reads from datagram queue associated with UDP session. * * Return value: number of bytes read, returns 0 if no data is available. **/int udp_recv(socket_udp *s, uint8_t *buffer, int buflen){ /* Reads data into the buffer, returning the number of bytes read. */ /* If no data is available, this returns the value zero immediately. */ /* Note: since we don't care about the source address of the packet */ /* we receive, this function becomes protocol independent. */ int len; ASSERT(buffer != NULL); ASSERT(buflen > 0); len = recvfrom(s->fd, buffer, buflen, 0, 0, 0); if (len > 0) { return len; } if (errno != ECONNREFUSED) { socket_error("recvfrom"); } return 0;}static fd_set rfd;static fd_t max_fd;/** * udp_fd_zero: * * Clears file descriptor from set associated with UDP sessions (see select(2)). * **/void udp_fd_zero(void){ FD_ZERO(&rfd); max_fd = 0;}/** * udp_fd_set: * @s: UDP session. * * Adds file descriptor associated of @s to set associated with UDP sessions. **/void udp_fd_set(socket_udp *s){ FD_SET(s->fd, &rfd); if (s->fd > (fd_t)max_fd) { max_fd = s->fd; }}/** * udp_fd_isset: * @s: UDP session. * * Checks if file descriptor associated with UDP session is ready for * reading. This function should be called after udp_select(). * * Returns: non-zero if set, zero otherwise. **/int udp_fd_isset(socket_udp *s){ return FD_ISSET(s->fd, &rfd);}/** * udp_select: * @timeout: maximum period to wait for data to arrive. * * Waits for data to arrive for UDP sessions. * * Return value: number of UDP sessions ready for reading. **/int udp_select(struct timeval *timeout){ return select(max_fd + 1, &rfd, NULL, NULL, timeout);}/** * udp_host_addr: * @s: UDP session. * * Return value: character string containing network address * associated with session @s. **/char *udp_host_addr(socket_udp *s){ if (s && s->mode == IPv6) { return udp_host_addr6(s); } return udp_host_addr4();}/** * udp_fd: * @s: UDP session. * * This function allows applications to apply their own socketopt()'s * and ioctl()'s to the UDP session. * * Return value: file descriptor of socket used by session @s. **/int udp_fd(socket_udp *s){ if (s && s->fd > 0) { return s->fd; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -