/* 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 server_send_header(int evfd, short event, void *client_)
{
    Client * const client = client_;
    ssize_t written;

    (void) evfd;
    if (event == EV_TIMEOUT) {
        server_mark_failure(client);
        client_disconnect(client);
        return;
    }
    if (client->header == NULL) {
        client_disconnect(client);
        return;
    }
    if (client->header_len <= (size_t) 0U) {
        goto already_written;
    }
    if ((written = write(client->server_fd,
                         client->header + client->header_written,
                         client->header_len - client->header_written)) !=
        (ssize_t) (client->header_len - client->header_written)) {
        if (written <= (ssize_t) 0) {
            if (errno == EINTR) {
                event_add(&client->server_write_ev,
                          &timeout_header_server_write);
                return;
            }
            switch (errno) {
#ifdef ETIMEDOUT
            case ETIMEDOUT:
#endif
#ifdef ECONNREFUSED
            case ECONNREFUSED:
#endif
#ifdef EHOSTDOWN
            case EHOSTDOWN:
#endif
#ifdef EHOSTUNREACH
            case EHOSTUNREACH:
#endif
#ifdef ECONNRESET
            case ECONNRESET:
#endif
#ifdef ECONNABORTED
            case ECONNABORTED:
#endif
#ifdef ENETRESET
            case ENETRESET:
#endif
#ifdef ENETUNREACH                
            case ENETUNREACH:
#endif
#ifdef ENETDOWN
            case ENETDOWN:
#endif
#ifdef EREMCHG
            case EREMCHG:
#endif
                server_mark_failure(client);
                break;
            default:
                plb_log(LL_NOTIFY, "While connecting to a real server : [%s]",
                        strerror(errno));
            }
            client_disconnect(client);            
            return;
        }
        if (client->server->status <= 0U) {
            plb_log(LL_WARNING, "[%s] is up again\n", client->server->name);
        }
        client->server->status = server_retry;
        client->header_written += written;
        event_add(&client->server_write_ev, &timeout_header_server_write);
        return;                        
    }
    client->header_len = (size_t) 0U;
    already_written:
    client->state = STATE_HEADER_SENT;
    free(client->header);
    client->header = NULL;
    client->header_len = (size_t) 0U;
    client->header_written = (size_t) 0U;    
    
    event_set(&client->server_read_ev, client->server_fd, EV_READ,
              server_forward_reply, client);
    event_add(&client->server_read_ev, &timeout_header_server_read);
}

void client_read_header(Client * const client)
{
    ssize_t readen;
    
    if (client->header == NULL) {
        if ((client->header = malloc(HEADER_MAX)) == NULL) {
            plb_log(LL_ERROR, "Out of memory to read the client query : [%s]",
                    strerror(errno));
            client_disconnect(client);
            return;
        }
        client->header_len = (size_t) 0U;
        client->header_written = (size_t) 0U;        
    }
    if ((readen = read(client->client_fd, client->header + client->header_len,
                       HEADER_MAX - client->header_len))
        <= (ssize_t) 0) {
        if (readen < (ssize_t) 0) {
            if (errno == EINTR) {
                return;
            }
            plb_log(LL_NOTIFY, "Client read error : [%s]",
                    strerror(errno));
        }
        client_disconnect(client);        
        return;
    }
    client->header_len += (size_t) readen;
    if (client->header_len >= HEADER_MAX) {
        plb_log(LOG_WARNING, "Client sent a very large request");
        client_disconnect(client);
    }
    
    do {
        register const char *s;
        const char *s_end;
        
        if (client->header_len <= protocol_header_end_len + (size_t) 1U) {
            break;
        }                    
        s = client->header;
        s_end = client->header + client->header_len 
            - (protocol_header_end_len - (size_t) 1U);
        do {
            if (memcmp(s, protocol_header_end,
                       protocol_header_end_len) == 0) {
                client->state = STATE_SEND_HEADER;
                if (connect_server(client) != 0) {
                    client_disconnect(client);
                    return;
                }
                break;
            }
            s++;
        } while (s != s_end);
    } while(0);
    
    event_add(&client->client_read_ev, &timeout_header_client_read);
}



syntax highlighted by Code2HTML, v. 0.9.1