httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From (Ralf S. Engelschall)
Subject Question: select loop for reliable sockets
Date Thu, 19 Mar 1998 13:14:08 GMT

I'm currently trying to enhance my patch for logfile network socket support by
making those socket logs reliable, i.e. when the connection breaks (e.g. the
logfile master server rebooted, etc.) the socket connection should be
re-initiated again. My idea is to use the maintainance functionality already
used for reliable piped logs.  Now I discovered that the probe_writable_fds()
function from http_main.c is run correctly but never is able to see the broken
socket. The FD_ISSET always returns true for the socket, although the
logfile-server already is down and mod_log_custom.c already sends to the
broken socket.

To trace it down I've extracted the relevant peace of code into a little
stand-alone program, and it showed the same behaviour: Sure, when the server
wents down, my program (the client) receives a SIGPIPE.  But the select-based
loop still is unable to recognize the fact that the socket is now broken. The
question is: WHY? Or what have to be arranged to let the FD_ISSET fail for the
socket? Perhaps some fiddling with setsockopt() or some fcntl()'s? Please

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>
#include <time.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>

static int reopen_socket_log(char *target)
    char host[1024];
    char *port;
    struct hostent *he;
    struct protoent *pe;
    struct sockaddr_in sar;
    FILE *fp;
    int s;

    /* parse host:port pair */
    strncpy(host, target, sizeof(host));
    if ((port = strchr(host, ':')) == NULL)
        return -1;
    *port++ = '\0';

    /* create socket address structure */
    memset((char *)&sar, 0, sizeof(sar));
    sar.sin_family = AF_INET;
    sar.sin_port   = htons(atoi(port));
    if ((sar.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) {
        if ((he = gethostbyname(host)) == NULL)
            return -1;
        sar.sin_addr.s_addr = *((u_long *)(he->h_addr_list[0]));

    /* create the socket and connect to it */
    if ((pe = getprotobyname("tcp")) == NULL)
        return -1;
    if ((s = socket(AF_INET, SOCK_STREAM, pe->p_proto)) < 0)
        return -1;
    if (connect(s, (struct sockaddr *)&sar, sizeof(sar)) < 0)
        return -1;

    return s;

int main(int argc, char *argv[]) 
    int s;
    fd_set fds;
    struct timeval tv;
    int rc;
    char buf[1024];
    int n;

    signal(SIGPIPE, SIG_IGN);
    if ((s = reopen_socket_log(argv[1])) == -1) {
        fprintf(stderr, "httpd: Couldn't connect to %s\n", argv[1]);
    fprintf(stderr, "startup: s=%d\n", s);
    write(s, "startup\n", 8);
    n = 1;
    while (1) {
         FD_SET(s, &fds);
         do {
             tv.tv_sec  = 0;
             tv.tv_usec = 0;
             rc = select(s+1, NULL, &fds, NULL, &tv);
         } while (rc == -1 && errno == EINTR);
         if (rc == -1) {
             fprintf(stderr, "UAAAHHH! rc=-1\n");
         if (rc == 0) {
             fprintf(stderr, "Hmmmmmm! rc=0\n");
         if (FD_ISSET(s, &fds)) {                   <<<<===== this is always
             write(s, buf, strlen(buf));
             fprintf(stderr, "ok, socket still available\n");
             sprintf(buf, "test usage #%d for socket\n", n++);
         else {
             fprintf(stderr, "Yup, socket now no longer available\n");
    fprintf(stderr, "end\n");
    write(s, "end\n", 4);
    return 0;

Any ideas or hints?
                                       Ralf S. Engelschall

View raw message