/* Pure Load Balancer - (C)opyleft 2003 Jedi/Sector One <j@pureftpd.org> */

#include <config.h>
#include "plb.h"
#include "plb_globals.h"
#ifdef WITH_DMALLOC
# include <dmalloc.h>
#endif

void cleanup_connect_ready(int evfd, short event, void *cleaned_server_)
{
    Server * const cleaned_server = (Server *) cleaned_server_;
    
    plb_log(LL_DEBUG, "Starting async cleanup");
    (void) evfd;
    if (cleaned_server->cleanup_fd == -1) {
        return;
    }
    if (event == EV_WRITE) {
        ssize_t written;
        
        while ((written = write(cleaned_server->cleanup_fd, "", (size_t) 1U))
               != 1U && errno == EINTR);
        if (written == (ssize_t) 1U) {
            cleaned_server->status = 1U;
            plb_log(LL_WARNING, "Bringing [%s] back to life",
                    cleaned_server->name);
        } else {
            plb_log(LL_DEBUG, "[%s] probe failure", cleaned_server->name);
        }
    }
    while (close(cleaned_server->cleanup_fd) != 0 && errno == EINTR);
    cleaned_server->cleanup_fd = -1;                
}

void spawn_cleanup(Server * const cleaned_server)
{
    int cleanup_fd;

    if (cleaned_server->cleanup_fd != -1) {
        plb_log(LL_DEBUG, "Cleanup already in progress, fd=[%d]",
                cleaned_server->cleanup_fd);
        return;
    }
    cleaned_server->cleanup_fd = -1;
    if ((cleanup_fd = socket(cleaned_server->ai_family,
                             SOCK_STREAM, IPPROTO_TCP)) == -1) {
        plb_log(LL_WARNING, "Unable to create a cleanup socket : [%s]",
                strerror(errno));
        return;
    }
    setsockopt_aggressive(cleanup_fd);
    socket_nonblock(cleanup_fd);
    for (;;) {
        if (connect(cleanup_fd, 
                    (struct sockaddr *) &cleaned_server->ai_addr,
                    (socklen_t) cleaned_server->ai_addrlen) != 0 &&
            errno != EINPROGRESS) {
            if (errno == EINTR) {
                continue;
            }
            plb_log(LL_NOTIFY, "Cleanup socket didn't connect() : [%s]",
                    strerror(errno));
            while (close(cleanup_fd) != 0 && errno == EINTR);
            return;
        }
        break;
    }
    cleaned_server->cleanup_fd = cleanup_fd;
    plb_log(LL_DEBUG, "Should spawn async health checking fd:[%d]",
            cleanup_fd);
    event_set(&cleaned_server->cleanup_ev, cleanup_fd, EV_WRITE | EV_TIMEOUT,
              cleanup_connect_ready, cleaned_server);
    event_add(&cleaned_server->cleanup_ev, &timeout_header_server_write);
}

void periodic_cleanup(int dummy, const short event, void *ev)
{
    register Server *cleaned_server;

    (void) dummy;
    (void) event;    
    if ((cleaned_server = serverpool_head) == NULL) {
        plb_log(LL_ERROR, "No server pool");
        return;
    }
    do {
        if (cleaned_server->status <= 0U) {
            spawn_cleanup(cleaned_server);
        }
    } while ((cleaned_server = cleaned_server->next) != NULL);
    
    evtimer_add((struct event *) ev, &timeout_cleanup);
}


syntax highlighted by Code2HTML, v. 0.9.1