Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -5174,6 +5174,53 @@ char *xstrdup(const char *string)
return p;
}

/* Try to connect to addr, using select() for timeout since AF_UNIX won't timeout normally */
#ifndef WIN32
int select_connect(int fd, const struct sockaddr_un *addr, size_t addrlen, const time_t d_sec, const suseconds_t d_usec)
{
int rc;
int err = 0;
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

rc = connect(fd, (const struct sockaddr *)addr, addrlen);
if (rc == -1 && errno != EINPROGRESS) {
err = errno;
} else if (rc == -1) {
fd_set w_fds;
fd_set e_fds;
struct timeval tv;

FD_ZERO(&w_fds);
FD_SET(fd, &w_fds);
FD_ZERO(&e_fds);
FD_SET(fd, &e_fds);

tv.tv_sec = d_sec;
tv.tv_usec = d_usec;

rc = select(fd + 1, NULL, &w_fds, &e_fds, &tv);

if (rc < 0) {
err = errno;
} else if (rc == 0) {
err = ETIMEDOUT;
} else {
socklen_t len = sizeof(err);
getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
}
}

fcntl(fd, F_SETFL, flags);

if (err != 0) {
errno = err;
return -1;
}
return 0;
}
#endif

/* Read up to buflen bytes from fd and return the number of bytes
read. If no data is available within d_sec + d_usec, return 0.
On error, a value < 0 is returned (errno indicates error). */
Expand Down
2 changes: 1 addition & 1 deletion drivers/upsdrvquery.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ udq_pipe_conn_t *upsdrvquery_connect(const char *sockfn) {
return NULL;
}

if (connect(conn->sockfd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
if (select_connect(conn->sockfd, &sa, sizeof(sa), 1, 0) < 0) {
if (nut_debug_level > 0 || nut_upsdrvquery_debug_level >= NUT_UPSDRVQUERY_DEBUG_LEVEL_CONNECT)
upslog_with_errno(LOG_ERR, "connect to driver socket at %s", sockfn);
close(conn->sockfd);
Expand Down
2 changes: 2 additions & 0 deletions include/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@

#ifndef WIN32
# include <syslog.h>
# include <sys/un.h>
#else /* WIN32 */
# include <winsock2.h>
# include <windows.h>
Expand Down Expand Up @@ -754,6 +755,7 @@ int match_regex_hex(const regex_t *preg, const int n);

/* Note: different method signatures instead of TYPE_FD_SER due to "const" */
#ifndef WIN32
int select_connect(int fd, const struct sockaddr_un *addr, size_t addrlen, const time_t d_sec, const suseconds_t d_usec);
ssize_t select_read(const int fd, void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec);
ssize_t select_write(const int fd, const void *buf, const size_t buflen, const time_t d_sec, const suseconds_t d_usec);
#else /* WIN32 */
Expand Down
5 changes: 4 additions & 1 deletion server/sstate.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,10 @@ TYPE_FD sstate_connect(upstype_t *ups)
return ERROR_FD;
}

ret = connect(fd, (struct sockaddr *) &sa, sizeof(sa));
ret = select_connect(fd, &sa, sizeof(sa), 1, 0);

if (ret < 0) {
int err = errno;
time_t now;

if (strstr(sa.sun_path, "/")) {
Expand All @@ -237,6 +238,8 @@ TYPE_FD sstate_connect(upstype_t *ups)
return ERROR_FD;

ups->last_connfail = now;
/* restore errno for logging */
errno = err;
if (strstr(ups->fn, "/")) {
upslog_with_errno(LOG_ERR, "Can't connect to UPS [%s] (%s)",
ups->name, ups->fn);
Expand Down
Loading