Skip to content
Snippets Groups Projects
Commit a5214bfc authored by Lev Kats's avatar Lev Kats Committed by Serge Petrenko
Browse files

sio: fix error message displaying bind address

Now `sio_bind` function prints address into error message directly
instead of relying on `fd` used in `bind` that failed to execute.

`sio_bind` used `sio_socketname_to_buffer` for error message
effectively attempting printing address bound to `fd` while there
actually was an error in binding that address to that socket in the
first place.

Fixes #5925

NO_DOC=bugfix
NO_CHANGELOG=minor
parent 06b87e27
No related branches found
No related tags found
No related merge requests found
...@@ -55,38 +55,49 @@ static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV, ...@@ -55,38 +55,49 @@ static_assert(SMALL_STATIC_SIZE > NI_MAXHOST + NI_MAXSERV,
* checks and all. * checks and all.
*/ */
static int static int
sio_socketname_to_buffer(int fd, char *buf, int size) sio_socketname_to_buffer(int fd,
const struct sockaddr *base_addr, socklen_t addrlen,
const struct sockaddr *peer_addr, socklen_t peerlen,
char *buf, int size)
{ {
int n = 0; int n = 0;
(void)n; (void)n;
SNPRINT(n, snprintf, buf, size, "fd %d", fd); SNPRINT(n, snprintf, buf, size, "fd %d", fd);
if (fd < 0) if (fd < 0)
return 0; return 0;
struct sockaddr_storage addr; if (base_addr != NULL) {
socklen_t addrlen = sizeof(addr);
struct sockaddr *base_addr = (struct sockaddr *)&addr;
int rc = getsockname(fd, base_addr, &addrlen);
if (rc == 0) {
SNPRINT(n, snprintf, buf, size, ", aka "); SNPRINT(n, snprintf, buf, size, ", aka ");
SNPRINT(n, sio_addr_snprintf, buf, size, base_addr, addrlen); SNPRINT(n, sio_addr_snprintf, buf, size, base_addr, addrlen);
} }
addrlen = sizeof(addr); if (peer_addr != NULL) {
rc = getpeername(fd, (struct sockaddr *) &addr, &addrlen);
if (rc == 0) {
SNPRINT(n, snprintf, buf, size, ", peer of "); SNPRINT(n, snprintf, buf, size, ", peer of ");
SNPRINT(n, sio_addr_snprintf, buf, size, base_addr, addrlen); SNPRINT(n, sio_addr_snprintf, buf, size,
peer_addr, peerlen);
} }
return 0; return 0;
} }
const char * const char *
sio_socketname(int fd) sio_socketname_addr(int fd, const struct sockaddr *base_addr,
socklen_t addrlen)
{ {
/* Preserve errno */ /* Preserve errno */
int save_errno = errno; int save_errno = errno;
int name_size = SERVICE_NAME_MAXLEN; int name_size = SERVICE_NAME_MAXLEN;
char *name = static_alloc(name_size); char *name = static_alloc(name_size);
int rc = sio_socketname_to_buffer(fd, name, name_size);
struct sockaddr_storage peer_addr_storage;
socklen_t peerlen = sizeof(peer_addr_storage);
struct sockaddr *peer_addr = (struct sockaddr *)&peer_addr_storage;
int rcp = getpeername(fd, peer_addr, &peerlen);
if (rcp != 0) {
peer_addr = NULL;
}
int rc = sio_socketname_to_buffer(fd,
base_addr, addrlen,
peer_addr, peerlen,
name, name_size);
/* /*
* Could fail only because of a bad format in snprintf, but it is not * Could fail only because of a bad format in snprintf, but it is not
* bad, so should not fail. * bad, so should not fail.
...@@ -101,6 +112,29 @@ sio_socketname(int fd) ...@@ -101,6 +112,29 @@ sio_socketname(int fd)
return name; return name;
} }
const char *
sio_socketname(int fd)
{
/* Preserve errno */
int save_errno = errno;
struct sockaddr_storage addr;
socklen_t addrlen = sizeof(addr);
struct sockaddr *base_addr = (struct sockaddr *)&addr;
int rcb = getsockname(fd, base_addr, &addrlen);
if (rcb != 0) {
base_addr = NULL;
}
const char *name = sio_socketname_addr(fd, base_addr, addrlen);
/*
* Restore the original errno, it might have been reset by
* getsockname().
*/
errno = save_errno;
return name;
}
/** Get a string representation of a socket option name, /** Get a string representation of a socket option name,
* for logging. * for logging.
*/ */
...@@ -245,7 +279,9 @@ sio_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) ...@@ -245,7 +279,9 @@ sio_bind(int fd, const struct sockaddr *addr, socklen_t addrlen)
{ {
int rc = bind(fd, addr, addrlen); int rc = bind(fd, addr, addrlen);
if (rc < 0) if (rc < 0)
diag_set(SocketError, sio_socketname(fd), "bind"); diag_set(SocketError,
sio_socketname_addr(fd, addr, addrlen),
"bind");
return rc; return rc;
} }
......
...@@ -236,6 +236,16 @@ ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags, ...@@ -236,6 +236,16 @@ ssize_t sio_recvfrom(int fd, void *buf, size_t len, int flags,
int int
sio_uri_to_addr(const char *uri, struct sockaddr *addr, bool *is_host_empty); sio_uri_to_addr(const char *uri, struct sockaddr *addr, bool *is_host_empty);
/* internals, for unit testing */
/**
* Return a string containing fd, base address and peer from arguments.
* Used mostly in error messages.
*/
const char *
sio_socketname_addr(int fd, const struct sockaddr *base_addr,
socklen_t addrlen);
#if defined(__cplusplus) #if defined(__cplusplus)
} /* extern "C" */ } /* extern "C" */
#endif /* defined(__cplusplus) */ #endif /* defined(__cplusplus) */
......
...@@ -89,6 +89,32 @@ check_uri_to_addr(void) ...@@ -89,6 +89,32 @@ check_uri_to_addr(void)
footer(); footer();
} }
static void
check_sio_socketname_addr(void)
{
header();
plan(2);
struct sockaddr_storage base_storage;
struct sockaddr *base_addr = (struct sockaddr *)&base_storage;
socklen_t addrlen = sizeof(base_storage);
bool is_host_empty;
char base_addr_str[] = "192.0.2.255:1";
sio_uri_to_addr(base_addr_str, base_addr, &is_host_empty);
const char *name = sio_socketname_addr(-3,
base_addr, addrlen);
is_str(name, "fd -3", "works for invalid fd");
name = sio_socketname_addr(3, base_addr, addrlen);
char expectedbase[] = "fd 3, aka 192.0.2.255:1";
is_str(name, expectedbase, "works for fd and base_addr only");
check_plan();
footer();
}
static void static void
check_auto_bind(void) check_auto_bind(void)
{ {
...@@ -118,9 +144,10 @@ main(void) ...@@ -118,9 +144,10 @@ main(void)
fiber_init(fiber_c_invoke); fiber_init(fiber_c_invoke);
header(); header();
plan(2); plan(3);
check_uri_to_addr(); check_uri_to_addr();
check_auto_bind(); check_auto_bind();
check_sio_socketname_addr();
int rc = check_plan(); int rc = check_plan();
footer(); footer();
......
...@@ -118,6 +118,8 @@ int check_plan(void); ...@@ -118,6 +118,8 @@ int check_plan(void);
#define is(a, b, ...) _ok0((a) == (b), #a " == " #b, ##__VA_ARGS__) #define is(a, b, ...) _ok0((a) == (b), #a " == " #b, ##__VA_ARGS__)
#define isnt(a, b, ...) _ok0((a) != (b), #a " != " #b, ##__VA_ARGS__) #define isnt(a, b, ...) _ok0((a) != (b), #a " != " #b, ##__VA_ARGS__)
#define is_str(a, b, fmt, args...) ok(strcmp(a, b) == 0, fmt, ##args)
#if UNIT_TAP_COMPATIBLE #if UNIT_TAP_COMPATIBLE
#define header() \ #define header() \
......
...@@ -10,8 +10,6 @@ ...@@ -10,8 +10,6 @@
#define URI_PARAM_MAX 10 #define URI_PARAM_MAX 10
#define URI_PARAM_VALUE_MAX 10 #define URI_PARAM_VALUE_MAX 10
#define is_str(a, b, fmt, args...) ok(strcmp(a, b) == 0, fmt, ##args)
static void static void
sample_uri_create(struct uri *uri) sample_uri_create(struct uri *uri)
{ {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment