Improve struct socket_address

Add struct sockaddr_in 'inet' union field, rename 'addr_un' union field
to 'local'

Replace recvwithttl()'s (struct sockaddr *) and socklen_t pair of args
with single (struct socket_address *) arg
This commit is contained in:
Andrew Bettison 2013-11-29 12:56:59 +10:30
parent d45470ce81
commit dafa1fc186
10 changed files with 73 additions and 67 deletions

View File

@ -43,10 +43,10 @@ static void mdp_unlink(int mdp_sock)
if (getsockname(mdp_sock, &addr.addr, &addr.addrlen))
WHYF_perror("getsockname(%d)", mdp_sock);
else if (addr.addr.sa_family==AF_UNIX
&& addr.addrlen > sizeof addr.addr_un.sun_family
&& addr.addrlen <= sizeof addr.addr_un && addr.addr_un.sun_path[0] != '\0') {
if (unlink(addr.addr_un.sun_path) == -1)
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.addr_un.sun_path));
&& addr.addrlen > sizeof addr.local.sun_family
&& addr.addrlen <= sizeof addr.local && addr.local.sun_path[0] != '\0') {
if (unlink(addr.local.sun_path) == -1)
WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path));
}
close(mdp_sock);
}
@ -123,7 +123,7 @@ ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_
addr.addrlen=hdr.msg_namelen;
// double check that the incoming address matches the servald daemon
if (cmp_sockaddr(&addr, &mdp_addr) != 0
&& ( addr.addr_un.sun_family != AF_UNIX
&& ( addr.local.sun_family != AF_UNIX
|| real_sockaddr(&addr, &addr) <= 0
|| cmp_sockaddr(&addr, &mdp_addr) != 0
)
@ -259,7 +259,7 @@ int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, mdp_port_t port, in
ssize_t len;
mdp->packetTypeAndFlags = 0;
set_nonblock(mdp_sockfd);
len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, &recvaddr.addr, &recvaddr.addrlen);
len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, &recvaddr);
set_block(mdp_sockfd);
if (len <= 0)
return -1; // no packet received
@ -272,7 +272,7 @@ int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, mdp_port_t port, in
// Compare the address of the sender with the address of our server, to ensure they are the same.
// If the comparison fails, then try using realpath(3) on the sender address and compare again.
if ( cmp_sockaddr(&recvaddr, &mdp_addr) != 0
&& ( recvaddr.addr_un.sun_family != AF_UNIX
&& ( recvaddr.local.sun_family != AF_UNIX
|| real_sockaddr(&recvaddr, &recvaddr) <= 0
|| cmp_sockaddr(&recvaddr, &mdp_addr) != 0
)

10
net.c
View File

@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "conf.h"
#include "net.h"
#include "socket.h"
#include "str.h"
#include "strbuf_helpers.h"
@ -138,8 +139,7 @@ ssize_t _write_str_nonblock(int fd, const char *str, struct __sourceloc __whence
return _write_all_nonblock(fd, str, strlen(str), __whence);
}
ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
struct sockaddr *recvaddr, socklen_t *recvaddrlen)
ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl, struct socket_address *recvaddr)
{
struct msghdr msg;
struct iovec iov[1];
@ -147,8 +147,8 @@ ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
iov[0].iov_base=buffer;
iov[0].iov_len=bufferlen;
bzero(&msg,sizeof(msg));
msg.msg_name = recvaddr;
msg.msg_namelen = *recvaddrlen;
msg.msg_name = &recvaddr->store;
msg.msg_namelen = recvaddr->addrlen;
msg.msg_iov = &iov[0];
msg.msg_iovlen = 1;
// setting the following makes the data end up in the wrong place
@ -192,7 +192,7 @@ ssize_t recvwithttl(int sock,unsigned char *buffer, size_t bufferlen,int *ttl,
}
}
}
*recvaddrlen=msg.msg_namelen;
recvaddr->addrlen = msg.msg_namelen;
return len;
}

4
net.h
View File

