- // Connect to everything in turn until we have a socket.
- 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;
- }
-
- do {
- err = connect(sock, ai->ai_addr, ai->ai_addrlen);
- } while (err == -1 && errno == EINTR);
-
- if (err != -1) {
- freeaddrinfo(ai);
- return sock;
- }
-
- ai = ai->ai_next;
- }
-
- // Give the last one as error.
- fprintf(stderr, "WARNING: Connect to '%s' failed (%s)\n",
- host.c_str(), strerror(errno));
- freeaddrinfo(ai);
- return -1;
-}
-
-void Input::do_work()
-{
- while (!should_stop) {
- if (state == SENDING_REQUEST || state == RECEIVING_HEADER || state == RECEIVING_DATA) {
- // 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 == EAGAIN)) {
- continue;
- }
- if (nfds == -1) {
- perror("poll");
- state = CLOSING_SOCKET;
- }
- }
-
- switch (state) {
- case NOT_CONNECTED:
- request.clear();
- request_bytes_sent = 0;
- response.clear();
-
- sock = lookup_and_connect(host, port);
- if (sock != -1) {
- // Yay, successful connect. Try to set it as nonblocking.
- int one = 1;
- if (ioctl(sock, FIONBIO, &one) == -1) {
- perror("ioctl(FIONBIO)");
- state = CLOSING_SOCKET;
- } else {
- state = SENDING_REQUEST;
- request = "GET " + path + " HTTP/1.0\r\nUser-Agent: cubemap\r\n\r\n";
- request_bytes_sent = 0;
- }
- }
- break;
- case SENDING_REQUEST: {
- size_t to_send = request.size() - request_bytes_sent;
- int ret;
-
- do {
- ret = write(sock, request.data() + request_bytes_sent, to_send);
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
- perror("write");
- state = CLOSING_SOCKET;
- continue;
- }
-
- assert(ret >= 0);
- request_bytes_sent += ret;
-
- if (request_bytes_sent == request.size()) {
- state = RECEIVING_HEADER;
- }
- break;
- }
- case RECEIVING_HEADER: {
- char buf[4096];
- int ret;
-
- do {
- ret = read(sock, buf, sizeof(buf));
- } while (ret == -1 && errno == EINTR);
-
- if (ret == -1) {
- perror("read");
- state = CLOSING_SOCKET;
- continue;
- }
-
- if (ret == 0) {
- // This really shouldn't happen...
- fprintf(stderr, "Socket unexpectedly closed while reading header\n");
- state = CLOSING_SOCKET;
- continue;
- }
-
- RequestParseStatus status = wait_for_double_newline(&response, buf, ret);
-
- if (status == RP_OUT_OF_SPACE) {
- fprintf(stderr, "WARNING: fd %d sent overlong response!\n", sock);
- state = CLOSING_SOCKET;
- continue;
- } else if (status == RP_NOT_FINISHED_YET) {
- continue;
- }