#include "backend"

bool Backend::connect() {
    PROFILE("Backend::connect");
    
    debugmsg("About to connect to back end " << description() << '\n');
    
    // Resolve hostname, prepare binding
    struct sockaddr_in backendaddr;
    
    backendaddr.sin_family = AF_INET;
    backendaddr.sin_port = htons(bdef.port());
    backendaddr.sin_addr.s_addr = dnsentry.resolve(bdef.server());

    // Client socket goes into nonblocking mode, so we can connect
    // and enforce a timeout later.
    int flags;
    if ( (flags = fcntl (clsocket.fd(), F_GETFL, 0)) == -1 )
	throw Error(string("Failed to get fd flags: ") + strerror(errno));    
    if (fcntl (clsocket.fd(), F_SETFL, flags | O_NONBLOCK) == -1)
	throw Error(string("Failed to fd in nonblocking mode: ") +
		    strerror(errno));

    // Do the connect
    int conres = ::connect (clsocket.fd(), (struct sockaddr *)&backendaddr,
			 sizeof(backendaddr));
    int conerrno = errno;
    debugmsg("Connect result: " << conres <<
	     ", errno: " << conerrno << ' ' << strerror(conerrno) << '\n');

    // Put socket again in blocking mode.
    if (fcntl (clsocket.fd(), F_SETFL, flags) == -1)
	throw Error(string("Failed to put fd in blocking mode: ") +
		    strerror(errno));
    
    // Check on the outcome of the connect
    if (!conres || conerrno == EINPROGRESS) {
	// Wait for socket to go writable.
	Fdset fdset (config.backend_write_timeout());
	fdset.add (clsocket);
	fdset.wait_rw();

#	ifdef CONNECTCHECK_ONLY_WRITABLE
	if (fdset.writeable(clsocket))
	    live(true);
	else {
	    markconnecterror();
	    live(false);
	}
#	else
	if (fdset.writeable(clsocket) && !fdset.readable(clsocket))
	    live(true);
	else {
	    debugmsg("Connect socket writable: " <<
		     (fdset.writeable(clsocket) ? "yes" : "no") <<
		     ", readable: " <<
		     (fdset.readable(clsocket)  ? "yes" : "no") <<
		     '\n');
	    markconnecterror();
	    live(false);
	}
#	endif	
    }

    debugmsg("Back end " << description() << " is " << livestr() <<
	     " (socket " << clsocket.fd() << ")\n");
    
    return (islive);
}
