-#include <stdio.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include "parse.h"
#include "serverpool.h"
#include "state.pb.h"
-#include "util.h"
#include "version.h"
using namespace std;
void HTTPInput::close_socket()
{
- safe_close(sock);
+ int ret;
+ do {
+ ret = close(sock);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == -1) {
+ log_perror("close()");
+ }
}
InputProto HTTPInput::serialize() const
addrinfo *base_ai = ai;
// Connect to everything in turn until we have a socket.
- while (ai && !should_stop()) {
+ while (ai && !should_stop) {
int sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
if (sock == -1) {
// Could be e.g. EPROTONOSUPPORT. The show must go on.
continue;
}
- // Now do a non-blocking connect. This is important because we want to be able to be
- // woken up, even though it's rather cumbersome.
-
- // Set the socket as nonblocking.
- int one = 1;
- if (ioctl(sock, FIONBIO, &one) == -1) {
- log_perror("ioctl(FIONBIO)");
- safe_close(sock);
- return -1;
- }
-
- // Do a non-blocking connect.
do {
err = connect(sock, ai->ai_addr, ai->ai_addrlen);
} while (err == -1 && errno == EINTR);
- if (err == -1 && errno != EINPROGRESS) {
- log_perror("connect");
- safe_close(sock);
- continue;
- }
-
- // Wait for the connect to complete, or an error to happen.
- for ( ;; ) {
- bool complete = wait_for_activity(sock, POLLIN | POLLOUT, NULL);
- if (should_stop()) {
- safe_close(sock);
- return -1;
- }
- if (complete) {
- break;
- }
- }
-
- // Check whether it ended in an error or not.
- socklen_t err_size = sizeof(err);
- if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &err_size) == -1) {
- log_perror("getsockopt");
- safe_close(sock);
- continue;
+ if (err != -1) {
+ freeaddrinfo(base_ai);
+ return sock;
}
- errno = err;
+ do {
+ err = close(sock);
+ } while (err == -1 && errno == EINTR);
- if (err == 0) {
- // Successful connect.
- freeaddrinfo(base_ai);
- return sock;
+ if (err == -1) {
+ log_perror("close");
+ // Can still continue.
}
- safe_close(sock);
ai = ai->ai_next;
}
void HTTPInput::do_work()
{
- while (!should_stop()) {
+ while (!should_stop) {
if (state == SENDING_REQUEST || state == RECEIVING_HEADER || state == RECEIVING_DATA) {
- bool activity = wait_for_activity(sock, (state == SENDING_REQUEST) ? POLLOUT : POLLIN, NULL);
- if (!activity) {
- // Most likely, should_stop was set.
+ // Since we are non-blocking, we need to wait for the right state first.
+ // Wait up to 50 ms, then check should_stop.
+ pollfd pfd;
+ pfd.fd = sock;
+ pfd.events = (state == SENDING_REQUEST) ? POLLOUT : POLLIN;
+ pfd.events |= POLLRDHUP;
+
+ int nfds = poll(&pfd, 1, 50);
+ if (nfds == 0 || (nfds == -1 && errno == EINTR)) {
continue;
}
+ if (nfds == -1) {
+ log_perror("poll");
+ state = CLOSING_SOCKET;
+ }
}
switch (state) {
break;
}
case CLOSING_SOCKET: {
- close_socket();
+ int err;
+ do {
+ err = close(sock);
+ } while (err == -1 && errno == EINTR);
+
+ if (err == -1) {
+ log_perror("close");
+ }
+
state = NOT_CONNECTED;
break;
}
// If we are still in NOT_CONNECTED, either something went wrong,
// or the connection just got closed.
// The earlier steps have already given the error message, if any.
- if (state == NOT_CONNECTED && !should_stop()) {
+ if (state == NOT_CONNECTED && !should_stop) {
log(INFO, "[%s] Waiting 0.2 second and restarting...", url.c_str());
- timespec timeout_ts;
- timeout_ts.tv_sec = 0;
- timeout_ts.tv_nsec = 200000000;
- wait_for_wakeup(&timeout_ts);
+ usleep(200000);
}
}
}