#include "storedip"

unsigned StoredIp::target(struct in_addr clientip,
			  BackendVector &targetlist) {
    PROFILE("StoredIP::target");
    IPStore::on();

    msg("Starting stored-ip dispatcher\n");

    int tb;
    if ( (tb = IPStore::target(clientip)) >= 0 ) {
	unsigned target = tb;
	IPStore::clear(clientip);
	if (balancer.backend(target).available()) {
	    // Historical target is up, go there!
	    msg("Sending " << inet2string(clientip) << " to " <<
		balancer.backend(target).description() << '\n');
	    return target;
	}
	msg ("Historical target " <<
	     balancer.backend(target).description() << " unavailable\n"); 
	if (config.dispatchmode() == Dispatchmode::m_strict_stored_ip)
	    throw Error("Stored-IP algorithm: target back end " +
			balancer.backend(target).description() +
			" unavailable");
    }

    // Client is seen for the first time, or after the timout period, or
    // their preferred back end is down (and we're in lax mode ofc).
    // Treat as new connection.
    Leastconn l;
    
    if (!config.removereservations())
	return l.target(clientip, targetlist);
    else {
	BackendVector tlist = targetlist;
	while (true) {
	    try {
		return l.target(clientip, tlist);
	    } catch (...) {
		// We're out of back ends and need to clear up the IP store
		// to retry.
		// We give it a sec, remove the oldest entry, and rebuild the
		// target list for the least-connections dispatch algorithm.
		warnmsg("Out of back ends, releasing oldest client entry "
			"and retrying\n");
		IPStore::clearoldest();
		sleep(1);
		BackendVector newlist;
		for (unsigned int i = 0; i < balancer.nbackends(); i++)
		    if (balancer.backend(i).available())
			newlist.add(i);
		tlist = newlist;
	    }
	}
    }
}
		
