F_NONNULL static void mon_interval_cb(struct ev_loop* loop, struct ev_timer* t, const int revents V_UNUSED) { dmn_assert(loop); dmn_assert(t); dmn_assert(revents == EV_TIMER); tcp_events_t* md = t->data; dmn_assert(md); if(md->tcp_state != TCP_STATE_WAITING) { log_warn("plugin_tcp_connect: A monitoring request attempt seems to have " "lasted longer than the monitoring interval. " "Skipping this round of monitoring - are you " "starved for CPU time?"); return; } dmn_assert(md->sock == -1); dmn_assert(!ev_is_active(md->connect_watcher)); dmn_assert(!ev_is_active(md->timeout_watcher) && !ev_is_pending(md->timeout_watcher)); log_debug("plugin_tcp_connect: Starting state poll of %s", md->desc); const bool isv6 = md->addr.sa.sa_family == AF_INET6; const int sock = socket(isv6 ? PF_INET6 : PF_INET, SOCK_STREAM, gdnsd_getproto_tcp()); if(sock == -1) { log_err("plugin_tcp_connect: Failed to create monitoring socket: %s", dmn_logf_errno()); return; } if(fcntl(sock, F_SETFL, (fcntl(sock, F_GETFL, 0)) | O_NONBLOCK) == -1) { log_err("plugin_tcp_connect: Failed to set O_NONBLOCK on monitoring socket: %s", dmn_logf_errno()); close(sock); return; } bool success = false; if(likely(connect(sock, &md->addr.sa, md->addr.len) == -1)) { switch(errno) { case EINPROGRESS: // this is the normal case, where nonblock connect // wants us to wait for writability... md->sock = sock; md->tcp_state = TCP_STATE_CONNECTING; ev_io_set(md->connect_watcher, sock, EV_WRITE); ev_io_start(loop, md->connect_watcher); ev_timer_set(md->timeout_watcher, md->tcp_svc->timeout, 0); ev_timer_start(loop, md->timeout_watcher); return; // don't do socket/status finishing actions below... break; // redundant case EPIPE: case ECONNREFUSED: case ETIMEDOUT: case EHOSTUNREACH: case EHOSTDOWN: case ENETUNREACH: // fast remote failures, e.g. when remote is local, I hope log_debug("plugin_tcp_connect: State poll of %s failed very quickly", md->desc); break; default: log_err("plugin_tcp_connect: Failed to connect() monitoring socket to remote server, possible local problem: %s", dmn_logf_errno()); } } else { success = true; } close(sock); gdnsd_mon_state_updater(md->idx, success); }
F_NONNULL static void mon_interval_cb(struct ev_loop* loop, struct ev_timer* t, const int revents V_UNUSED) { dmn_assert(loop); dmn_assert(t); dmn_assert(revents == EV_TIMER); http_events_t* md = (http_events_t*)t->data; dmn_assert(md); if(unlikely(md->hstate != HTTP_STATE_WAITING)) { log_warn("plugin_http_status: A monitoring request attempt seems to have " "lasted longer than the monitoring interval. " "Skipping this round of monitoring - are you " "starved for CPU time?"); return; } dmn_assert(md->sock == -1); dmn_assert(!ev_is_active(md->read_watcher)); dmn_assert(!ev_is_active(md->write_watcher)); dmn_assert(!ev_is_active(md->timeout_watcher)); log_debug("plugin_http_status: Starting state poll of %s", md->smgr->desc); do { const bool isv6 = md->addr.sa.sa_family == AF_INET6; const int sock = socket(isv6 ? PF_INET6 : PF_INET, SOCK_STREAM, gdnsd_getproto_tcp()); if(unlikely(sock < 0)) { log_err("plugin_http_status: Failed to create monitoring socket: %s", logf_errno()); break; } if(unlikely(fcntl(sock, F_SETFL, (fcntl(sock, F_GETFL, 0)) | O_NONBLOCK) == -1)) { log_err("plugin_http_status: Failed to set O_NONBLOCK on monitoring socket: %s", logf_errno()); close(sock); break; } md->already_connected = true; if(likely(connect(sock, &md->addr.sa, md->addr.len) == -1)) { if(likely(errno == EINPROGRESS)) { md->already_connected = false; } else { switch(errno) { case EPIPE: case ECONNREFUSED: case ETIMEDOUT: case EHOSTUNREACH: case EHOSTDOWN: case ENETUNREACH: break; default: log_err("plugin_http_status: Failed to connect() monitoring socket to remote server, possible local problem: %s", logf_errno()); } close(sock); break; } } md->sock = sock; md->hstate = HTTP_STATE_WRITING; md->done = 0; ev_io_set(md->write_watcher, sock, EV_WRITE); ev_io_start(loop, md->write_watcher); ev_timer_set(md->timeout_watcher, md->http_svc->timeout, 0); ev_timer_start(loop, md->timeout_watcher); return; } while(0); // This is only reachable via "break"'s above, which indicate an immediate failure log_debug("plugin_http_status: State poll of %s failed very quickly", md->smgr->desc); md->hstate = HTTP_STATE_WAITING; gdnsd_mon_state_updater(md->smgr, false); }