mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-20 08:30:42 +01:00
refactor create_udp_socket
Function used very old style and was hard to read. Now also supports strucutred handling of exceptions. see also https://github.com/rsyslog/rsyslog/pull/2049 see also https://github.com/rsyslog/rsyslog/issues/2040
This commit is contained in:
parent
08f2d10caa
commit
ee1499f462
427
runtime/net.c
427
runtime/net.c
@ -1252,6 +1252,206 @@ closeUDPListenSockets(int *pSockArr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* create a single UDP socket and bail out if an error occurs.
|
||||||
|
* This is called from a loop inside create_udp_socket which
|
||||||
|
* iterates through potentially multiple sockets. NOT to be
|
||||||
|
* used elsewhere.
|
||||||
|
*/
|
||||||
|
static rsRetVal ATTR_NONNULL(1, 2)
|
||||||
|
create_single_udp_socket(int *const s, /* socket */
|
||||||
|
struct addrinfo *const r,
|
||||||
|
const uchar *const hostname,
|
||||||
|
const int bIsServer,
|
||||||
|
const int rcvbuf,
|
||||||
|
const int sndbuf,
|
||||||
|
const int ipfreebind,
|
||||||
|
const char *const device
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const int on = 1;
|
||||||
|
int sockflags;
|
||||||
|
int actrcvbuf;
|
||||||
|
int actsndbuf;
|
||||||
|
socklen_t optlen;
|
||||||
|
char errStr[1024];
|
||||||
|
DEFiRet;
|
||||||
|
|
||||||
|
assert(r != NULL); // does NOT work with -O2 or higher due to ATTR_NONNULL!
|
||||||
|
assert(s != NULL);
|
||||||
|
|
||||||
|
# if defined (_AIX)
|
||||||
|
/* AIXPORT : socktype will be SOCK_DGRAM, as set in hints before */
|
||||||
|
*s = socket(r->ai_family, SOCK_DGRAM, r->ai_protocol);
|
||||||
|
# else
|
||||||
|
*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
|
||||||
|
# endif
|
||||||
|
if (*s < 0) {
|
||||||
|
if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT)) {
|
||||||
|
errmsg.LogError(errno, NO_ERRCODE, "create_udp_socket(), socket");
|
||||||
|
/* it is debateble if PF_INET with EAFNOSUPPORT should
|
||||||
|
* also be ignored...
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef IPV6_V6ONLY
|
||||||
|
if (r->ai_family == AF_INET6) {
|
||||||
|
int ion = 1;
|
||||||
|
if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||||
|
(char *)&ion, sizeof (ion)) < 0) {
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "error creating UDP socket - setsockopt");
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
if(device) {
|
||||||
|
# if defined(SO_BINDTODEVICE)
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) < 0)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "create UDP socket bound to device failed");
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) {
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "create UDP socket failed to set REUSEADDR");
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need to enable BSD compatibility. Otherwise an attacker
|
||||||
|
* could flood our log files by sending us tons of ICMP errors.
|
||||||
|
*/
|
||||||
|
/* AIXPORT : SO_BSDCOMPAT socket option is depricated, and its usage
|
||||||
|
* has been discontinued on most unixes, AIX does not support this option,
|
||||||
|
* hence avoid the call.
|
||||||
|
*/
|
||||||
|
# if !defined(OS_BSD) && !defined(__hpux) && !defined(_AIX)
|
||||||
|
if (should_use_so_bsdcompat()) {
|
||||||
|
if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT, (char *) &on, sizeof(on)) < 0) {
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "create UDP socket failed to set BSDCOMPAT");
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
if(bIsServer) {
|
||||||
|
DBGPRINTF("net.c: trying to set server socket %d to non-blocking mode\n", *s);
|
||||||
|
if ((sockflags = fcntl(*s, F_GETFL)) != -1) {
|
||||||
|
sockflags |= O_NONBLOCK;
|
||||||
|
/* SETFL could fail too, so get it caught by the subsequent
|
||||||
|
* error check.
|
||||||
|
*/
|
||||||
|
sockflags = fcntl(*s, F_SETFL, sockflags);
|
||||||
|
}
|
||||||
|
if (sockflags == -1) {
|
||||||
|
LogError(errno, RS_RET_ERR, "net.c: socket %d fcntl(O_NONBLOCK)", *s);
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sndbuf != 0) {
|
||||||
|
# if defined(SO_SNDBUFFORCE)
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_SNDBUFFORCE, &sndbuf, sizeof(sndbuf)) < 0)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
/* if we fail, try to do it the regular way. Experiments show that at
|
||||||
|
* least some platforms do not return an error here, but silently set
|
||||||
|
* it to the max permitted value. So we do our error check a bit
|
||||||
|
* differently by querying the size below.
|
||||||
|
*/
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) != 0) {
|
||||||
|
/* keep Coverity happy */
|
||||||
|
DBGPRINTF("setsockopt in %s:%d failed - this is expected and "
|
||||||
|
"handled at later stages\n", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* report socket buffer sizes */
|
||||||
|
optlen = sizeof(actsndbuf);
|
||||||
|
if(getsockopt(*s, SOL_SOCKET, SO_SNDBUF, &actsndbuf, &optlen) == 0) {
|
||||||
|
LogMsg(0, NO_ERRCODE, LOG_INFO,
|
||||||
|
"socket %d, actual os socket sndbuf size is %d", *s, actsndbuf);
|
||||||
|
if(sndbuf != 0 && actsndbuf/2 != sndbuf) {
|
||||||
|
errmsg.LogError(errno, NO_ERRCODE,
|
||||||
|
"could not set os socket sndbuf size %d for socket %d, "
|
||||||
|
"value now is %d", sndbuf, *s, actsndbuf/2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DBGPRINTF("could not obtain os socket rcvbuf size for socket %d: %s\n",
|
||||||
|
*s, rs_strerror_r(errno, errStr, sizeof(errStr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(rcvbuf != 0) {
|
||||||
|
# if defined(SO_RCVBUFFORCE)
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof(rcvbuf)) < 0)
|
||||||
|
# endif
|
||||||
|
{
|
||||||
|
/* if we fail, try to do it the regular way. Experiments show that at
|
||||||
|
* least some platforms do not return an error here, but silently set
|
||||||
|
* it to the max permitted value. So we do our error check a bit
|
||||||
|
* differently by querying the size below.
|
||||||
|
*/
|
||||||
|
if(setsockopt(*s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) != 0) {
|
||||||
|
/* keep Coverity happy */
|
||||||
|
DBGPRINTF("setsockopt in %s:%d failed - this is expected and "
|
||||||
|
"handled at later stages\n", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
optlen = sizeof(actrcvbuf);
|
||||||
|
if(getsockopt(*s, SOL_SOCKET, SO_RCVBUF, &actrcvbuf, &optlen) == 0) {
|
||||||
|
LogMsg(0, NO_ERRCODE, LOG_INFO,
|
||||||
|
"socket %d, actual os socket rcvbuf size %d\n", *s, actrcvbuf);
|
||||||
|
if(rcvbuf != 0 && actrcvbuf/2 != rcvbuf) {
|
||||||
|
errmsg.LogError(errno, NO_ERRCODE,
|
||||||
|
"cannot set os socket rcvbuf size %d for socket %d, value now is %d",
|
||||||
|
rcvbuf, *s, actrcvbuf/2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DBGPRINTF("could not obtain os socket rcvbuf size for socket %d: %s\n",
|
||||||
|
*s, rs_strerror_r(errno, errStr, sizeof(errStr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bIsServer) {
|
||||||
|
/* rgerhards, 2007-06-22: if we run on a kernel that does not support
|
||||||
|
* the IPV6_V6ONLY socket option, we need to use a work-around. On such
|
||||||
|
* systems the IPv6 socket does also accept IPv4 sockets. So an IPv4
|
||||||
|
* socket can not listen on the same port as an IPv6 socket. The only
|
||||||
|
* workaround is to ignore the "socket in use" error. This is what we
|
||||||
|
* do if we have to.
|
||||||
|
*/
|
||||||
|
if( (bind(*s, r->ai_addr, r->ai_addrlen) < 0)
|
||||||
|
# ifndef IPV6_V6ONLY
|
||||||
|
&& (errno != EADDRINUSE)
|
||||||
|
# endif
|
||||||
|
) {
|
||||||
|
if (errno == EADDRNOTAVAIL && ipfreebind != IPFREEBIND_DISABLED) {
|
||||||
|
if (setsockopt(*s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) {
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "setsockopt(IP_FREEBIND)");
|
||||||
|
} else if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
|
||||||
|
errmsg.LogError(errno, RS_RET_ERR, "bind with IP_FREEBIND");
|
||||||
|
} else {
|
||||||
|
if (ipfreebind >= IPFREEBIND_ENABLED_WITH_LOG)
|
||||||
|
errmsg.LogMsg(0, RS_RET_OK_WARN, LOG_WARNING,
|
||||||
|
"bound address %s IP free", hostname);
|
||||||
|
//FINALIZE; TODO: activate this (issue 2040) BUT ensure first
|
||||||
|
// that the option is actually configurable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ABORT_FINALIZE(RS_RET_ERR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
finalize_it:
|
||||||
|
if(iRet != RS_RET_OK) {
|
||||||
|
close(*s);
|
||||||
|
*s = -1;
|
||||||
|
}
|
||||||
|
RETiRet;
|
||||||
|
}
|
||||||
|
|
||||||
/* creates the UDP listen sockets
|
/* creates the UDP listen sockets
|
||||||
* hostname and/or pszPort may be NULL, but not both!
|
* hostname and/or pszPort may be NULL, but not both!
|
||||||
* bIsServer indicates if a server socket should be created
|
* bIsServer indicates if a server socket should be created
|
||||||
@ -1264,21 +1464,17 @@ closeUDPListenSockets(int *pSockArr)
|
|||||||
static int *
|
static int *
|
||||||
create_udp_socket(uchar *hostname,
|
create_udp_socket(uchar *hostname,
|
||||||
uchar *pszPort,
|
uchar *pszPort,
|
||||||
int bIsServer,
|
const int bIsServer,
|
||||||
int rcvbuf,
|
const int rcvbuf,
|
||||||
const int sndbuf,
|
const int sndbuf,
|
||||||
int ipfreebind,
|
const int ipfreebind,
|
||||||
char *device)
|
char *device)
|
||||||
{
|
{
|
||||||
struct addrinfo hints, *res, *r;
|
struct addrinfo hints, *res, *r;
|
||||||
int error, maxs, *s, *socks, on = 1;
|
int error, maxs, *s, *socks;
|
||||||
int sockflags;
|
rsRetVal localRet;
|
||||||
int actrcvbuf;
|
|
||||||
int actsndbuf;
|
|
||||||
socklen_t optlen;
|
|
||||||
char errStr[1024];
|
|
||||||
|
|
||||||
assert(!((pszPort == NULL) && (hostname == NULL)));
|
assert(!((pszPort == NULL) && (hostname == NULL))); /* one of them must be non-NULL */
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
if(bIsServer)
|
if(bIsServer)
|
||||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
|
hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV;
|
||||||
@ -1286,12 +1482,12 @@ create_udp_socket(uchar *hostname,
|
|||||||
hints.ai_flags = AI_NUMERICSERV;
|
hints.ai_flags = AI_NUMERICSERV;
|
||||||
hints.ai_family = glbl.GetDefPFFamily();
|
hints.ai_family = glbl.GetDefPFFamily();
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
#if defined (_AIX)
|
# if defined (_AIX)
|
||||||
/* AIXPORT : SOCK_DGRAM has the protocol IPPROTO_UDP
|
/* AIXPORT : SOCK_DGRAM has the protocol IPPROTO_UDP
|
||||||
* getaddrinfo needs this hint on AIX
|
* getaddrinfo needs this hint on AIX
|
||||||
*/
|
*/
|
||||||
hints.ai_protocol = IPPROTO_UDP;
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
#endif
|
# endif
|
||||||
error = getaddrinfo((char*) hostname, (char*) pszPort, &hints, &res);
|
error = getaddrinfo((char*) hostname, (char*) pszPort, &hints, &res);
|
||||||
if(error) {
|
if(error) {
|
||||||
errmsg.LogError(0, NO_ERRCODE, "%s", gai_strerror(error));
|
errmsg.LogError(0, NO_ERRCODE, "%s", gai_strerror(error));
|
||||||
@ -1304,202 +1500,21 @@ create_udp_socket(uchar *hostname,
|
|||||||
/* EMPTY */;
|
/* EMPTY */;
|
||||||
socks = MALLOC((maxs+1) * sizeof(int));
|
socks = MALLOC((maxs+1) * sizeof(int));
|
||||||
if (socks == NULL) {
|
if (socks == NULL) {
|
||||||
errmsg.LogError(0, NO_ERRCODE, "couldn't allocate memory for UDP sockets, suspending UDP "
|
errmsg.LogError(0, RS_RET_OUT_OF_MEMORY, "couldn't allocate memory for UDP "
|
||||||
"message reception");
|
"sockets, suspending UDP message reception");
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*socks = 0; /* num of sockets counter at start of array */
|
*socks = 0; /* num of sockets counter at start of array */
|
||||||
s = socks + 1;
|
s = socks + 1;
|
||||||
for (r = res; r != NULL ; r = r->ai_next) {
|
for (r = res; r != NULL ; r = r->ai_next) {
|
||||||
#if defined (_AIX)
|
localRet = create_single_udp_socket(s, r, hostname, bIsServer, rcvbuf,
|
||||||
/* AIXPORT : socktype will be SOCK_DGRAM, as set in hints above */
|
sndbuf, ipfreebind, device);
|
||||||
*s = socket(r->ai_family, SOCK_DGRAM, r->ai_protocol);
|
if(localRet == RS_RET_OK) {
|
||||||
#else
|
(*socks)++;
|
||||||
*s = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
|
s++;
|
||||||
#endif
|
|
||||||
if (*s < 0) {
|
|
||||||
if(!(r->ai_family == PF_INET6 && errno == EAFNOSUPPORT))
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "create_udp_socket(), socket");
|
|
||||||
/* it is debateble if PF_INET with EAFNOSUPPORT should
|
|
||||||
* also be ignored...
|
|
||||||
*/
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef IPV6_V6ONLY
|
|
||||||
if (r->ai_family == AF_INET6) {
|
|
||||||
int ion = 1;
|
|
||||||
if (setsockopt(*s, IPPROTO_IPV6, IPV6_V6ONLY,
|
|
||||||
(char *)&ion, sizeof (ion)) < 0) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "setsockopt");
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
if(device) {
|
|
||||||
# if defined(SO_BINDTODEVICE)
|
|
||||||
if(setsockopt(*s, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device) + 1) < 0)
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "setsockopt(SO_BINDTODEVICE)");
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if we have an error, we "just" suspend that socket. Eventually
|
|
||||||
* other sockets will work. At the end of this function, we check
|
|
||||||
* if we managed to open at least one socket. If not, we'll write
|
|
||||||
* a "inet suspended" message and declare failure. Else we use
|
|
||||||
* what we could obtain.
|
|
||||||
* rgerhards, 2007-06-22
|
|
||||||
*/
|
|
||||||
if (setsockopt(*s, SOL_SOCKET, SO_REUSEADDR,
|
|
||||||
(char *) &on, sizeof(on)) < 0 ) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "setsockopt(REUSEADDR)");
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We need to enable BSD compatibility. Otherwise an attacker
|
|
||||||
* could flood our log files by sending us tons of ICMP errors.
|
|
||||||
*/
|
|
||||||
/* AIXPORT : SO_BSDCOMPAT socket option is depricated , and its usage has been discontinued
|
|
||||||
on most unixes, AIX does not support this option , hence avoid the call.
|
|
||||||
*/
|
|
||||||
#if !defined(OS_BSD) && !defined(__hpux) && !defined(_AIX)
|
|
||||||
if (should_use_so_bsdcompat()) {
|
|
||||||
if (setsockopt(*s, SOL_SOCKET, SO_BSDCOMPAT,
|
|
||||||
(char *) &on, sizeof(on)) < 0) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "setsockopt(BSDCOMPAT)");
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if(bIsServer) {
|
|
||||||
DBGPRINTF("net.c: trying to set server socket %d to non-blocking mode\n", *s);
|
|
||||||
if ((sockflags = fcntl(*s, F_GETFL)) != -1) {
|
|
||||||
sockflags |= O_NONBLOCK;
|
|
||||||
/* SETFL could fail too, so get it caught by the subsequent
|
|
||||||
* error check.
|
|
||||||
*/
|
|
||||||
sockflags = fcntl(*s, F_SETFL, sockflags);
|
|
||||||
}
|
|
||||||
if (sockflags == -1) {
|
|
||||||
LogError(errno, NO_ERRCODE, "net.c: socket %d fcntl(O_NONBLOCK)", *s);
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sndbuf != 0) {
|
|
||||||
# if defined(SO_SNDBUFFORCE)
|
|
||||||
if(setsockopt(*s, SOL_SOCKET, SO_SNDBUFFORCE, &sndbuf, sizeof(sndbuf)) < 0)
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
/* if we fail, try to do it the regular way. Experiments show that at
|
|
||||||
* least some platforms do not return an error here, but silently set
|
|
||||||
* it to the max permitted value. So we do our error check a bit
|
|
||||||
* differently by querying the size below.
|
|
||||||
*/
|
|
||||||
if(setsockopt(*s, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)) != 0) {
|
|
||||||
/* keep Coverity happy */
|
|
||||||
DBGPRINTF("setsockopt in %s:%d failed - this is expected and "
|
|
||||||
"handled at later stages\n", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* report socket buffer sizes */
|
|
||||||
optlen = sizeof(actsndbuf);
|
|
||||||
if(getsockopt(*s, SOL_SOCKET, SO_SNDBUF, &actsndbuf, &optlen) == 0) {
|
|
||||||
LogMsg(0, NO_ERRCODE, LOG_INFO,
|
|
||||||
"socket %d, actual os socket sndbuf size is %d", *s, actsndbuf);
|
|
||||||
if(sndbuf != 0 && actsndbuf/2 != sndbuf) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE,
|
|
||||||
"could not set os socket sndbuf size %d for socket %d, "
|
|
||||||
"value now is %d", sndbuf, *s, actsndbuf/2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBGPRINTF("could not obtain os socket rcvbuf size for socket %d: %s\n",
|
|
||||||
*s, rs_strerror_r(errno, errStr, sizeof(errStr)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(rcvbuf != 0) {
|
|
||||||
# if defined(SO_RCVBUFFORCE)
|
|
||||||
if(setsockopt(*s, SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf, sizeof(rcvbuf)) < 0)
|
|
||||||
# endif
|
|
||||||
{
|
|
||||||
/* if we fail, try to do it the regular way. Experiments show that at
|
|
||||||
* least some platforms do not return an error here, but silently set
|
|
||||||
* it to the max permitted value. So we do our error check a bit
|
|
||||||
* differently by querying the size below.
|
|
||||||
*/
|
|
||||||
if(setsockopt(*s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) != 0) {
|
|
||||||
/* keep Coverity happy */
|
|
||||||
DBGPRINTF("setsockopt in %s:%d failed - this is expected and "
|
|
||||||
"handled at later stages\n", __FILE__, __LINE__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
optlen = sizeof(actrcvbuf);
|
|
||||||
if(getsockopt(*s, SOL_SOCKET, SO_RCVBUF, &actrcvbuf, &optlen) == 0) {
|
|
||||||
LogMsg(0, NO_ERRCODE, LOG_INFO,
|
|
||||||
"socket %d, actual os socket rcvbuf size %d\n", *s, actrcvbuf);
|
|
||||||
if(rcvbuf != 0 && actrcvbuf/2 != rcvbuf) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE,
|
|
||||||
"cannot set os socket rcvbuf size %d for socket %d, value now is %d",
|
|
||||||
rcvbuf, *s, actrcvbuf/2);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBGPRINTF("could not obtain os socket rcvbuf size for socket %d: %s\n",
|
|
||||||
*s, rs_strerror_r(errno, errStr, sizeof(errStr)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bIsServer) {
|
|
||||||
|
|
||||||
/* rgerhards, 2007-06-22: if we run on a kernel that does not support
|
|
||||||
* the IPV6_V6ONLY socket option, we need to use a work-around. On such
|
|
||||||
* systems the IPv6 socket does also accept IPv4 sockets. So an IPv4
|
|
||||||
* socket can not listen on the same port as an IPv6 socket. The only
|
|
||||||
* workaround is to ignore the "socket in use" error. This is what we
|
|
||||||
* do if we have to.
|
|
||||||
*/
|
|
||||||
if( (bind(*s, r->ai_addr, r->ai_addrlen) < 0)
|
|
||||||
# ifndef IPV6_V6ONLY
|
|
||||||
&& (errno != EADDRINUSE)
|
|
||||||
# endif
|
|
||||||
) {
|
|
||||||
if (errno == EADDRNOTAVAIL && ipfreebind != IPFREEBIND_DISABLED) {
|
|
||||||
if (setsockopt(*s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)) < 0) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "setsockopt(IP_FREEBIND)");
|
|
||||||
}
|
|
||||||
else if (bind(*s, r->ai_addr, r->ai_addrlen) < 0) {
|
|
||||||
errmsg.LogError(errno, NO_ERRCODE, "bind with IP_FREEBIND");
|
|
||||||
} else {
|
|
||||||
if (ipfreebind >= IPFREEBIND_ENABLED_WITH_LOG)
|
|
||||||
errmsg.LogMsg(0, RS_RET_OK_WARN, LOG_WARNING,
|
|
||||||
"bound address %s IP free", hostname);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(*s);
|
|
||||||
*s = -1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(*socks)++;
|
|
||||||
s++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(res != NULL)
|
if(res != NULL)
|
||||||
@ -1512,7 +1527,7 @@ create_udp_socket(uchar *hostname,
|
|||||||
if(*socks == 0) {
|
if(*socks == 0) {
|
||||||
errmsg.LogError(0, NO_ERRCODE, "No UDP socket could successfully be initialized, "
|
errmsg.LogError(0, NO_ERRCODE, "No UDP socket could successfully be initialized, "
|
||||||
"some functionality may be disabled.\n");
|
"some functionality may be disabled.\n");
|
||||||
/* we do NOT need to free any sockets, because there were none... */
|
/* we do NOT need to close any sockets, because there were none... */
|
||||||
free(socks);
|
free(socks);
|
||||||
return(NULL);
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user