Usually, for passive sockets, one wishes to bind a particular well-known
port, so that clients can easily connect. But automated tests cannot
necessarily bind a well-known port, because that would cause multiple
concurrent tests to interfere with each other or with a real instance of
the service running on the system. They could bind to a randomly selected
port chosen by the user (the Open vSwitch automated tests currently do this)
but this leads to occasional "false negative" test failures when the port
selected happens to be in use.
The best alternative for automated tests is to let the kernel choose a
port that is not otherwise in use, which can be accomplished by specifying
port 0. But in that case there is no easy way for other software to know
what port the kernel chose. This commit fixes that problem one way by
logging the bound port when it is chosen by the kernel.
Signed-off-by: Ben Pfaff <blp@nicira.com>
- * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
inet_open_passive(int style, const char *target, int default_port,
struct sockaddr_in *sinp, uint8_t dscp)
{
inet_open_passive(int style, const char *target, int default_port,
struct sockaddr_in *sinp, uint8_t dscp)
{
+ bool kernel_chooses_port;
struct sockaddr_in sin;
int fd = 0, error;
unsigned int yes = 1;
struct sockaddr_in sin;
int fd = 0, error;
unsigned int yes = 1;
+ kernel_chooses_port = sin.sin_port == htons(0);
+ if (sinp || kernel_chooses_port) {
socklen_t sin_len = sizeof sin;
socklen_t sin_len = sizeof sin;
- if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0){
+ if (getsockname(fd, (struct sockaddr *) &sin, &sin_len) < 0) {
error = errno;
VLOG_ERR("%s: getsockname: %s", target, strerror(error));
goto error;
error = errno;
VLOG_ERR("%s: getsockname: %s", target, strerror(error));
goto error;
VLOG_ERR("%s: getsockname: invalid socket name", target);
goto error;
}
VLOG_ERR("%s: getsockname: invalid socket name", target);
goto error;
}
+ if (sinp) {
+ *sinp = sin;
+ }
+ if (kernel_chooses_port) {
+ VLOG_INFO("%s: listening on port %"PRIu16,
+ target, ntohs(sin.sin_port));
+ }