Support for IPv6 sockets. How nice one doesn't have to ifdef around

ten years of API evolution :-)
This commit is contained in:
Martin Mares 1999-08-03 19:36:51 +00:00
parent dce267832a
commit 4f22c98185
3 changed files with 112 additions and 19 deletions

View file

@ -88,6 +88,8 @@ ipv6_classify(ip_addr *a)
case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE; case 14: return IADDR_MULTICAST | SCOPE_UNIVERSE;
} }
} }
if (!x && !a->addr[1] && !a->addr[2] && a->addr[3] == 1)
return IADDR_HOST | SCOPE_HOST; /* Loopback address */
return IADDR_INVALID; return IADDR_INVALID;
} }

View file

@ -28,6 +28,10 @@
#include "lib/event.h" #include "lib/event.h"
#include "nest/iface.h" #include "nest/iface.h"
#ifdef IPV6
#include <linux/in6.h> /* FIXMEv6: glibc variant? */
#endif
#include "lib/unix.h" #include "lib/unix.h"
/* /*
@ -311,6 +315,37 @@ sk_new(pool *p)
#define ERR(x) do { err = x; goto bad; } while(0) #define ERR(x) do { err = x; goto bad; } while(0)
#ifdef IPV6
static inline void
set_inaddr(struct in6_addr *ia, ip_addr a)
{
ipa_hton(a);
memcpy(ia, &a, sizeof(a));
}
void
fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
{
sa->sin6_family = AF_INET6;
sa->sin6_port = htons(port);
sa->sin6_flowinfo = 0;
set_inaddr(&sa->sin6_addr, a);
}
void
get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
{
if (sa->sin6_family != AF_INET6)
bug("get_sockaddr called for wrong address family");
if (port)
*port = ntohs(sa->sin6_port);
memcpy(a, &sa->sin6_addr, sizeof(*a));
ipa_ntoh(*a);
}
#else
static inline void static inline void
set_inaddr(struct in_addr *ia, ip_addr a) set_inaddr(struct in_addr *ia, ip_addr a)
{ {
@ -319,7 +354,7 @@ set_inaddr(struct in_addr *ia, ip_addr a)
} }
void void
fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port) fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port)
{ {
sa->sin_family = AF_INET; sa->sin_family = AF_INET;
sa->sin_port = htons(port); sa->sin_port = htons(port);
@ -327,7 +362,7 @@ fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port)
} }
void void
get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port) get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port)
{ {
if (sa->sin_family != AF_INET) if (sa->sin_family != AF_INET)
bug("get_sockaddr called for wrong address family"); bug("get_sockaddr called for wrong address family");
@ -337,6 +372,8 @@ get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port)
ipa_ntoh(*a); ipa_ntoh(*a);
} }
#endif
static char * static char *
sk_setup(sock *s) sk_setup(sock *s)
{ {
@ -346,6 +383,11 @@ sk_setup(sock *s)
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
ERR("fcntl(O_NONBLOCK)"); ERR("fcntl(O_NONBLOCK)");
#ifdef IPV6
if (s->ttl >= 0 && s->type != SK_UDP_MC && s->type != SK_IP_MC &&
setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IPV6_UNICAST_HOPS");
#else
if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0) if ((s->tos >= 0) && setsockopt(fd, SOL_IP, IP_TOS, &s->tos, sizeof(s->tos)) < 0)
ERR("IP_TOS"); ERR("IP_TOS");
if (s->ttl >= 0) if (s->ttl >= 0)
@ -355,13 +397,6 @@ sk_setup(sock *s)
if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0) if (setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof(one)) < 0)
ERR("SO_DONTROUTE"); ERR("SO_DONTROUTE");
} }
#ifdef IP_PMTUDISC
if (s->type != SK_TCP_PASSIVE && s->type != SK_TCP_ACTIVE && s->type != SK_MAGIC)
{
int dont = IP_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
ERR("IP_PMTUDISC");
}
#endif #endif
/* FIXME: Set send/receive buffers? */ /* FIXME: Set send/receive buffers? */
/* FIXME: Set keepalive for TCP connections? */ /* FIXME: Set keepalive for TCP connections? */
@ -393,7 +428,7 @@ int
sk_open(sock *s) sk_open(sock *s)
{ {
int fd, e; int fd, e;
struct sockaddr_in sa; sockaddr sa;
int zero = 0; int zero = 0;
int one = 1; int one = 1;
int type = s->type; int type = s->type;
@ -405,15 +440,15 @@ sk_open(sock *s)
{ {
case SK_TCP_ACTIVE: case SK_TCP_ACTIVE:
case SK_TCP_PASSIVE: case SK_TCP_PASSIVE:
fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP);
break; break;
case SK_UDP: case SK_UDP:
case SK_UDP_MC: case SK_UDP_MC:
fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP);
break; break;
case SK_IP: case SK_IP:
case SK_IP_MC: case SK_IP_MC:
fd = socket(PF_INET, SOCK_RAW, s->dport); fd = socket(BIRD_PF, SOCK_RAW, s->dport);
break; break;
case SK_MAGIC: case SK_MAGIC:
fd = s->fd; fd = s->fd;
@ -432,12 +467,39 @@ sk_open(sock *s)
case SK_UDP: case SK_UDP:
case SK_IP: case SK_IP:
if (s->iface) /* It's a broadcast socket */ if (s->iface) /* It's a broadcast socket */
#ifdef IPV6
bug("IPv6 has no broadcasts");
#else
if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
ERR("SO_BROADCAST"); ERR("SO_BROADCAST");
#endif
break; break;
case SK_UDP_MC: case SK_UDP_MC:
case SK_IP_MC: case SK_IP_MC:
{ {
#ifdef IPV6
/* Fortunately, IPv6 socket interface is recent enough and therefore standardized */
ASSERT(s->iface && s->iface->addr);
if (has_dest)
{
int t = s->iface->index;
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0)
ERR("IPV6_MULTICAST_HOPS");
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0)
ERR("IPV6_MULTICAST_LOOP");
if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &t, sizeof(t)) < 0)
ERR("IPV6_MULTICAST_IF");
}
if (has_src)
{
struct ipv6_mreq mreq;
set_inaddr(&mreq.ipv6mr_multiaddr, s->daddr);
mreq.ipv6mr_ifindex = s->iface->index;
if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
ERR("IPV6_ADD_MEMBERSHIP");
}
#else
/* With IPv4 there are zillions of different socket interface variants. Ugh. */
#ifdef HAVE_STRUCT_IP_MREQN #ifdef HAVE_STRUCT_IP_MREQN
struct ip_mreqn mreq; struct ip_mreqn mreq;
#define mreq_add mreq #define mreq_add mreq
@ -484,6 +546,7 @@ sk_open(sock *s)
/* And this one sets interface for _receiving_ multicasts from */ /* And this one sets interface for _receiving_ multicasts from */
if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0) if (has_src && setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0)
ERR("IP_ADD_MEMBERSHIP"); ERR("IP_ADD_MEMBERSHIP");
#endif
break; break;
} }
} }
@ -516,6 +579,26 @@ sk_open(sock *s)
if (listen(fd, 8)) if (listen(fd, 8))
ERR("listen"); ERR("listen");
break; break;
case SK_MAGIC:
break;
default:
#ifdef IPV6
#ifdef IPV6_MTU_DISCOVER
{
int dont = IPV6_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IPV6, IPV6_MTU_DISCOVER, &dont, sizeof(dont)) < 0)
ERR("IPV6_MTU_DISCOVER");
}
#endif
#else
#ifdef IP_PMTUDISC
{
int dont = IP_PMTUDISC_DONT;
if (setsockopt(fd, SOL_IP, IP_PMTUDISC, &dont, sizeof(dont)) < 0)
ERR("IP_PMTUDISC");
}
#endif
#endif
} }
sk_alloc_bufs(s); sk_alloc_bufs(s);
@ -560,7 +643,7 @@ sk_maybe_write(sock *s)
case SK_IP: case SK_IP:
case SK_IP_MC: case SK_IP_MC:
{ {
struct sockaddr_in sa; sockaddr sa;
if (s->tbuf == s->tpos) if (s->tbuf == s->tpos)
return 1; return 1;
@ -611,7 +694,7 @@ sk_read(sock *s)
{ {
case SK_TCP_ACTIVE: case SK_TCP_ACTIVE:
{ {
struct sockaddr_in sa; sockaddr sa;
fill_in_sockaddr(&sa, s->daddr, s->dport); fill_in_sockaddr(&sa, s->daddr, s->dport);
if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0) if (connect(s->fd, (struct sockaddr *) &sa, sizeof(sa)) >= 0)
sk_tcp_connected(s); sk_tcp_connected(s);
@ -624,7 +707,7 @@ sk_read(sock *s)
} }
case SK_TCP_PASSIVE: case SK_TCP_PASSIVE:
{ {
struct sockaddr_in sa; sockaddr sa;
int al = sizeof(sa); int al = sizeof(sa);
int fd = accept(s->fd, (struct sockaddr *) &sa, &al); int fd = accept(s->fd, (struct sockaddr *) &sa, &al);
if (fd >= 0) if (fd >= 0)
@ -678,7 +761,7 @@ sk_read(sock *s)
return s->rx_hook(s, 0); return s->rx_hook(s, 0);
default: default:
{ {
struct sockaddr_in sa; sockaddr sa;
int al = sizeof(sa); int al = sizeof(sa);
int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al); int e = recvfrom(s->fd, s->rbuf, s->rbsize, 0, (struct sockaddr *) &sa, &al);

View file

@ -21,10 +21,18 @@ volatile int async_config_flag;
volatile int async_dump_flag; volatile int async_dump_flag;
volatile int async_shutdown_flag; volatile int async_shutdown_flag;
#ifdef IPV6
#define BIRD_PF PF_INET6
typedef struct sockaddr_in6 sockaddr;
#else
#define BIRD_PF PF_INET
typedef struct sockaddr_in sockaddr;
#endif
void io_init(void); void io_init(void);
void io_loop(void); void io_loop(void);
void fill_in_sockaddr(struct sockaddr_in *sa, ip_addr a, unsigned port); void fill_in_sockaddr(sockaddr *sa, ip_addr a, unsigned port);
void get_sockaddr(struct sockaddr_in *sa, ip_addr *a, unsigned *port); void get_sockaddr(sockaddr *sa, ip_addr *a, unsigned *port);
/* krt.c bits */ /* krt.c bits */