Skip to content

Commit d43ee51

Browse files
committed
Optimize comparison of similar sockets
Take advantage from de-duplication done in allocate_sfd. Create a new special case, when sfd is created, but its fd is not. Such case is used for interface bound sockets only with random outgoing ports. Speed up searching in random sockets. Server members are not compared one after one, but just pointer to sfd is compared. We ensure each serverfd is unique, so different pointers means different servers.
1 parent 509dce5 commit d43ee51

File tree

4 files changed

+75
-50
lines changed

4 files changed

+75
-50
lines changed

src/dnsmasq.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,7 +1691,8 @@ static int set_dns_listeners(time_t now)
16911691
get_new_frec(now, &wait, NULL);
16921692

16931693
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1694-
poll_listen(serverfdp->fd, POLLIN);
1694+
if (serverfdp->fd != -1)
1695+
poll_listen(serverfdp->fd, POLLIN);
16951696

16961697
for (i = 0; i < RANDOM_SOCKS; i++)
16971698
if (daemon->randomsocks[i].refcount != 0)
@@ -1742,7 +1743,7 @@ static void check_dns_listeners(time_t now)
17421743
int pipefd[2];
17431744

17441745
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
1745-
if (poll_check(serverfdp->fd, POLLIN))
1746+
if (serverfdp->fd != -1 && poll_check(serverfdp->fd, POLLIN))
17461747
reply_query(serverfdp->fd, now);
17471748

17481749
for (i = 0; i < RANDOM_SOCKS; i++)

src/dnsmasq.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,16 +541,19 @@ union mysockaddr {
541541
#define SERV_GOT_TCP 32768 /* Got some data from the TCP connection */
542542

543543
struct serverfd {
544-
int fd;
544+
int fd; /* -1 when random sockets are used */
545545
union mysockaddr source_addr;
546546
char interface[IF_NAMESIZE+1];
547547
unsigned int ifindex, used, preallocated;
548548
struct serverfd *next;
549549
};
550550

551+
#define SERVERFD_INVALID ((struct serverfd *) ~0)
552+
551553
struct randfd {
552-
struct server *serv;
554+
struct serverfd *sfd; /* might be set to SERVERFD_INVALID */
553555
int fd;
556+
short family; /* needed when sfd == NULL */
554557
unsigned short refcount; /* refcount == 0xffff means overflow record. */
555558
};
556559

src/forward.c

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,16 +2174,6 @@ static int random_sock(struct server *s)
21742174
return -1;
21752175
}
21762176

2177-
/* compare source addresses and interface, serv2 can be null. */
2178-
static int server_isequal(const struct server *serv1,
2179-
const struct server *serv2)
2180-
{
2181-
return (serv2 &&
2182-
serv2->ifindex == serv1->ifindex &&
2183-
sockaddr_isequal(&serv2->source_addr, &serv1->source_addr) &&
2184-
strncmp(serv2->interface, serv1->interface, IF_NAMESIZE) == 0);
2185-
}
2186-
21872177
/* fdlp points to chain of randomfds already in use by transaction.
21882178
If there's already a suitable one, return it, else allocate a
21892179
new one and add it to the list.
@@ -2202,12 +2192,13 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
22022192
int fd = 0;
22032193

22042194
/* If server has a pre-allocated fd, use that. */
2205-
if (serv->sfd)
2195+
if (serv->sfd && serv->sfd->fd != -1)
22062196
return serv->sfd->fd;
22072197

22082198
/* existing suitable random port socket linked to this transaction? */
22092199
for (rfl = *fdlp; rfl; rfl = rfl->next)
2210-
if (server_isequal(serv, rfl->rfd->serv))
2200+
if (rfl->rfd->family == serv->addr.sa.sa_family &&
2201+
rfl->rfd->sfd == serv->sfd)
22112202
return rfl->rfd->fd;
22122203

