//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project
//
//File: gsmpadjacencyprotocol.h
//
//State: $State: Exp $
//
//Version: $Revision: 1.8 $
//
//Date: $Date: 1998/10/19 18:14:01 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
// 
//Author:
//      Harri Sunila
//
//Description:
//      Class for GSMP Adjacency Protocol -conduit
//
//Copyright:    
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999 
//      
//Licence:
//     
//
//History:
//
//

#ifndef __GSMP_GSMPADJACENCYPROTOCOL_H__
#define __GSMP_GSMPADJACENCYPROTOCOL_H__

#include "pf/conduit.h"
#include "pf/protocol.h"
#include "pf/timer.h"
#include "pf/frame.h"
#include "iface/cpcsif/cpcsdownprimitives.h"
#include "gsmpdefs.h"
#include "gsmpmessage.h"
#include "gsmpadjacencyprotocolmessage.h"
#include "gsmptimeouts.h"

class gsmpAdjacencyState;
class gsmpAdjacencySYNSENTstate;
class gsmpAdjacencySYNRCVDstate;
class gsmpAdjacencyESTABstate;

//
// Class: gsmpAdjacencyProtocol
//
// Description:
//     See file description
//

class gsmpAdjacencyProtocol : public pfProtocol 
{
    public:
        static pfConduit create(pfUlong port_);
        gsmpAdjacencyProtocol(const gsmpAdjacencyProtocol &other_);
        virtual ~gsmpAdjacencyProtocol(void);
        
        virtual pfProtocol *cloneImplementation(void);

        // Variable initializers
        void setSYNCtimeout(pfUlong msec_);
        void setResyncTimeout(pfUlong msec_);
        void setRetryTimeout(pfUlong msec_);
        
        void setName(const string &nearEntityName_);
        void setPort(pfUlong nearEntityPort_);
        
        void generateNewInstanceNumber(void);

        // Sender methods
        // Methods to send Adjacency Protocol Messages
        
        void sendAdjacencyProtocolSYNmessage(void);
        void sendAdjacencyProtocolSYNACKmessage(void);
        void sendAdjacencyProtocolACKmessage(void);
        void sendAdjacencyProtocolRSTACKmessage(void);

        // Method to send GSMP Protocol Message

        void sendGsmpProtocolMessage(gsmpMessage *message_);

        void sendGsmpLinkEstablished(void);
        void sendGsmpLinkNotEstablished(void);
        
        // Peer verification

        void updatePeerVerifier(gsmpAdjacencyProtocolMessage *message_);
        void resetPeerVerifier(void);
        void updateFarEntity(const string &farEntityName_,
                             pfUlong farEntityPort_,
                             pfUlong farEntityInstance_);
        void updateFarEntity(gsmpAdjacencyProtocolMessage *message_);
        void resetFarEntity(void);
        void updateLastReceivedData(gsmpAdjacencyProtocolMessage *message_);

        
        // Following events have been defined in RFC 1987 page 37 & 38

        bool conditionA(gsmpAdjacencyProtocolMessage *message_);
        bool conditionB(gsmpAdjacencyProtocolMessage *message_);
        bool conditionC(gsmpAdjacencyProtocolMessage *message_);

        // ACK locking
        
        void releaseACKlock(void);
        bool acquireACKlock(void);

        // Methods to change state

        void toAdjacencySYNSENTstate(void);
        void toAdjacencySYNRCVDstate(void);
        void toAdjacencyESTABstate(void);

        // Methods to start & stop timers

        void startTimer(void);
        void stopTimer(void);
        bool isTimerActive(void) const;
        
        void startResyncTimer(void);
        void stopResyncTimer(void);

        void startRetryTimer(void);
        void stopRetryTimer(void);

        // Method to implement the behaviour if resynchronization has failed

        void resyncFailed(void);
        
    private:

        gsmpAdjacencyProtocol(void);
        
        // Method to send CPCS-UNITDATA.request, used by sender methods

        void sendCpcsUNITDATAreq(pfFrame &frame_);

        // Method to initialize SwC's name (_nearEntityName).
        // The name is provided by the ATM interface as the
        // End System Identifier (ESI), known also as the MAC-address.
        
        void getESI(void);
        
        // Timers. _timerSYNC is for periodical generation of SYN, SYNACK,
        // ACK and RSTACK messages. _resyncTimer is to detect the lost of
        // synchronisation between controller and switch. _retryTimer is a
        // timer do detect if resynchronization has been failed. _resyncTimer
        // and _retryTimer are not defined in RFC 1987.
        
        pfTimer _timerSYNC;
        pfTimer _resyncTimer;
        pfTimer _retryTimer;
        
        // Default expiration intervals (in msecs) for timers

        static const pfUlong DEFAULT_SYNC_TIMEOUT = 1000;
        static const pfUlong DEFAULT_RESYNC_TIMEOUT = 3000;
        static const pfUlong DEFAULT_RETRY_TIMEOUT = 60000;

        // Timer expiration intervals
        pfUlong _saveSYNCtimeout;
        pfUlong _resyncTimeout;
        pfUlong _retryTimeout;

        // At most one ACK should be sent between any successive SYNC-tics.
        // This is for counting them.

        bool _ACKlock;

        // Sender data

        string _nearEntityName;
        pfUlong _nearEntityPort;
        pfUlong _nearEntityInstance;

        // Receiver data

        string _farEntityName;
        pfUlong _farEntityPort;
        pfUlong _farEntityInstance;

        // Last sent data
        
        string _lastSentName;
        pfUlong _lastSentPort;
        pfUlong _lastSentInstance;

        // Last received data

        string _lastReceivedSenderName;
        string _lastReceivedReceiverName;
        pfUlong _lastReceivedSenderPort;
        pfUlong _lastReceivedReceiverPort;
        pfUlong _lastReceivedSenderInstance;
        pfUlong _lastReceivedReceiverInstance;
};

#endif // __GSMPADJACENCYPROTOCOL_H__
