static void ssl_err(const char* s) ATTR_NORETURN;
static void ssl_path_err(const char* s, const char *path) ATTR_NORETURN;
+/** timeout to wait for connection over stream, in msec */
+#define UNBOUND_CONTROL_CONNECT_TIMEOUT 5000
+
/** Give unbound-control usage, and exit (1). */
static void
usage(void)
return ctx;
}
+/** check connect error */
+static void
+checkconnecterr(int err, const char* svr, struct sockaddr_storage* addr,
+ socklen_t addrlen, int statuscmd, int useport)
+{
+#ifndef USE_WINSOCK
+ if(!useport) log_err("connect: %s for %s", strerror(err), svr);
+ else log_err_addr("connect", strerror(err), addr, addrlen);
+ if(err == ECONNREFUSED && statuscmd) {
+ printf("unbound is stopped\n");
+ exit(3);
+ }
+#else
+ int wsaerr = err;
+ if(!useport) log_err("connect: %s for %s", wsa_strerror(wsaerr), svr);
+ else log_err_addr("connect", wsa_strerror(wsaerr), addr, addrlen);
+ if(wsaerr == WSAECONNREFUSED && statuscmd) {
+ printf("unbound is stopped\n");
+ exit(3);
+ }
+#endif
+ exit(1);
+}
+
/** contact the server with TCP connect */
static int
contact_server(const char* svr, struct config_file* cfg, int statuscmd)
if(fd == -1) {
fatal_exit("socket: %s", sock_strerror(errno));
}
+ fd_set_nonblock(fd);
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
#ifndef USE_WINSOCK
- int err = errno;
- if(!useport) log_err("connect: %s for %s", strerror(err), svr);
- else log_err_addr("connect", strerror(err), &addr, addrlen);
- if(err == ECONNREFUSED && statuscmd) {
- printf("unbound is stopped\n");
- exit(3);
+#ifdef EINPROGRESS
+ if(errno != EINPROGRESS) {
+ checkconnecterr(errno, svr, &addr,
+ addrlen, statuscmd, useport);
}
+#endif
#else
- int wsaerr = WSAGetLastError();
- if(!useport) log_err("connect: %s for %s", wsa_strerror(wsaerr), svr);
- else log_err_addr("connect", wsa_strerror(wsaerr), &addr, addrlen);
- if(wsaerr == WSAECONNREFUSED && statuscmd) {
- printf("unbound is stopped\n");
- exit(3);
+ if(WSAGetLastError() != WSAEINPROGRESS &&
+ WSAGetLastError() != WSAEWOULDBLOCK) {
+ checkconnecterr(WSAGetLastError(), svr, &addr,
+ addrlen, statuscmd, useport);
}
#endif
- exit(1);
}
+ while(1) {
+ fd_set rset, wset, eset;
+ struct timeval tv;
+ FD_ZERO(&rset);
+ FD_SET(FD_SET_T fd, &rset);
+ FD_ZERO(&wset);
+ FD_SET(FD_SET_T fd, &wset);
+ FD_ZERO(&eset);
+ FD_SET(FD_SET_T fd, &eset);
+ tv.tv_sec = UNBOUND_CONTROL_CONNECT_TIMEOUT/1000;
+ tv.tv_usec= (UNBOUND_CONTROL_CONNECT_TIMEOUT%1000)*1000;
+ if(select(fd+1, &rset, &wset, &eset, &tv) == -1) {
+ fatal_exit("select: %s", sock_strerror(errno));
+ }
+ if(!FD_ISSET(fd, &rset) && !FD_ISSET(fd, &wset) &&
+ !FD_ISSET(fd, &eset)) {
+ fatal_exit("timeout: could not connect to server");
+ } else {
+ /* check nonblocking connect error */
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+ if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &len) < 0) {
+#ifndef USE_WINSOCK
+ error = errno; /* on solaris errno is error */
+#else
+ error = WSAGetLastError();
+#endif
+ }
+ if(error != 0) {
+#ifndef USE_WINSOCK
+#ifdef EINPROGRESS
+ if(error == EINPROGRESS)
+ continue; /* try again later */
+#endif
+#ifdef EWOULDBLOCK
+ if(error == EWOULDBLOCK)
+ continue; /* try again later */
+#endif
+#else
+ if(error == WSAEINPROGRESS)
+ continue; /* try again later */
+ if(error == WSAEWOULDBLOCK)
+ continue; /* try again later */
+#endif
+ checkconnecterr(error, svr, &addr, addrlen,
+ statuscmd, useport);
+ }
+ }
+ break;
+ }
+ fd_set_block(fd);
return fd;
}