@ -52,6 +52,8 @@ ssize_t _write_all_nonblock(int fd, const void *buf, size_t len, struct __source
ssize_t _writev_all(int fd, const struct iovec *iov, int iovcnt, struct __sourceloc __whence);
ssize_t _write_str(int fd, const char *str, struct __sourceloc __whence);
ssize_t _write_str_nonblock(int fd, const char *str, struct __sourceloc __whence);
ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct sockaddr *recvaddr, socklen_t *recvaddrlen);
struct socket_address;
ssize_t recvwithttl(int sock, unsigned char *buffer, size_t bufferlen, int *ttl, struct socket_address *);
#endif // __SERVALD_NET_H

View File

@ -25,6 +25,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include <fnmatch.h>
#include "serval.h"
#include "conf.h"
#include "net.h"
#include "socket.h"
#include "strbuf.h"
#include "strbuf_helpers.h"
#include "overlay_buffer.h"
@ -248,18 +250,19 @@ int overlay_interface_compare(overlay_interface *one, overlay_interface *two)
// OSX doesn't recieve broadcast packets on sockets bound to an interface's address
// So we have to bind a socket to INADDR_ANY to receive these packets.
static void
overlay_interface_read_any(struct sched_ent *alarm){
overlay_interface_read_any(struct sched_ent *alarm)
{
if (alarm->poll.revents & POLLIN) {
int plen=0;
int recvttl=1;
unsigned char packet[16384];
overlay_interface *interface=NULL;
struct sockaddr src_addr;
socklen_t addrlen = sizeof(src_addr);
struct socket_address recvaddr;
recvaddr.addrlen = sizeof recvaddr.store;
/* Read only one UDP packet per call to share resources more fairly, and also
enable stats to accurately count packets received */
plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &src_addr, &addrlen);
plen = recvwithttl(alarm->poll.fd, packet, sizeof(packet), &recvttl, &recvaddr);
if (plen == -1) {
WHY_perror("recvwithttl(c)");
unwatch(alarm);
@ -267,18 +270,16 @@ overlay_interface_read_any(struct sched_ent *alarm){
return;
}
struct in_addr src = ((struct sockaddr_in *)&src_addr)->sin_addr;
/* Try to identify the real interface that the packet arrived on */
interface = overlay_interface_find(src, 0);
interface = overlay_interface_find(recvaddr.inet.sin_addr, 0);
/* Drop the packet if we don't find a match */
if (!interface){
if (config.debug.overlayinterfaces)
DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(src));
DEBUGF("Could not find matching interface for packet received from %s", inet_ntoa(recvaddr.inet.sin_addr));
return;
}
packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen);
packetOkOverlay(interface, packet, plen, recvttl, &recvaddr);
}
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
INFO("Closing broadcast socket due to error");
@ -569,25 +570,24 @@ cleanup:
return cleanup_ret;
}
static void interface_read_dgram(struct overlay_interface *interface){
static void interface_read_dgram(struct overlay_interface *interface)
{
int plen=0;
unsigned char packet[8096];
struct sockaddr src_addr;
socklen_t addrlen = sizeof(src_addr);
struct socket_address recvaddr;
recvaddr.addrlen = sizeof recvaddr.store;
/* Read only one UDP packet per call to share resources more fairly, and also
enable stats to accurately count packets received */
int recvttl=1;
plen = recvwithttl(interface->alarm.poll.fd,packet, sizeof(packet), &recvttl, &src_addr, &addrlen);
plen = recvwithttl(interface->alarm.poll.fd,packet, sizeof(packet), &recvttl, &recvaddr);
if (plen == -1) {
WHY_perror("recvwithttl(c)");
overlay_interface_close(interface);
return;
}
packetOkOverlay(interface, packet, plen, recvttl, &src_addr, addrlen);
packetOkOverlay(interface, packet, plen, recvttl, &recvaddr);
}
struct file_packet{
@ -678,8 +678,10 @@ static void interface_read_file(struct overlay_interface *interface)
alloca_sockaddr_in(&packet.dst_addr)
);
}else{
packetOkOverlay(interface, packet.payload, packet.payload_length, -1,
(struct sockaddr*)&packet.src_addr, (socklen_t) sizeof(packet.src_addr));
struct socket_address srcaddr;
srcaddr.addrlen = sizeof packet.src_addr;
srcaddr.inet = packet.src_addr;
packetOkOverlay(interface, packet.payload, packet.payload_length, -1, &srcaddr);
}
}
}

View File

