[Zope-dev] Zope closes connection if the client closes the write-end of connection

Izak Burger izak at upfrontsystems.co.za
Thu Oct 15 06:41:51 EDT 2009


Hi all,

Yesterday we tried to get the backend probe feature of varnish to work 
with zope. It failed, claiming that a response was not received. 
Checking the Z2 log showed that the request was received but that zero 
bytes was transferred. Using tcpdump shows that varnish closes the 
connection before zope can send the response.

I eventually distilled the check varnish uses into a small C program, 
and an interesting problem shows up. When you call shutdown(fd, SHUT_WR) 
on your socket connection, in effect telling zope that you're done 
talking to it, it looks like zope responds in kind by not talking to you 
either. I deduce this from the fact that poll() returns POLLHUP in 
revents and read() returns zero (EOF). POLLHUP, if I understand this 
correctly, means the other side (zope) has hung up.

This effectively makes it impossible to use certain kinds of monitoring 
software with zope, specifically varnish.

I would appreciate it if someone in the know could look at the code, 
tell me what I (and by extension varnish) am doing wrong, or whether 
this is perhaps a bug in zope (which I strongly suspect).

The attached C code works fine against apache, and it also works fine 
against zope if you remove the shutdown() call.

regards,
Izak

--- snip: poll.c ---
#define URL "/"

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char **argv){
     struct pollfd fds[1];
     int timeout_msecs = 5000;
     int ret;
     int i, sd, request_size, offset;
     struct sockaddr_in addr;
     char buf[1024];

     if(argc < 3){
         fprintf(stderr, "Usage: %s ip port\n", argv[0]);
         return 1;
     }

     /* Open network connection */
     sd = socket(AF_INET, SOCK_STREAM, 0);
     addr.sin_family = AF_INET;
     addr.sin_addr.s_addr = inet_addr(argv[1]);
     addr.sin_port = htons(atoi(argv[2]));

     if (connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0){
         perror("connect");
         return 1;
     }

     /* Send the request */
     request_size = snprintf(buf, sizeof(buf),
         "GET %s HTTP/1.0\r\nConnection: close\r\n\r\n", URL);
     offset = 0;
     while(offset < request_size){
         i = write(sd, buf+offset, request_size-offset);
         offset += i;
     }

     /* Shutdown the write side */
     shutdown(sd, SHUT_WR);

     /* Now wait for data to come back */
     do {
         fds[0].fd = sd;
         fds[0].events = POLLIN;
         fds[0].revents = 0;
         ret = poll(fds, 1, timeout_msecs);
         if (ret > 0) {
             printf("%d POLLIN events on fd %d\n", ret, fds[0].fd);
             printf("revents = %d\n", fds[0].revents);
             i = read(sd, buf, sizeof(buf));
             printf("Read %d bytes from %d\n", i, sd);
         } else if (ret == 0){
             printf("Timeout\n");
         } else {
             perror("poll");
         }
     } while(i>0);
}
--- snip ---


More information about the Zope-Dev mailing list