/* 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

#define	EVENT_FD_(e) ((e)->ev_fd)

void client_disconnect(Client * const client)
{
    current_nb_clients--;
    if (client->header != NULL) {
        free(client->header);
        client->header = NULL;
        client->header_len = (size_t) 0U;
        client->header_written = (size_t) 0U;        
    }
    if (client->replybuf != NULL) {
        free(client->replybuf);
        client->replybuf = NULL;
        client->replybuf_len = (size_t) 0U;
        client->replybuf_written = (size_t) 0U;        
    }
    if (client->postbuf != NULL) {
        free(client->postbuf);
        client->postbuf = NULL;
        client->postbuf_len = (size_t) 0U;
        client->postbuf_written = (size_t) 0U;        
    }
    if (EVENT_FD((&client->server_read_ev)) != -1) {
        event_del(&client->server_read_ev);
        EVENT_FD_((&client->server_read_ev)) = -1;
    }
    if (EVENT_FD((&client->server_write_ev)) != -1) {
        event_del(&client->server_write_ev);
        EVENT_FD_((&client->server_write_ev)) = -1;
    }
    if (EVENT_FD((&client->client_read_ev)) != -1) {
        event_del(&client->client_read_ev);
        EVENT_FD_((&client->client_read_ev)) = -1;
    }
    if (EVENT_FD((&client->client_write_ev)) != -1) {
        event_del(&client->client_write_ev);
        EVENT_FD_((&client->client_write_ev)) = -1;
    }
    if (client->server_fd != -1) {
        while (close(client->server_fd) != 0 && errno == EINTR);
        client->server_fd = -1;
    }
    if (client->client_fd != -1) {
        while (close(client->client_fd) != 0 && errno == EINTR);
        client->client_fd = -1;
    }
    client->state = STATE_OFFLINE;
}

int handle_timeout(const short event, Client * const client)
{
    if ((event & EV_TIMEOUT) != 0) {
        plb_log(LL_DEBUG, "Timeout");
        client_disconnect(client);
        return 1;
    }
    return 0;
}

static void smtp_banner(const int fd)
{
    char banner[300];
    char nodename[256];
    ssize_t written;
    size_t towrite;
    
    if (gethostname(nodename, sizeof nodename - (size_t) 1U) != 0) {
        nodename[0] = 'x';
        nodename[1] = 0;
    }
    nodename[sizeof nodename - (size_t) 1U] = 0;
    snprintf(banner, sizeof banner,
             "220 %s ESMTP - Pure Load Balancer ready\r\n", nodename);
    towrite = strlen(banner);
    while ((written = write(fd, banner, towrite)) < (ssize_t) 0 &&
           errno == EINTR);            /* to be rewritten */
    if (written < (ssize_t) 0 || (size_t) written != towrite) {
        plb_log(LL_NOTIFY, 
                "Error while sending a banner to a client (nmap scan?): [%s]",
                strerror(errno));
    }
}

void new_client(const int listenfd, short event, void *ev)
{
    static int last_was_full;    
    Client *client;
    struct sockaddr_storage client_sa;
    socklen_t client_sa_len;
    int client_fd;
    
    (void) ev;
    (void) event;
    if ((client_fd = accept(listenfd, (struct sockaddr *) &client_sa,
                            &client_sa_len)) < 0) {
        plb_log(LL_ERROR, "Unable to accept a new client connection : [%s]",
                strerror(errno));
        return;
    }
    setsockopt_aggressive(client_fd);
    socket_nonblock(client_fd);
    if (client_fd >= (int) max_clients) {        
        (void) write(client_fd, SERVER_FULL_MSG, 
                     sizeof SERVER_FULL_MSG - (size_t) 1U);
        if (last_was_full == 0) {
            plb_log(LL_WARNING, "Server full - too many clients");
            last_was_full = 1;
        }
        while (close(client_fd) != 0 && errno == EINTR);
        return;
    } else {
        last_was_full = 0;
    }
    if (protocol == PROTOCOL_SMTP) {
        smtp_banner(client_fd);
    }
    current_nb_clients++;
    client = &clients[client_fd];
    client->client_fd = client_fd;
    client->server_fd = -1;    
    client->state = STATE_HEADER;
    client->header = NULL;
    client->postbuf = NULL;
    client->replybuf = NULL;    
    client->header_len = (size_t) 0U;
    client->header_written = (size_t) 0U;    
    client->postbuf_len = (size_t) 0U;
    client->postbuf_written = (size_t) 0U;    
    client->replybuf_len = (size_t) 0U;
    client->replybuf_written = (size_t) 0U;    
    EVENT_FD_((&client->client_read_ev)) = -1;
    EVENT_FD_((&client->client_write_ev)) = -1;
    EVENT_FD_((&client->server_read_ev)) = -1;
    EVENT_FD_((&client->server_write_ev)) = -1;
    event_set(&client->client_read_ev, client_fd,
              EV_READ, client_read, &clients[client_fd]);
    event_add(&client->client_read_ev, &timeout_header_client_read);
}



syntax highlighted by Code2HTML, v. 0.9.1