Build msg's ctrl only one time

This commit is contained in:
angt
2016-03-02 12:57:29 +00:00
parent fc8e97caef
commit 013d8c76d0

197
mud.c
View File

@@ -22,18 +22,14 @@ struct path_info {
uint64_t count;
};
struct path_addr {
unsigned index;
union {
struct in_addr in;
struct in6_addr in6;
} bind;
struct sockaddr_storage peer;
};
struct path {
int up;
struct path_addr addr;
unsigned index;
struct sockaddr_storage addr;
struct {
unsigned char data[256];
size_t size;
} ctrl;
uint64_t dt;
uint64_t rdt;
uint64_t rtt;
@@ -106,56 +102,49 @@ uint64_t mud_now (struct mud *mud)
return (now.tv_sec*UINT64_C(1000000)+now.tv_usec)-mud->base;
}
static
void mud_unmapv4 (struct sockaddr *addr)
{
if (addr->sa_family != AF_INET6)
return;
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)addr;
if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
return;
struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_port = sin6->sin6_port,
};
memcpy(&sin.sin_addr.s_addr,
&sin6->sin6_addr.s6_addr[12],
sizeof(sin.sin_addr.s_addr));
memcpy(addr, &sin, sizeof(sin));
}
static
ssize_t mud_send_path (struct mud *mud, struct path *path, uint64_t now, void *data, size_t size)
{
if (!size)
return 0;
unsigned char ctrl[1024];
struct iovec iov = {
.iov_base = data,
.iov_len = size,
};
struct msghdr msg = {
.msg_name = &path->addr.peer,
.msg_namelen = sizeof(path->addr.peer),
.msg_name = &path->addr,
.msg_namelen = sizeof(path->addr),
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = ctrl,
.msg_controllen = sizeof(ctrl),
.msg_control = path->ctrl.data,
.msg_controllen = path->ctrl.size,
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
if (path->addr.peer.ss_family == AF_INET) {
struct in_pktinfo ipi = {
.ipi_ifindex = path->addr.index,
.ipi_spec_dst = path->addr.bind.in,
};
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(ipi));
memcpy(CMSG_DATA(cmsg), &ipi, sizeof(ipi));
msg.msg_controllen = CMSG_SPACE(sizeof(ipi));
} else {
struct in6_pktinfo ipi6 = {
.ipi6_ifindex = path->addr.index,
.ipi6_addr = path->addr.bind.in6,
};
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(ipi6));
memcpy(CMSG_DATA(cmsg), &ipi6, sizeof(ipi6));
msg.msg_controllen = CMSG_SPACE(sizeof(ipi6));
}
ssize_t ret = sendmsg(mud->fd, &msg, 0);
if (ret > 0) {
@@ -262,8 +251,8 @@ struct path *mud_get_path (struct mud *mud, int index, struct sockaddr *addr)
struct path *path;
for (path = mud->path; path; path = path->next) {
if ((path->addr.index == index) &&
(!mud_cmp_addr(addr, (struct sockaddr *)&path->addr.peer)))
if ((path->index == index) &&
(!mud_cmp_addr(addr, (struct sockaddr *)&path->addr)))
break;
}
@@ -295,6 +284,13 @@ struct path *mud_new_path (struct mud *mud, unsigned index, struct sockaddr *add
return NULL;
}
struct msghdr msg = {
.msg_control = path->ctrl.data,
.msg_controllen = sizeof(path->ctrl.data),
};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
for (struct ifaddrs *ifa = ifaddrs; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr)
continue;
@@ -305,23 +301,44 @@ struct path *mud_new_path (struct mud *mud, unsigned index, struct sockaddr *add
if (strncmp(sock->name, ifa->ifa_name, sizeof(sock->name)))
continue;
switch (addr->sa_family) {
case AF_INET:
memcpy(&path->addr.peer, addr, sizeof(struct sockaddr_in));
memcpy(&path->addr.bind.in,
if (addr->sa_family == AF_INET) {
path->index = index;
memcpy(&path->addr, addr, sizeof(struct sockaddr_in));
struct in_pktinfo ipi = {
.ipi_ifindex = index,
};
memcpy(&ipi.ipi_spec_dst,
&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr,
sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(&path->addr.peer, addr, sizeof(struct sockaddr_in6));
memcpy(&path->addr.bind.in6,
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(ipi));
memcpy(CMSG_DATA(cmsg), &ipi, sizeof(ipi));
path->ctrl.size = CMSG_SPACE(sizeof(ipi));
}
if (addr->sa_family == AF_INET6) {
path->index = index;
memcpy(&path->addr, addr, sizeof(struct sockaddr_in6));
struct in6_pktinfo ipi6 = {
.ipi6_ifindex = index,
};
memcpy(&ipi6.ipi6_addr,
&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr.s6_addr,
sizeof(struct in6_addr));
break;
default:
freeifaddrs(ifaddrs);
free(path);
return NULL;
cmsg->cmsg_level = IPPROTO_IPV6;
cmsg->cmsg_type = IPV6_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(ipi6));
memcpy(CMSG_DATA(cmsg), &ipi6, sizeof(ipi6));
path->ctrl.size = CMSG_SPACE(sizeof(ipi6));
}
break;
@@ -329,7 +346,11 @@ struct path *mud_new_path (struct mud *mud, unsigned index, struct sockaddr *add
freeifaddrs(ifaddrs);
path->addr.index = index;
if (!path->index) {
free(path);
return NULL;
}
path->next = mud->path;
mud->path = path;
@@ -411,7 +432,7 @@ int mud_bind (struct mud *mud, const char *name)
struct path *path;
for (path = mud->path; path; path = path->next)
mud_new_path(mud, ifr.ifr_ifindex, (struct sockaddr *)&path->addr.peer);
mud_new_path(mud, ifr.ifr_ifindex, (struct sockaddr *)&path->addr);
return 0;
}
@@ -626,25 +647,14 @@ int mud_pull (struct mud *mud)
if (ret <= 0)
break;
mud_unmapv4((struct sockaddr *)&addr);
int cmsg_level = IPPROTO_IP;
int cmsg_type = IP_PKTINFO;
if (addr.ss_family == AF_INET6) {
struct sockaddr_in6 *sin6 =(struct sockaddr_in6 *)&addr;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = sin6->sin6_port;
memcpy(&sin.sin_addr.s_addr,
sin6->sin6_addr.s6_addr+12,
sizeof(sin.sin_addr.s_addr));
memcpy(&addr, &sin, sizeof(sin));
} else {
cmsg_level = IPPROTO_IPV6;
cmsg_type = IPV6_PKTINFO;
}
cmsg_level = IPPROTO_IPV6;
cmsg_type = IPV6_PKTINFO;
}
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
@@ -672,11 +682,28 @@ int mud_pull (struct mud *mud)
struct path *path = mud_get_path(mud, index, (struct sockaddr *)&addr);
if (!path) {
if (path) {
struct msghdr send_msg = {
.msg_control = path->ctrl.data,
.msg_controllen = path->ctrl.size,
};
struct cmsghdr *send_cmsg = CMSG_FIRSTHDR(&send_msg);
if (cmsg_level == IPPROTO_IP) {
memcpy(&((struct in_pktinfo *)CMSG_DATA(send_cmsg))->ipi_spec_dst,
&((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr,
sizeof(struct in_addr));
} else {
memcpy(&((struct in6_pktinfo *)CMSG_DATA(send_cmsg))->ipi6_addr,
&((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr,
sizeof(struct in6_addr));
}
} else {
unsigned char tmp[sizeof(packet->data)];
if (mud_decrypt(mud, NULL, tmp, sizeof(tmp),
packet->data, (size_t)ret, 4) == -1)
packet->data, (size_t)ret, 4) == -1)
continue;
path = mud_new_path(mud, index, (struct sockaddr *)&addr);
@@ -686,17 +713,6 @@ int mud_pull (struct mud *mud)
}
path->up = 1;
path->addr.index = index;
if (cmsg_level == IPPROTO_IP) {
memcpy(&path->addr.bind.in,
&((struct in_pktinfo *)CMSG_DATA(cmsg))->ipi_addr,
sizeof(path->addr.bind.in));
} else {
memcpy(&path->addr.bind.in6,
&((struct in6_pktinfo *)CMSG_DATA(cmsg))->ipi6_addr,
sizeof(path->addr.bind.in6));
}
uint64_t send_time = mud_read48(packet->data);
int64_t dt = (now-path->recv.time)-(send_time-path->recv.send_time);
@@ -727,7 +743,8 @@ int mud_pull (struct mud *mud)
mud_write48(&pong[6*1], now);
mud_write48(&pong[6*2], path->rdt);
int ret = mud_encrypt(mud, 0, tmp, sizeof(tmp), pong, sizeof(pong), sizeof(pong));
int ret = mud_encrypt(mud, 0, tmp, sizeof(tmp),
pong, sizeof(pong), sizeof(pong));
if (ret > 0) {
mud_send_path(mud, path, now, tmp, (size_t)ret);