/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * Originally developed by Aaron Bannert and Justin Erenkrantz, eBuilt.
 */

#include <stdlib.h>      /* For atexit */
#include <apr.h>        
#include <apr_general.h> /* For apr_initialize */
#include <apr_strings.h>
#include <apr_file_io.h>

#include <flood_profile.h>

/* FIXME: Base this on RCS ID? */
#define FLOOD_VERSION ".001"

#define CRLF "\r\n"

/* FIXME: replace the apr_recv logic with something sane. */
#define MAX_DOC_LENGTH 8192

#define LOCAL_SOCKET_TIMEOUT 30 * APR_USEC_PER_SEC

/* Win32 doesn't have stdout or stderr. */
apr_file_t *local_stdout, *local_stderr;

/* Should be the new apr_sms_t struct?  Not ready yet.  */
apr_pool_t *local_pool;

/* Construct a request */
static void construct_request(request_t *r)
{
    /* FIXME: Handle keepalives. */
    switch (r->method)
    {
    case GET:
        r->rbuf = apr_psprintf(local_pool, 
                               "GET %s HTTP/1.1" CRLF
                               "User-Agent: Flood/" FLOOD_VERSION CRLF
                               "Host: %s" CRLF CRLF,
                               r->parsed_uri->path, 
                               r->parsed_uri->hostinfo);
        r->rbuftype = POOL;
        r->rbufsize = strlen(r->rbuf);
        break;
    case HEAD:
        r->rbuf = apr_psprintf(local_pool, 
                               "HEAD %s HTTP/1.1" CRLF
                               "User-Agent: Flood/" FLOOD_VERSION CRLF
                               "Host: %s" CRLF CRLF,
                               r->parsed_uri->path, 
                               r->parsed_uri->hostinfo);
        r->rbuftype = POOL;
        r->rbufsize = strlen(r->rbuf);
        break;
    case POST:
        /* FIXME */
        r->rbuf = apr_psprintf(local_pool, 
                               "POST %s HTTP/1.1" CRLF
                               "User-Agent: Flood/" FLOOD_VERSION CRLF
                               "Host: %s" CRLF CRLF,
                               r->parsed_uri->path, 
                               r->parsed_uri->hostinfo);
        r->rbuftype = POOL;
        r->rbufsize = strlen(r->rbuf);
        break;
    }

}

/* Open the TCP connection to the server */
static apr_socket_t* open_socket(request_t *r)
{
    apr_status_t rv = 0;
    apr_sockaddr_t *destsa;
    /* FIXME: apr_socket_t == socket_t - fix profile.h */
    apr_socket_t *socket;

    if ((rv = apr_sockaddr_info_get(&destsa, r->parsed_uri->hostname, APR_INET, 
                                    r->parsed_uri->port, 0, local_pool)) 
                                    != APR_SUCCESS) {
        return NULL;
    }

    if ((rv = apr_socket_create(&socket, APR_INET, SOCK_STREAM, 
                                local_pool)) != APR_SUCCESS) {
        return NULL;
    }

    if ((rv = apr_connect(socket, destsa)) != APR_SUCCESS) {
        if (APR_STATUS_IS_EINPROGRESS(rv)) {
            /* FIXME: Handle better */
            apr_socket_close(socket);
            return NULL;
        }
        else {
            /* FIXME: Handle */
            apr_socket_close(socket);
            return NULL;
        }
    }

    apr_setsocketopt(socket, APR_SO_TIMEOUT, LOCAL_SOCKET_TIMEOUT);

    return socket;
}

/* close down TCP socket */
static void close_socket(apr_socket_t *s)
{
    /* FIXME: recording and other stuff here? */
    apr_socket_close(s);
}

static apr_status_t write_socket(request_t *r, apr_socket_t *s)
{
    apr_size_t l;
    apr_status_t e;

    l = r->rbufsize;

    e = apr_send(s, r->rbuf, &l);

    /* FIXME: Better error and allow restarts? */
    if (l != r->rbufsize)
        return APR_EGENERAL;

    return APR_SUCCESS;     
}

/* FIXME: poll implementation? */
static response_t *read_socket(apr_socket_t *s)
{
    apr_status_t status;
    response_t *resp; 

    resp = apr_pcalloc(local_pool, sizeof(response_t));
    resp->rbuftype = POOL;
    resp->rbufsize = MAX_DOC_LENGTH;
    resp->rbuf = apr_pcalloc(local_pool, resp->rbufsize);

    status = apr_recv(s, resp->rbuf, &resp->rbufsize);

    if (status != APR_SUCCESS && status != APR_EOF)
        return NULL;

    return resp;
}

int main(int argc, char** argv)
{
    request_t r;
    apr_socket_t *s;

    /* FIXME: Where is Roy's change to return the global pool... */
    apr_initialize();
    atexit(apr_terminate);
   
    apr_pool_create(&local_pool, NULL);

    /* The pool should close these file descriptors */ 
    apr_file_open_stdout(&local_stdout, local_pool);
    apr_file_open_stderr(&local_stderr, local_pool);

    r.uri = "http://www.apachelabs.org/";
    r.method = GET;

    r.parsed_uri = apr_pcalloc(local_pool, sizeof(uri_components));

    /* FIXME: This is the private copy. */
    ap_parse_uri_components(local_pool, r.uri, r.parsed_uri);
    if (!r.parsed_uri->port)
        r.parsed_uri->port = DEFAULT_HTTP_PORT;

    apr_file_printf(local_stdout, "%s\n", r.parsed_uri->hostname);

    construct_request(&r);

    s = open_socket(&r);

    if (s)
    {
        response_t *resp;

        if (write_socket(&r, s) == APR_SUCCESS)
        {
            /* Wait .25 seconds... */
            /* FIXME: replace with poll. */
            apr_sleep(0.25 * APR_USEC_PER_SEC);

            resp = read_socket(s);

            if (resp)
                apr_file_printf(local_stdout, "%s\n", (char*)resp->rbuf);
        }
        close_socket(s);
    }
        
    return EXIT_SUCCESS;
}