@ -1479,11 +1479,11 @@ static void overlay_mdp_poll(struct sched_ent *alarm)
unsigned char buffer[16384];
int ttl;
struct socket_address client;
client.addrlen=sizeof(client.store);
client.addrlen = sizeof client.store;
ttl=-1;
ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, (struct sockaddr *)&client.addr, &client.addrlen);
ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, &client);
if (len > 0) {
if (client.addrlen <= sizeof(sa_family_t))

View File

@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
#include "conf.h"
#include "socket.h"
#include "str.h"
#include "strbuf.h"
#include "overlay_buffer.h"
@ -320,7 +321,7 @@ int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface
}
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
int recvttl, struct sockaddr *recvaddr, socklen_t recvaddrlen)
int recvttl, struct socket_address *recvaddr)
{
IN();
/*
@ -385,8 +386,8 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
}
}
if (recvaddr&&recvaddr->sa_family!=AF_INET)
RETURN(WHYF("Unexpected protocol family %d",recvaddr->sa_family));
if (recvaddr && recvaddr->addr.sa_family != AF_INET)
RETURN(WHYF("Unexpected protocol family %d", recvaddr->addr.sa_family));
struct overlay_frame f;
struct decode_context context;
@ -399,11 +400,11 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s
f.interface = interface;
if (recvaddr)
f.recvaddr = *((struct sockaddr_in *)recvaddr);
f.recvaddr = recvaddr->inet;
else
bzero(&f.recvaddr, sizeof f.recvaddr);
int ret=parseEnvelopeHeader(&context, interface, (struct sockaddr_in *)recvaddr, b);
int ret=parseEnvelopeHeader(&context, interface, recvaddr ? &recvaddr->inet : NULL, b);
if (ret){
ob_free(b);
RETURN(ret);

View File

@ -433,7 +433,7 @@ static int radio_link_parse(struct overlay_interface *interface, struct radio_li
if (config.debug.radio_link)
DEBUGF("PDU Complete (length=%d)",state->packet_length);
packetOkOverlay(interface, state->dst, state->packet_length, -1, NULL, 0);
packetOkOverlay(interface, state->dst, state->packet_length, -1, NULL);
state->packet_length=sizeof(state->dst)+1;
}
return 1;

View File

@ -404,7 +404,7 @@ void insertTransactionInCache(unsigned char *transaction_id);
int overlay_forward_payload(struct overlay_frame *f);
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
int recvttl, struct sockaddr *recvaddr, socklen_t recvaddrlen);
int recvttl, struct socket_address *recvaddr);
int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *frame,
struct overlay_buffer *buffer, struct subscriber **nexthop);
int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface,

View File

@ -44,14 +44,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
int _make_local_sockaddr(struct __sourceloc __whence, struct socket_address *addr, const char *fmt, ...)
{
bzero(addr, sizeof(*addr));
addr->addr_un.sun_family = AF_UNIX;
addr->local.sun_family = AF_UNIX;
va_list ap;
va_start(ap, fmt);
int r = vformf_serval_instance_path(__WHENCE__, addr->addr_un.sun_path, sizeof addr->addr_un.sun_path, fmt, ap);
int r = vformf_serval_instance_path(__WHENCE__, addr->local.sun_path, sizeof addr->local.sun_path, fmt, ap);
va_end(ap);
if (!r)
return WHY("socket name overflow");
addr->addrlen=sizeof addr->addr_un.sun_family + strlen(addr->addr_un.sun_path) + 1;
addr->addrlen=sizeof addr->local.sun_family + strlen(addr->local.sun_path) + 1;
// TODO perform real path transformation in making the serval instance path
// if (real_sockaddr(addr, addr) == -1)
// return -1;
@ -60,7 +60,7 @@ int _make_local_sockaddr(struct __sourceloc __whence, struct socket_address *add
// For the abstract name we use the absolute path name with the initial '/' replaced by the
// leading nul. This ensures that different instances of the Serval daemon have different socket
// names.
addr->addr_un.sun_path[0] = '\0'; // mark as Linux abstract socket
addr->local.sun_path[0] = '\0'; // mark as Linux abstract socket
--addr->addrlen; // do not count trailing nul in abstract socket name
#endif // USE_ABSTRACT_NAMESPACE
return 0;
@ -80,24 +80,24 @@ int _make_local_sockaddr(struct __sourceloc __whence, struct socket_address *add
*/
int real_sockaddr(const struct socket_address *src_addr, struct socket_address *dst_addr)
{
int src_path_len = src_addr->addrlen - sizeof src_addr->addr_un.sun_family;
if ( src_addr->addrlen >= sizeof src_addr->addr_un.sun_family + 1
&& src_addr->addr_un.sun_family == AF_UNIX
&& src_addr->addr_un.sun_path[0] != '\0'
&& src_addr->addr_un.sun_path[src_path_len - 1] == '\0'
int src_path_len = src_addr->addrlen - sizeof src_addr->local.sun_family;
if ( src_addr->addrlen >= sizeof src_addr->local.sun_family + 1
&& src_addr->local.sun_family == AF_UNIX
&& src_addr->local.sun_path[0] != '\0'
&& src_addr->local.sun_path[src_path_len - 1] == '\0'
) {
char real_path[PATH_MAX];
size_t real_path_len;
if (realpath(src_addr->addr_un.sun_path, real_path) == NULL)
return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->addr_un.sun_path));
else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->addr_un.sun_path)
if (realpath(src_addr->local.sun_path, real_path) == NULL)
return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->local.sun_path));
else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->local.sun_path)
return WHYF("sockaddr overrun: realpath(%s) returned %s",
alloca_str_toprint(src_addr->addr_un.sun_path), alloca_str_toprint(real_path));
alloca_str_toprint(src_addr->local.sun_path), alloca_str_toprint(real_path));
else if ( real_path_len != src_path_len
|| memcmp(real_path, src_addr->addr_un.sun_path, src_path_len) != 0
|| memcmp(real_path, src_addr->local.sun_path, src_path_len) != 0
) {
memcpy(dst_addr->addr_un.sun_path, real_path, real_path_len);
dst_addr->addrlen = real_path_len + sizeof dst_addr->addr_un.sun_family;
memcpy(dst_addr->local.sun_path, real_path, real_path_len);
dst_addr->addrlen = real_path_len + sizeof dst_addr->local.sun_family;
return 1;
}
}
@ -133,23 +133,23 @@ int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address
// Both addresses are in the same family...
switch (addrA->addr.sa_family) {
case AF_UNIX: {
unsigned pathlenA = addrA->addrlen - sizeof (addrA->addr_un.sun_family);
unsigned pathlenB = addrB->addrlen - sizeof (addrB->addr_un.sun_family);
unsigned pathlenA = addrA->addrlen - sizeof (addrA->local.sun_family);
unsigned pathlenB = addrB->addrlen - sizeof (addrB->local.sun_family);
int c;
if ( pathlenA > 1 && pathlenB > 1
&& addrA->addr_un.sun_path[0] == '\0'
&& addrB->addr_un.sun_path[0] == '\0'
&& addrA->local.sun_path[0] == '\0'
&& addrB->local.sun_path[0] == '\0'
) {
// Both abstract sockets - just compare names, nul bytes are not terminators.
c = memcmp(&addrA->addr_un.sun_path[1],
&addrB->addr_un.sun_path[1],
c = memcmp(&addrA->local.sun_path[1],
&addrB->local.sun_path[1],
(pathlenA < pathlenB ? pathlenA : pathlenB) - 1);
} else {
// Either or both are named local file sockets. If the file names are identical up to the
// first nul, then the addresses are equal. This collates abstract socket names, whose first
// character is a nul, ahead of all non-empty file socket names.
c = strncmp(addrA->addr_un.sun_path,
addrB->addr_un.sun_path,
c = strncmp(addrA->local.sun_path,
addrB->local.sun_path,
(pathlenA < pathlenB ? pathlenA : pathlenB));
}
if (c == 0)

View File

@ -9,7 +9,8 @@ struct socket_address{
socklen_t addrlen;
union{
struct sockaddr addr;
struct sockaddr_un addr_un;
struct sockaddr_un local; // name "unix" is a predefined macro
struct sockaddr_in inet;
struct sockaddr_storage store;
};
};
@ -53,4 +54,4 @@ ssize_t _recv_message(struct __sourceloc, int fd, struct socket_address *address
#define send_message(fd, address, data) _send_message(__WHENCE__, (fd), (address), (data))
#define recv_message(fd, address, data) _recv_message(__WHENCE__, (fd), (address), (data))
#endif
#endif