/* Agent Tcl
   Bob Gray
   26 June 1995

   genAgentConn.h

   This file defines the class that handles the connection between the agent
   and the server.

   Copyright (c) 1995-1998, Robert S. Gray Dartmouth College

   See the file "agent.terms" for information on usage and redistribution
   of this file and for a DISCLAIMER OF ALL WARRANTIES.
*/

#ifndef _GEN_AGENT_CONN
#define _GEN_AGENT_CONN

#ifndef NO_PRAGMAS
#pragma interface
#endif

#ifndef _AGENT_ID_H
#include "agentId.h"
#endif
#ifndef _MESG_CONNECTION_H
#include "mesgConnection.h"		// ConnectionTrap
#endif
#ifndef _PLAT_SIZES_H
#include "platSizes.h"			// UINT_32
#endif
#ifndef _TRUEFALSE_H
#include "truefalse.h"			// BOOLEAN
#endif

    /* forward declarations so we can compile */

class AGENT;
class AgentMasks;
class AgentConnection;
class DynamicBuffer;
class MachineId;
class MESSAGE;
class MonitorLock;
class MonitorGroup;
class MESSAGE_SET;
struct timeval;

    /* connection from the agent to a server */

class AgentConnectionProxy
{
	AgentConnection *m_connection;     // the connection
	BOOLEAN m_connectionOwner;         // e_TRUE if the proxy owns the connection

	AgentConnectionProxy (const AgentConnectionProxy&) {
	    // unimplemented
	}

	AgentConnectionProxy& operator= (const AgentConnectionProxy&) {
	    // unimplemented
	    return (*this);
	}

    protected:

	AgentConnectionProxy (AgentConnection *connection, BOOLEAN owner = e_FALSE):
	    m_connection (connection),
	    m_connectionOwner (owner)
	{
	    // empty
	}

    public:

	enum BackgroundHandler {
	    e_BACKGROUND_OKAY,
	    e_BACKGROUND_BAD
	};

	static AgentConnectionProxy *makeConnection 
	    (struct timeval stop, 
	     AGENT *agent, 
	     const MachineId& machine, 
	     const BASE_SECURITY &security,
	     int &errorCode,
	     BackgroundHandler backgroundHandler
	    );

	AgentConnection *operator-> (void) {
	    return (m_connection);
	}

	AgentConnection *relinquishConnection (void) {
	    AgentConnection *connection = m_connection;
	    m_connection = NULL;
	    m_connectionOwner = e_FALSE;
	    return (connection);
	}

       ~AgentConnectionProxy ();
};

class AgentConnection: public ConnectionTrap
{
	    // server TCP/IP port and Unix socketname

	static UINT_32 m_port;
	static char *m_unixsocket;

	    // per-instance variables

	AGENT *m_agent;			// agent that created the connection
	MachineId m_machine;		// destination machine
	BASE_SECURITY m_security;	// security information
	SocketConnection *m_connection;  // actual connection
        BOOLEAN m_backgroundConnection; // e_TRUE if this is a background connection
	ConnectionTrap *m_trap;         // trap to call on message arrival
	MonitorLock *m_lock;            // lock for mutual exclusion
	MonitorGroup *m_locks;		// masks lock and our lock for mutual exclusion

    private:
 
	    /* receive any message except for a RESP_MESSAGE, RESP_EVENT or */
	    /* RESP_MEETING messages -- RESP_MESSAGE, RESP_EVENT and        */
	    /* RESP_MEETING messages are transparently added to the agent's */
	    /* internal queues for later processing                         */

	int unsecureReceiveNoncommNolock
	    (MESSAGE *&receivedMessage, 
	     const MESSAGE_SET &messageSet,
	     struct timeval *stop = NULL);

    protected:

	    /* callback routine for asynchronous message arrival */

        void connectionAlarm
	    (Connection &connection, Connection::ConnectionStatus status);

	    /* send a secure/unsecure message along the connection */

	int send
	    (MESSAGE& message, struct timeval *stop = NULL);

	int unsecureSend
	    (MESSAGE& message, struct timeval *stop = NULL);

    public: 

	    /* close or do not close a provided file descriptor */

	enum FdDisposition {
	    e_Close	= 0,
	    e_NoClose   = 1 
	};

	    /* constructor and destructor */

	AgentConnection (AGENT *agent, 
	    const MachineId &machine, const BASE_SECURITY &security);

	AgentConnection (int fd, AGENT *agent, 
	    const MachineId &machine, const BASE_SECURITY &security,
	    FdDisposition fdDisposition = e_Close);
	
	virtual ~AgentConnection
	    ();

	    /* connect to the destination machine */

	int connect 
	    (struct timeval stop);

	    /* send a message and receive the response */

	int RPC
	    (MESSAGE &message, const MESSAGE_SET& messageSet, 
	     MESSAGE*& response,
	     struct timeval *stop = NULL);

	int unsecureRPC
	    (MESSAGE &message, const MESSAGE_SET& messageSet, 
	     MESSAGE*& response);

	    /* send a buffered message */

	int unsecureSendFromBuffer
	    (DynamicBuffer& buffer);

	    /* receive any message */

	MESSAGE * unsecureReceiveAny
	    (const MESSAGE_SET &messageSet);

	    /* receive any message except for a RESP_MESSAGE, RESP_EVENT or */
	    /* RESP_MEETING messages -- RESP_MESSAGE, RESP_EVENT and        */
	    /* RESP_MEETING messages are transparently added to the agent's */
	    /* internal queues for later processing                         */

	int unsecureReceiveNoncomm
	    (MESSAGE *&receivedMessage, 
	     const MESSAGE_SET &messageSet,
	     struct timeval *stop = NULL);

	    /* turn this connection into a background connection */

	void makeBackground
	    (ConnectionTrap *trap, MonitorGroup monitorGroup);

	BOOLEAN isBackground
	    (void);

	    /* see if a message is pending on the connection */

	int isMessagePending
	    (int& flags);

	    /* get the file descriptor associated with this connection */

	int getFd (void) {
	    return (m_connection -> getFd());
	}
};

#endif /* _GEN_CONNECTION_H */