22132204
/* No. need new link. */
@@ -2224,7 +2215,8 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
22242215
if ((fd = random_sock(serv)) != -1)
22252216
{
22262217
rfd = &daemon->randomsocks[i];
2227-
rfd->serv = serv;
2218+
rfd->sfd = serv->sfd;
2219+
rfd->family = serv->addr.sa.sa_family;
22282220
rfd->fd = fd;
22292221
rfd->refcount = 1;
22302222
}
@@ -2237,7 +2229,8 @@ int allocate_rfd(struct randfd_list **fdlp, struct server *serv)
22372229
{
22382230
i = (j + finger) % RANDOM_SOCKS;
22392231
if (daemon->randomsocks[i].refcount != 0 &&
2240-
server_isequal(serv, daemon->randomsocks[i].serv) &&
2232+
serv->addr.sa.sa_family == daemon->randomsocks[i].family &&
2233+
serv->sfd == daemon->randomsocks[i].sfd &&
22412234
daemon->randomsocks[i].refcount != 0xfffe)
22422235
{
22432236
finger = i + 1;
@@ -2527,18 +2520,11 @@ void resend_query()
25272520
void server_gone(struct server *server)
25282521
{
25292522
struct frec *f;
2530-
int i;
25312523

25322524
for (f = daemon->frec_list; f; f = f->next)
25332525
if (f->sentto && f->sentto == server)
25342526
free_frec(f);
25352527

2536-
/* If any random socket refers to this server, NULL the reference.
2537-
No more references to the socket will be created in the future. */
2538-
for (i = 0; i < RANDOM_SOCKS; i++)
2539-
if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].serv == server)
2540-
daemon->randomsocks[i].serv = NULL;
2541-
25422528
if (daemon->last_server == server)
25432529
daemon->last_server = NULL;
25442530

src/network.c

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,11 +1378,29 @@ int local_bind(int fd, union mysockaddr *addr, char *intname, unsigned int ifind
13781378
return 1;
13791379
}
13801380

1381+
static int allocate_sfd_socket(union mysockaddr *addr, char *intname, unsigned int ifindex)
1382+
{
1383+
int fd;
1384+
int opt = 1;
1385+
1386+
if ((fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
1387+
return -1;
1388+
1389+
if ((addr->sa.sa_family == AF_INET6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
1390+
!local_bind(fd, addr, intname, ifindex, 0) || !fix_fd(fd))
1391+
{
1392+
int errsave = errno; /* save error from bind/setsockopt. */
1393+
close(fd);
1394+
errno = errsave;
1395+
return -1;
1396+
}
1397+
return fd;
1398+
}
1399+
13811400
static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsigned int ifindex)
13821401
{
13831402
struct serverfd *sfd;
1384-
int errsave;
1385-
int opt = 1;
1403+
int singlefd = 1;
13861404

13871405
/* when using random ports, servers which would otherwise use
13881406
the INADDR_ANY/port0 socket have sfd set to NULL, this is
@@ -1391,13 +1409,15 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsi
13911409
{
13921410
errno = 0;
13931411

1394-
if (addr->sa.sa_family == AF_INET &&
1395-
addr->in.sin_port == htons(0))
1396-
return NULL;
1397-
1398-
if (addr->sa.sa_family == AF_INET6 &&
1399-
addr->in6.sin6_port == htons(0))
1400-
return NULL;
1412+
if ((addr->sa.sa_family == AF_INET &&
1413+
addr->in.sin_port == htons(0)) ||
1414+
(addr->sa.sa_family == AF_INET6 &&
1415+
addr->in6.sin6_port == htons(0)))
1416+
{
1417+
if (intname[0] == 0)
1418+
return NULL;
1419+
singlefd = 0;
1420+
}
14011421
}
14021422

14031423
/* may have a suitable one already */
@@ -1411,21 +1431,16 @@ static struct serverfd *allocate_sfd(union mysockaddr *addr, char *intname, unsi
14111431
errno = ENOMEM; /* in case malloc fails. */
14121432
if (!(sfd = whine_malloc(sizeof(struct serverfd))))
14131433
return NULL;
1414-
1415-
if ((sfd->fd = socket(addr->sa.sa_family, SOCK_DGRAM, 0)) == -1)
1416-
{
1417-
free(sfd);
1418-
return NULL;
1419-
}
14201434

1421-
if ((addr->sa.sa_family == AF_INET6 && setsockopt(sfd->fd, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)) == -1) ||
1422-
!local_bind(sfd->fd, addr, intname, ifindex, 0) || !fix_fd(sfd->fd))
1423-
{
1424-
errsave = errno; /* save error from bind/setsockopt. */
1425-
close(sfd->fd);
1426-
free(sfd);
1427-
errno = errsave;
1428-
return NULL;
1435+
sfd->fd = -1;
1436+
if (singlefd)
1437+
{
1438+
sfd->fd = allocate_sfd_socket(addr, intname, ifindex);
1439+
if (sfd->fd == -1)
1440+
{
1441+
free(sfd);
1442+
return NULL;
1443+
}
14291444
}
14301445

14311446
safe_strncpy(sfd->interface, intname, sizeof(sfd->interface));
@@ -1607,6 +1622,27 @@ void add_update_server(int flags,
16071622
}
16081623
}
16091624

1625+
static void free_sfd(struct serverfd *sfd)
1626+
{
1627+
int i;
1628+
struct randfd_list *rl;
1629+
1630+
/* If any random socket refers to this serverfd, invalidate the reference.
1631+
NULL is valid value in randfd.sfd, cannot use that. */
1632+
for (i = 0; i < RANDOM_SOCKS; i++)
1633+
if (daemon->randomsocks[i].refcount != 0 && daemon->randomsocks[i].sfd == sfd)
1634+
daemon->randomsocks[i].sfd = SERVERFD_INVALID;
1635+
for (rl = daemon->rfl_poll; rl; rl = rl->next)
1636+
/* Invalidate sfd pointer so it is no longer reused.
1637+
* Pending answers might be still received and processed. */
1638+
if (rl->rfd->sfd == sfd)
1639+
rl->rfd->sfd = SERVERFD_INVALID;
1640+
1641+
if (sfd->fd != -1)
1642+
close(sfd->fd);
1643+
free(sfd);
1644+
}
1645+
16101646
void check_servers(void)
16111647
{
16121648
struct irec *iface;
@@ -1747,8 +1783,7 @@ void check_servers(void)
17471783
if (!sfd->used)
17481784
{
17491785
*up = sfd->next;
1750-
close(sfd->fd);
1751-
free(sfd);
1786+
free_sfd(sfd);
17521787
}
17531788
else
17541789
up = &sfd->next;

0 commit comments

Comments
 (0)