📄 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 _WIN32
static 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
}
#endif
static 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 _WIN32
int 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 + -