#include "tcpdispatcher"

void TcpDispatcher::dispatch() {
    // Check that a working algorithm is available. May be missing if
    // constructor's "new" failed.
    if (!algorithm())
	throw Error("No algorithm in Tcpdispatcher::dispatch");
    
    bool connected = false;

    // Build up the target list, if not yet done so. The HTTP dispatcher
    // might've created it already for host-based matching (in which case
    // we won't bother here).
    if (! targetlist().isdefined()) {
	msg("Creating target list for the TCP dispatcher\n");
	for (unsigned i = 0; i < balancer.nbackends(); i++)
	    if (balancer.backend(i).available()) {
		targetlist().add(i);
		if (config.verbose())
		    msg("  Candidate target: " <<
			balancer.backend(i).description() << '\n');
	    }	
    }

    // Call the dispatch algorithm until we can connect,
    // or until the algorithm is out of back ends (throws exception).
    while (!connected) {
	targetbackend(algorithm()->target(clientfd().clientaddr().sin_addr,
					  targetlist()));

	// Define a dummy back end according to the current selection.
	// Connect to it. If that succeeds, get the socket from it.
	Backend tb;
	tb.server(balancer.backend(targetbackend()).server());
	tb.port(balancer.backend(targetbackend()).port());

	if (!tb.connect()) {
	    balancer.backend(targetbackend()).live(false);
	    if (config.verbose())
		msg("Failed to connect to back end " << tb.description() <<
		    ", trying to dispatch to other\n");
	    // Re-evaluate back ends. Something may have come online.
	    msg("Re-creating target list for the TCP dispatcher.\n");
	    targetlist().reset();
	    for (unsigned i = 0; i < balancer.nbackends(); i++)
		if (balancer.backend(i).available()) {
		    targetlist().add(i);
		    if (config.verbose())
			msg("  Candidate target: " <<
			    balancer.backend(i).description() << '\n');
		}	
	    // And now fall thru into the next loop run...
	} else {
	    connected = true;
	    backendfd(tb.sock());
	    msg ("Will dispatch client to back end " << tb.description() <<
		 " on fd " << tb.sock().fd() << '\n');
	    break;
	}
    }
}
