#include "tcpdispatcher"

void TcpDispatcher::execute() {
    Threadlist::clientfd(clientfd());
    Threadlist::clientip(clientfd().clientaddr().sin_addr);

    if (!check_dos() ||
	!check_acl())
	return;
    
    debugmsg("Dispatch request for client fd " << clientfd().fd() << '\n');

    // Try to determine the back end.
    try {
	Threadlist::desc("Dispatching");
	dispatch();
    } catch (Error const &e) {
	warnmsg(e.what() << " ("
		<< inet2string(clientfd().clientaddr().sin_addr)
		<< ")\n");
	return;
    }

    // Verify that the target is within the allowed set.
    if (targetbackend() < 0 || targetbackend() >= (int)balancer.nbackends()) {
	warnmsg("Target back end " << targetbackend() << "out of range\n");
	return;
    }

    // Dispatch!
    msg("Dispatching client fd " << clientfd().fd() << " to " <<
	balancer.backend(targetbackend()).description() << ", fd " <<
	backendfd().fd() << '\n');

    Threadlist::desc("Serving");
    Threadlist::backend(targetbackend());
    Threadlist::backendfd(backendfd());
    
    balancer.backend(targetbackend()).startconnection();
    if (config.onstart().length()) {
	ostringstream o;
	o << config.onstart() << ' '
	  << inet2string(clientfd().clientaddr().sin_addr)
	  << balancer.backend(targetbackend()).description()
	  << ' ' << balancer.backend(targetbackend()).connections();
	msg("Running onstart script: " << o.str() << '\n');
	sysrun(o.str());
    }

    bool failed = false;
    try {
	handle();
    } catch (Error const &e) {
	warnmsg(e.what() << " ("
		<< inet2string(clientfd().clientaddr().sin_addr)
		<< ")\n");
	failed = true;
	if (config.onfail().length()) {
	    ostringstream o;
	    o << config.onfail() << ' '
	      << inet2string(clientfd().clientaddr().sin_addr)
	      << balancer.backend(targetbackend()).description() << ' '
	      << balancer.backend(targetbackend()).connections();
	    msg("Running onfail script: " << o.str() << '\n');
	    sysrun(o.str());
	}
    }

    balancer.backend(targetbackend()).endconnection();
    if (!failed && config.onend().length()) {
	ostringstream o;
	o << config.onend() << ' '
	  << inet2string(clientfd().clientaddr().sin_addr)
	  << balancer.backend(targetbackend()).description() << ' '
	  << balancer.backend(targetbackend()).connections();
	msg("Running onend script: " << o.str() << '\n');
	sysrun(o.str());
    }

    msg ("Done dispatching to back end fd " << backendfd().fd() << " at " <<
	 balancer.backend(targetbackend()).description() << '\n');
}
