Skip to content

Commit 2ee60e0

Browse files
committed
MB-28629: Improve logging when failing to set up server socket
Previously we did not print out which port we failed to configure during startup. Instead the log looked like: INFO Enable management port(s) INFO Enable user port(s) CRITICAL Failed to create listening socket This patch extends this to: INFO Enable management port(s) INFO Enable user port(s) CRITICAL Failed to create IPv4 port for "*":11210 CRITICAL Failed to create IPv6 port for "*":11210 CRITICAL Failed to create listening socket This gives deeper insight in why we failed to start. It is still considered a fatal error if we fail to create all ports specified by ns_server as we don't really have a way to tell ns_server which port we failed to set up (and it can't tell us to try again). Change-Id: I35dbdc23f4dae08a9f196b113d11bd1b8e184c9a Reviewed-on: http://review.couchbase.org/90791 Reviewed-by: Dave Rigby <[email protected]> Tested-by: Build Bot <[email protected]>
1 parent 41f62c7 commit 2ee60e0

File tree

1 file changed

+79
-41
lines changed

1 file changed

+79
-41
lines changed

daemon/memcached.cc

Lines changed: 79 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,31 +1266,38 @@ static void add_listening_port(const NetworkInterface *interf, in_port_t port, s
12661266
/**
12671267
* Create a socket and bind it to a specific port number
12681268
* @param interface the interface to bind to
1269-
* @param port the port number to bind to
1269+
* @param true if we was able to set up this interface
1270+
* false if we failed to set up this interface
12701271
*/
1271-
static int server_socket(const NetworkInterface *interf) {
1272+
static bool server_socket(const NetworkInterface& interf) {
12721273
SOCKET sfd;
1273-
struct addrinfo hints;
1274-
int success = 0;
1275-
const char *host = NULL;
1274+
addrinfo hints = {};
1275+
1276+
// Set to true when we create an IPv4 interface
1277+
bool ipv4 = false;
1278+
// Set to true when we create an IPv6 interface
1279+
bool ipv6 = false;
12761280

1277-
memset(&hints, 0, sizeof(hints));
12781281
hints.ai_flags = AI_PASSIVE;
12791282
hints.ai_protocol = IPPROTO_TCP;
12801283
hints.ai_socktype = SOCK_STREAM;
12811284

1282-
if (interf->ipv4 && interf->ipv6) {
1285+
if (interf.ipv4 && interf.ipv6) {
12831286
hints.ai_family = AF_UNSPEC;
1284-
} else if (interf->ipv4) {
1287+
} else if (interf.ipv4) {
12851288
hints.ai_family = AF_INET;
1286-
} else if (interf->ipv6) {
1289+
} else if (interf.ipv6) {
12871290
hints.ai_family = AF_INET6;
1291+
} else {
1292+
throw std::invalid_argument(
1293+
"server_socket: can't create a socket without IPv4 or IPv6");
12881294
}
12891295

1290-
std::string port_buf = std::to_string(interf->port);
1296+
std::string port_buf = std::to_string(interf.port);
12911297

1292-
if (!interf->host.empty() && interf->host != "*") {
1293-
host = interf->host.c_str();
1298+
const char* host = nullptr;
1299+
if (!interf.host.empty() && interf.host != "*") {
1300+
host = interf.host.c_str();
12941301
}
12951302

12961303
struct addrinfo *ai;
@@ -1305,32 +1312,37 @@ static int server_socket(const NetworkInterface *interf) {
13051312
LOG_WARNING("getaddrinfo(): {}", cb_strerror(error));
13061313
}
13071314
#endif
1308-
return 1;
1315+
return false;
13091316
}
13101317

1318+
// getaddrinfo may return multiple entries for a given name/port pair.
1319+
// Iterate over all of them and try to set up a listen object.
1320+
// We need at least _one_ entry per requested configuration (IPv4/6) in
1321+
// order to call it a success.
13111322
for (struct addrinfo* next = ai; next; next = next->ai_next) {
1312-
if ((sfd = new_server_socket(next, interf->tcp_nodelay)) == INVALID_SOCKET) {
1313-
/* getaddrinfo can return "junk" addresses,
1314-
* we make sure at least one works before erroring.
1315-
*/
1323+
if ((sfd = new_server_socket(next, interf.tcp_nodelay)) ==
1324+
INVALID_SOCKET) {
1325+
// getaddrinfo can return "junk" addresses,
13161326
continue;
13171327
}
13181328

13191329
in_port_t listenport = 0;
13201330
if (bind(sfd, next->ai_addr, (socklen_t)next->ai_addrlen) == SOCKET_ERROR) {
1321-
error = cb::net::get_socket_error();
1322-
if (!cb::net::is_addrinuse(error)) {
1323-
LOG_WARNING("Failed to bind to address: {}",
1324-
cb_strerror(error));
1325-
safe_close(sfd);
1326-
freeaddrinfo(ai);
1327-
return 1;
1328-
}
1331+
LOG_WARNING("Failed to bind to address: {}",
1332+
cb_strerror(cb::net::get_socket_error()));
13291333
safe_close(sfd);
13301334
continue;
13311335
}
13321336

1333-
success++;
1337+
// We've configured this port.
1338+
if (next->ai_addr->sa_family == AF_INET) {
1339+
// We have at least one entry
1340+
ipv4 = true;
1341+
} else if (next->ai_addr->sa_family == AF_INET6) {
1342+
// We have at least one entry
1343+
ipv6 = true;
1344+
}
1345+
13341346
if (next->ai_addr->sa_family == AF_INET ||
13351347
next->ai_addr->sa_family == AF_INET6) {
13361348
union {
@@ -1347,28 +1359,50 @@ static int server_socket(const NetworkInterface *interf) {
13471359
}
13481360
}
13491361

1350-
auto* lconn = conn_new_server(sfd, listenport, next->ai_addr->sa_family,
1351-
*interf, main_base);
1362+
auto* lconn = conn_new_server(
1363+
sfd, listenport, next->ai_addr->sa_family, interf, main_base);
13521364
if (lconn == nullptr) {
1353-
FATAL_ERROR(EXIT_FAILURE, "Failed to create listening connection");
1365+
FATAL_ERROR(
1366+
EXIT_FAILURE,
1367+
R"(Failed to create listening object: Host "{}" Port "{}" IPv{})",
1368+
interf.host.empty() ? "*" : interf.host,
1369+
interf.port,
1370+
next->ai_addr->sa_family == AF_INET ? "4" : "6");
13541371
}
13551372

13561373
lconn->setNext(listen_conn);
13571374
listen_conn = lconn;
13581375

13591376
stats.daemon_conns++;
13601377
stats.curr_conns.fetch_add(1, std::memory_order_relaxed);
1361-
add_listening_port(interf, listenport, next->ai_addr->sa_family);
1378+
add_listening_port(&interf, listenport, next->ai_addr->sa_family);
13621379
}
13631380

13641381
freeaddrinfo(ai);
13651382

1366-
/* Return zero iff we detected no errors in starting up connections */
1367-
return success == 0;
1383+
bool ret = true;
1384+
1385+
if (interf.ipv4 && !ipv4) {
1386+
// Failed to create an IPv4 port
1387+
LOG_CRITICAL(R"(Failed to create IPv4 port for "{}:{}")",
1388+
interf.host.empty() ? "*" : interf.host,
1389+
interf.port);
1390+
ret = false;
1391+
}
1392+
1393+
if (interf.ipv6 && !ipv6) {
1394+
// Failed to create an IPv6 oprt
1395+
LOG_CRITICAL(R"(Failed to create IPv6 port for "{}:{}")",
1396+
interf.host.empty() ? "*" : interf.host,
1397+
interf.port);
1398+
ret = false;
1399+
}
1400+
1401+
return ret;
13681402
}
13691403

1370-
static int server_sockets(bool management) {
1371-
int ret = 0;
1404+
static bool server_sockets(bool management) {
1405+
bool success = true;
13721406

13731407
if (management) {
13741408
LOG_INFO("Enable management port(s)");
@@ -1378,25 +1412,29 @@ static int server_sockets(bool management) {
13781412

13791413
for (auto& interface : settings.getInterfaces()) {
13801414
if (management && interface.management) {
1381-
ret |= server_socket(&interface);
1415+
if (!server_socket(interface)) {
1416+
success = false;
1417+
}
13821418
} else if (!management && !interface.management) {
1383-
ret |= server_socket(&interface);
1419+
if (!server_socket(interface)) {
1420+
success = false;
1421+
}
13841422
}
13851423
}
13861424

1387-
return ret;
1425+
return success;
13881426
}
13891427

13901428
static void create_listen_sockets(bool management) {
1391-
if (server_sockets(management)) {
1392-
FATAL_ERROR(EX_OSERR, "Failed to create listening socket");
1429+
if (!server_sockets(management)) {
1430+
FATAL_ERROR(EX_OSERR, "Failed to create listening socket(s)");
13931431
}
13941432

13951433
if (management) {
13961434
// the client is not expecting us to update the port set at
13971435
// later time, so enable all ports immediately
1398-
if (server_sockets(false)) {
1399-
FATAL_ERROR(EX_OSERR, "Failed to create listening socket");
1436+
if (!server_sockets(false)) {
1437+
FATAL_ERROR(EX_OSERR, "Failed to create listening socket(s)");
14001438
}
14011439
}
14021440

0 commit comments

Comments
 (0)