mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
Unix sockets: remove on closing only the file this socket bound
When a reload cannot take a listening Unix socket over (a bind-time -ol option changed), the new service binds the path anew, and the old listener, closing after it, removed the file, the new socket's by then, leaving nothing to connect to. The socket's file (device and inode) is now noted on binding and the path removed on closing only if it is still that file. structures.h includes <stddef.h> for offsetof() in SASIZE(), which needs it wherever the header is used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
9612bbdd22
commit
5c19e6368f
@ -898,6 +898,7 @@ struct listener {
|
||||
char *netns, *device;
|
||||
struct sockoptset opts;
|
||||
int maxseg;
|
||||
uint64_t undev, unino; /* its file, for a Unix socket on a path */
|
||||
int optversion; /* the configuration whose options are set */
|
||||
/* the services accepting on it, linked by lisnext */
|
||||
struct srvparam *owners;
|
||||
@ -972,6 +973,28 @@ static void listenerrelease(struct srvparam *srv);
|
||||
|
||||
static int srvopen(struct srvstart *s);
|
||||
|
||||
#ifdef WITH_UN
|
||||
/* A Unix socket bound to a path: its file is noted, as a service of a
|
||||
newer configuration may bind the same path anew before this socket is
|
||||
closed, when the file is the other's, which closing must not remove. */
|
||||
static void unbound(PROXYSOCKADDRTYPE *sa, uint64_t *dev, uint64_t *ino){
|
||||
struct stat st;
|
||||
|
||||
if(*SAFAMILY(sa) == AF_UNIX && *SAADDR(sa) && !stat((char *)SAADDR(sa), &st)){
|
||||
*dev = (uint64_t)st.st_dev;
|
||||
*ino = (uint64_t)st.st_ino;
|
||||
}
|
||||
}
|
||||
|
||||
static void ununlink(PROXYSOCKADDRTYPE *sa, uint64_t dev, uint64_t ino){
|
||||
struct stat st;
|
||||
|
||||
if(*SAFAMILY(sa) == AF_UNIX && *SAADDR(sa) && !stat((char *)SAADDR(sa), &st) &&
|
||||
(uint64_t)st.st_dev == dev && (uint64_t)st.st_ino == ino)
|
||||
unlink((char *)SAADDR(sa));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* The listening socket of the service: its listener's, opened by the first
|
||||
of the listener's services to get here. */
|
||||
static int srvlisten(struct srvstart *s){
|
||||
@ -993,6 +1016,8 @@ static int srvlisten(struct srvstart *s){
|
||||
_3proxy_mutex_lock(&listener_mutex);
|
||||
l->sock = srv->srvsock;
|
||||
l->optversion = srv->version;
|
||||
l->undev = srv->undev;
|
||||
l->unino = srv->unino;
|
||||
_3proxy_mutex_unlock(&listener_mutex);
|
||||
}
|
||||
else if(srv->srvsock != INVALID_SOCKET){
|
||||
@ -1087,6 +1112,9 @@ static int srvopen(struct srvstart *s){
|
||||
sleeptime = (sleeptime<<1);
|
||||
if(!sleeptime) return -3;
|
||||
}
|
||||
#ifdef WITH_UN
|
||||
unbound(&srv->intsa, &srv->undev, &srv->unino);
|
||||
#endif
|
||||
#ifndef NOTCPMAIN
|
||||
if(!s->isudp){
|
||||
if(srv->so._listen (srv->so.state, sock, srv->backlog?srv->backlog : 1+(srv->maxchild>>3))==-1) {
|
||||
@ -1838,7 +1866,7 @@ static void listenerstop(struct srvparam *srv){
|
||||
if(sock == INVALID_SOCKET) return;
|
||||
so._closesocket(so.state, sock);
|
||||
#ifdef WITH_UN
|
||||
if(*SAFAMILY(&l->sa) == AF_UNIX && *SAADDR(&l->sa))unlink((char *)SAADDR(&l->sa));
|
||||
ununlink(&l->sa, l->undev, l->unino);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2047,7 +2075,7 @@ void srvfree(struct srvparam * srv){
|
||||
if(srv->srvsock != INVALID_SOCKET) {
|
||||
so._closesocket(srv->so.state, srv->srvsock);
|
||||
#ifdef WITH_UN
|
||||
if(*SAFAMILY(&srv->intsa) == AF_UNIX && *SAADDR(&srv->intsa))unlink((char *)SAADDR(&srv->intsa));
|
||||
ununlink(&srv->intsa, srv->undev, srv->unino);
|
||||
#endif
|
||||
}
|
||||
srv->srvsock = INVALID_SOCKET;
|
||||
|
||||
@ -113,6 +113,7 @@ int
|
||||
|
||||
#ifdef WITH_UN
|
||||
#include <sys/un.h>
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#define ALLOW 0
|
||||
@ -631,6 +632,8 @@ struct srvparam {
|
||||
AUTHFUNC authfunc;
|
||||
PROXYFUNC pf;
|
||||
SOCKET srvsock, cbsock;
|
||||
/* the file of a Unix socket bound to a path, to remove only it */
|
||||
uint64_t undev, unino;
|
||||
int childcount;
|
||||
int maxchild;
|
||||
int backlog;
|
||||
|
||||
@ -157,6 +157,18 @@ def run(t):
|
||||
t.fail("its file is still there", path, "missing")
|
||||
t.eq((200, 1000), unix_get(path, url), "and the proxy answers on it")
|
||||
|
||||
# --- a bind-time option changed: a new socket on the same path, and
|
||||
# the old one, closing after, must not remove the new one's file -------
|
||||
t.write_config("unixsock", config().replace(f"proxy -iunix:{path}",
|
||||
f"proxy -olSO_REUSEADDR=0 -iunix:{path}"))
|
||||
t.http(f"http://127.0.0.1:{adm}/R")
|
||||
# the old services stop within a second of the reload
|
||||
time.sleep(2)
|
||||
t.ok("a new socket on the same path keeps its file when the old one closes") \
|
||||
if os.path.exists(path) else \
|
||||
t.fail("a new socket on the same path keeps its file when the old one closes", path, "missing")
|
||||
t.eq((200, 1000), unix_get(path, url), "and the proxy answers on it")
|
||||
|
||||
# --- no service listens there any more: the file goes -------------------
|
||||
t.write_config("unixsock", config(unix=False))
|
||||
t.http(f"http://127.0.0.1:{adm}/R")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user