udppm: answer through a socket of the session's own without SHARE_UDP_SOCKET

A build which does not share the UDP listening socket (NO_SHARE_UDP_SOCKET,
which Makefile.win, Makefile.watcom and CMake set for Windows, as Windows
does not take a recv and a send on one socket from two threads) has
dnspr answer from a socket of its own, bound to the service's address,
but udppm still answered through the service's socket. Since sockets
are taken over on a reload, that socket is now also read by the new
services while old sessions write to it. A udppm session in such a
build now makes its own socket too, as dnspr does and as udppm did
before; it is only written to, and closed when the session ends.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Vladimir Dubrovin 2026-10-18 12:48:07 +03:00
parent 5c19e6368f
commit be2ad06dba

View File

@ -35,6 +35,9 @@ void * udppmchild(struct clientparam* param) {
int authres;
int i;
int len = 0;
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
SOCKET copy = INVALID_SOCKET;
#endif
if(parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) { RETURN(100) }
@ -49,6 +52,23 @@ void * udppmchild(struct clientparam* param) {
authres = (*param->srv->authfunc)(param);
if(authres) { RETURN(authres); }
if((authres = udpbind(param))) { RETURN(authres); }
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
/* A build which does not share the UDP listening socket (see proxy.h)
answers the client through a socket of the session's own, bound to
the service's address, as dnspr does; the listening socket has
SO_REUSEADDR set for it in such a build. It is only written to. */
{
PROXYSOCKADDRTYPE local;
SASIZETYPE size = sizeof(local);
unsigned long ul = 1;
if(param->srv->so._getsockname(param->sostate, param->srv->srvsock, (struct sockaddr *)&local, &size)) { RETURN(21); }
if((copy = nssocket(param->srv, &param->srv->so, param->sostate, NS_IN, SASOCK(&local), SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { RETURN(818); }
ioctlsocket(copy, FIONBIO, &ul);
if(param->srv->so._setsockopt(param->sostate, copy, SOL_SOCKET, SO_REUSEADDR, (char *)&ul, sizeof(int))) { RETURN(820); }
if(param->srv->so._bind(param->sostate, copy, (struct sockaddr *)&local, SASIZE(&local))) { RETURN(822); }
}
#endif
if(!param->srv->s_option)hashadd(&udp_table, param, &param, MAX_COUNTER_TIME);
if(!param->bandlimfunc || !(*param->bandlimfunc)(param, 0, param->srv->udplen)){
if(param->udp_nhops){
@ -65,7 +85,11 @@ void * udppmchild(struct clientparam* param) {
}
_3proxy_sem_unlock(udpinit);
param->srvinbuf = 0;
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
param->clisock = copy;
#else
param->clisock = param->srv->srvsock;
#endif
param->waitserver64 = 0x7fffffffffffffff;
param->res = udpsockmap(param, param->srv->timeouts[STRING_L]);
_3proxy_sem_lock(udpinit);
@ -75,6 +99,9 @@ CLEANRET:
_3proxy_sem_unlock(udpinit);
dolog(param, NULL);
#if defined(_WIN32) && !defined(SHARE_UDP_SOCKET)
if(copy != INVALID_SOCKET) param->srv->so._closesocket(param->sostate, copy);
#endif
param->clisock = INVALID_SOCKET;
return (NULL);
}