#include "hashedip"

unsigned HashedIp::target(struct in_addr clientip,
		     BackendVector &targetlist) {

    // Nothing to do if we don't have targets.
    if (!targetlist.size())
	throw Error("Hashed-ip algorithm: no back ends to dispatch to");
    
    // Hash the client's IP into an index
    unsigned h = 0;
    for (char *cp = (char*)&clientip;
	 unsigned(cp - (char*)&clientip) < sizeof(struct in_addr);
	 cp++) {
	h += *cp;
	h %= targetlist.size();
    }
    unsigned index = targetlist[h];

    msg("Client IP "<< inet2string(clientip) << " hashes to " << index <<
	", back end " << balancer.backend(index).description()  << '\n');

    // In strict mode, back end must be available, or don't proceed
    // In lax mode, fall back to least-connections dispatching
    if (! balancer.backend(index).available()) {
	if (config.dispatchmode() == Dispatchmode::m_strict_hashed_ip)
	    throw Error("Hashed-IP algorithm: target back end " +
			balancer.backend(index).description() +
			" unavailable");
	else {
	    msg("Hashed-IP algorithm: target back end " <<
		balancer.backend(index).description() << " unavailable, "
		<< "falling back to least-connections\n");
	    Leastconn l;
	    index = l.target(clientip, targetlist);
	}
    }

    // Got it
    return (index);
}
