//Editor-Info: -*- C++ -*-
//
//Subject: TOVE project
//
//File: gsmpadjacencyprotocol.cpp
//
//State: $State: Exp $
//
//Version: $Revision: 1.13 $
//
//Date: $Date: 1998/12/10 10:26:59 $
//
//Organisation:
//      Helsinki University of Technology
//      Laboratory of Telecommunications Software and Multimedia
// 
//Author:
//      Harri Sunila
//
//Description:
//      See corresponding header file.
//
//Copyright:    
//      Copyright 1999 Helsinki University of Technology
//      ALL RIGHTS RESERVED BETWEEN JANUARY 1996 AND JUNE 1999 
//      
//Licence:
//     
//
//History:
//

#include "gsmpadjacencyprotocol.h"
#include "gsmpadjacencystate.h"
#include "gsmpadjacencySYNSENTstate.h"
#include "gsmpadjacencySYNRCVDstate.h"
#include "gsmpadjacencyESTABstate.h"
#include "gsmpinternalmessages.h"
#include "gsmpexceptions.h"
#include "pf/bytes.h"
#include "pf/debug.h"

#include <stdlib.h>
#include <time.h>

// getESI() needs the following

#include <atm.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <linux/atmdev.h>
#include <stdio.h>

//
// Function: create 
//
// Description:  
//     This static method creates a new GSMP Adjacency Protocol Conduit. 

pfConduit gsmpAdjacencyProtocol :: create(pfUlong port_)
{
    gsmpAdjacencyProtocol *protocol = new gsmpAdjacencyProtocol;
    protocol->setPort(port_);
    protocol->getESI();

    pfConduit conduit(protocol);
    return conduit;
}

//
// Function: gsmpAdjacencyProtocol
//
// Description:
//     Constructor
//

gsmpAdjacencyProtocol::gsmpAdjacencyProtocol(void)
    : _timerSYNC(),
      _resyncTimer(),
      _retryTimer(),
      _saveSYNCtimeout(DEFAULT_SYNC_TIMEOUT),
      _resyncTimeout(DEFAULT_RESYNC_TIMEOUT),
      _retryTimeout(DEFAULT_RETRY_TIMEOUT),
      _ACKlock(0),
      _nearEntityName(),
      _nearEntityPort(0),
      _nearEntityInstance(0),
      _farEntityName(),
      _farEntityPort(0),
      _farEntityInstance(0),
      _lastSentName(),
      _lastSentPort(0),
      _lastSentInstance(0),
      _lastReceivedSenderName(),
      _lastReceivedReceiverName(),
      _lastReceivedSenderPort(0),
      _lastReceivedReceiverPort(0),
      _lastReceivedSenderInstance(0),
      _lastReceivedReceiverInstance(0)
{
    gsmpSYNCtimeout *syncMessenger = new gsmpSYNCtimeout;
    gsmpResyncTimeout *resyncMessenger = new gsmpResyncTimeout;
    gsmpRetryTimeout *retryMessenger = new gsmpRetryTimeout;
    
    generateNewInstanceNumber();
    
    _timerSYNC.setHost(this);
    _timerSYNC.setMessenger(syncMessenger);
    setSYNCtimeout(_saveSYNCtimeout);
    
    _resyncTimer.setHost(this);
    _resyncTimer.setMessenger(resyncMessenger);
    setResyncTimeout(_resyncTimeout);

    _retryTimer.setHost(this);
    _retryTimer.setMessenger(retryMessenger);
    setRetryTimeout(_retryTimeout);
    
    toAdjacencySYNSENTstate();
    return;
}

//
// Function: gsmpAdjacencyProtocol
//
// Description:
//     Copy constructor
//

gsmpAdjacencyProtocol::gsmpAdjacencyProtocol(
    const gsmpAdjacencyProtocol &other_)
    : _timerSYNC(other_._timerSYNC),
      _resyncTimer(other_._resyncTimer),
      _retryTimer(other_._retryTimer),
      _saveSYNCtimeout(other_._saveSYNCtimeout),
      _resyncTimeout(other_._resyncTimeout),
      _retryTimeout(other_._retryTimeout),
      _ACKlock(other_._ACKlock),
      _nearEntityName(other_._nearEntityName),
      _nearEntityPort(other_._nearEntityPort),
      _nearEntityInstance(other_._nearEntityInstance),
      _farEntityName(other_._farEntityName),
      _farEntityPort(other_._farEntityPort),
      _farEntityInstance(other_._farEntityInstance),
      _lastSentName(other_._lastSentName),
      _lastSentPort(other_._lastSentPort),
      _lastSentInstance(other_._lastSentInstance),
      _lastReceivedSenderName(other_._lastReceivedSenderName),
      _lastReceivedReceiverName(other_._lastReceivedReceiverName),
      _lastReceivedSenderPort(other_._lastReceivedSenderPort),
      _lastReceivedReceiverPort(other_._lastReceivedReceiverPort),
      _lastReceivedSenderInstance(other_._lastReceivedSenderInstance),
      _lastReceivedReceiverInstance(other_._lastReceivedReceiverInstance)
{
    gsmpSYNCtimeout *syncMessenger = new gsmpSYNCtimeout;
    gsmpResyncTimeout *resyncMessenger = new gsmpResyncTimeout;
    gsmpRetryTimeout *retryMessenger = new gsmpRetryTimeout;
    
    _timerSYNC.setHost(this);
    _timerSYNC.setMessenger(syncMessenger);
    setSYNCtimeout(_saveSYNCtimeout);
    
    _resyncTimer.setHost(this);
    _resyncTimer.setMessenger(resyncMessenger);
    setResyncTimeout(_resyncTimeout);

    _retryTimer.setHost(this);
    _retryTimer.setMessenger(retryMessenger);
    setRetryTimeout(_retryTimeout);

    toAdjacencySYNSENTstate();
    return;
}

//
// Function: ~gsmpAdjacencyProtocol
//
// Description:
//     Destructor
//

gsmpAdjacencyProtocol::~gsmpAdjacencyProtocol(void)
{
    return;
}

//
// Function: cloneImplementation
//
// Description: 
//

pfProtocol *gsmpAdjacencyProtocol :: cloneImplementation(void)
{
    pfProtocol *newProtocol = new gsmpAdjacencyProtocol(*this);
    return newProtocol;
}

//
// Function: sendAdjacencyProtocolSYNmessage
//
// Description:
//     This method sends Adjacency Protocol SYN Message to the switch.
//     It sends CPCS-UNITDATA.request to the CPCS-Adapter.
//

void gsmpAdjacencyProtocol::sendAdjacencyProtocolSYNmessage(void)
{
    pfFrame frame;
    // Save receiver information
    _lastSentName = _farEntityName;
    _lastSentPort = _farEntityPort;
    _lastSentInstance = _farEntityInstance;

    gsmpAdjacencyProtocolSYNmessage message(_nearEntityName,
                                            _farEntityName, 
                                            _nearEntityPort,
                                            _farEntityPort, 
                                            _nearEntityInstance,
                                            _farEntityInstance);
    try
    {
        frame = message.encodeFrame();
        sendCpcsUNITDATAreq(frame);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        exit(0);
    }
    return;
}

//
// Function: sendAdjacencyProtocolSYNACKmessage
//
// Description:
//     This method sends Adjacency Protocol SYNACK Message to the switch.
//     It sends CPCS-UNITDATA.request to the CPCS-Adapter.
//

void gsmpAdjacencyProtocol :: sendAdjacencyProtocolSYNACKmessage(void)
{
    pfFrame frame;
    // Save receiver information
    _lastSentName = _farEntityName;
    _lastSentPort = _farEntityPort;
    _lastSentInstance = _farEntityInstance;

    gsmpAdjacencyProtocolSYNACKmessage message(_nearEntityName,
                                               _farEntityName, 
                                               _nearEntityPort,
                                               _farEntityPort, 
                                               _nearEntityInstance,
                                               _farEntityInstance);
    try
    {
        frame = message.encodeFrame();
        sendCpcsUNITDATAreq(frame);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        exit(0);
    }
    return;
}

//
// Function: sendAdjacencyProtocolACKmessage
//
// Description:
//     This method sends Adjacency Protocol ACK Message to the switch.
//     It sends CPCS-UNITDATA.request to the CPCS-Adapter.
//

void gsmpAdjacencyProtocol :: sendAdjacencyProtocolACKmessage(void)
{
    if (acquireACKlock() != 0)
    {
        pfFrame frame;
        // Save receiver information
        _lastSentName = _farEntityName;
        _lastSentPort = _farEntityPort;
        _lastSentInstance = _farEntityInstance;

        gsmpAdjacencyProtocolACKmessage message(_nearEntityName,
                                                _farEntityName, 
                                                _nearEntityPort,
                                                _farEntityPort, 
                                                _nearEntityInstance,
                                                _farEntityInstance);
        try
        {
            frame = message.encodeFrame();
            sendCpcsUNITDATAreq(frame);
        }
        catch (pfException &exception)
        {
            exception.printInfo();
            exit(0);
        }
    }
    return;
}

//
// Function: sendAdjacencyProtocolRSTACKmessage
//
// Description:
//     This method sends Adjacency Protocol RSTACK Message to the switch.
//     It sends CPCS-UNITDATA.request to the CPCS-Adapter.
//

void gsmpAdjacencyProtocol :: sendAdjacencyProtocolRSTACKmessage(void)
{
    pfFrame frame;
    // Save receiver information
    _lastSentName = _lastReceivedSenderName;
    _lastSentPort = _lastReceivedSenderPort;
    _lastSentInstance = _lastReceivedSenderInstance;

    gsmpAdjacencyProtocolRSTACKmessage message(_lastReceivedReceiverName,
                                               _lastReceivedSenderName, 
                                               _lastReceivedReceiverPort,
                                               _lastReceivedSenderPort, 
                                               _lastReceivedReceiverInstance,
                                               _lastReceivedSenderInstance);
    try
    {
        frame = message.encodeFrame();
        sendCpcsUNITDATAreq(frame);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        exit(0);
    }
    return;
}

//
// Function: sendGsmpProtocolMessage 
//
// Description:
//     This is a general method to send GSMP Protocol Messages to the switch.
//     It encodes the message and calls the sendCpcsUNITDATAreq method.
//

void gsmpAdjacencyProtocol :: sendGsmpProtocolMessage(gsmpMessage *message_)
{
    try
    {
        pfFrame frame = message_->encodeFrame();
        sendCpcsUNITDATAreq(frame);
    }
    catch (pfException &exception)
    {
        exception.printInfo();
        exit(0);
    }
    return;
}

//
// Function: sendGsmpLinkEstablished 
//
// Description:
//     This is a method to send implementaition specific gsmpLinkEstablished
//     message to GSMP.
//

void gsmpAdjacencyProtocol :: sendGsmpLinkEstablished(void)
{
    gsmpLinkEstablished *message = new gsmpLinkEstablished;
    toB(message);
    return;
}

//
// Function: sendGsmpLinkNotEstablished 
//
// Description:
//     This is a method to send implementaition specific gsmpLinkNotEstablished
//     message to GSMP.
//

void gsmpAdjacencyProtocol :: sendGsmpLinkNotEstablished(void)
{
    gsmpLinkNotEstablished *message = new gsmpLinkNotEstablished;
    toB(message);
    return;
}

//
// Function: sendCpcsUNITDATAreq
//
// Description:
//     This method sends CPCS-UNITDATA.request. It is used by send methods
//     to actually send messages to the CPCS-Adapter
//

void gsmpAdjacencyProtocol :: sendCpcsUNITDATAreq(pfFrame &frame_)
{
    // Add the LLC/SNAP header
    frame_.putFirst(gsmpMessage::LLC_SNAP_HEADER,
                    sizeof(gsmpMessage::LLC_SNAP_HEADER));

    cpcsUNITDATAreq *message = new cpcsUNITDATAreq;
    message->setInterfaceData(frame_);
    toA(message);
    return;
}

//
// Function: setSYNCtimeout
//
// Description:
//     This method sets the Adjacency Protocol SYNC timeout 
//

void gsmpAdjacencyProtocol :: setSYNCtimeout(pfUlong msec_)
{
    _saveSYNCtimeout = msec_;
    _timerSYNC.setTimeout(_saveSYNCtimeout);
    return;
}

//
// Function: setResyncTimeout
//
// Description:
//     This method sets the Adjacency Protocol resynchronization timeout.
//

void gsmpAdjacencyProtocol :: setResyncTimeout(pfUlong msec_)
{
    _resyncTimeout = msec_;
    _resyncTimer.setTimeout(_resyncTimeout);
    return;
}

//
// Function: setRetryTimeout
//
// Description:
//     This method sets the Adjacency Protocol resynchronization timeout.
//

void gsmpAdjacencyProtocol :: setRetryTimeout(pfUlong msec_)
{
    _retryTimeout = msec_;
    _retryTimer.setTimeout(_retryTimeout);
    return;
}

//
// Function: setName
//
// Description:
//     This method sets name for controller
//

void gsmpAdjacencyProtocol :: setName(const string &nearEntityName_)
{
    if (nearEntityName_.length() != gsmpMessage::GSMP_SWITCH_NAME_LENGTH)
    {
        throw gsmpInvalidLengthException(PF_EX_INFO);
    }
    _nearEntityName = nearEntityName_;
    return;
}

//
// Function: setPort
//
// Description:
//     This method sets the port for controller 
//

void gsmpAdjacencyProtocol :: setPort(pfUlong nearEntityPort_)
{
    _nearEntityPort = nearEntityPort_;
    return;
}

//
// Function: generateNewInstanceNumber
//
// Description:
//     This method generates new unique instance number for the controller 
//

void gsmpAdjacencyProtocol :: generateNewInstanceNumber()
{
    if (_nearEntityInstance == 0)
    {
        srand(time(0));
        _nearEntityInstance = rand();
    }
    if (_nearEntityInstance == 0xFFFFFFFF)
    {
        _nearEntityInstance = 0;
    }
    _nearEntityInstance++;
    return;
}

//
// Function: updatePeerVerifier
//
// Description:
//     This function is described in RFC 1987 page 37. It stores the Sender
//     Name, Sender Port and Sender Instance from received Adjacency Protocol
//     SYN or SYNACK message.
//

void gsmpAdjacencyProtocol :: updatePeerVerifier(
    gsmpAdjacencyProtocolMessage *message_)
{
    _farEntityName = message_->getSenderName();
    _farEntityPort = message_->getSenderPort();
    _farEntityInstance = message_->getSenderInstance();
    return;
}

//
// Function: resetPeerVerifier
//
// Description:
//     This function deletes information about Sender previously stored by
//     "Update Peer Verifier" operation. 
//
  
void gsmpAdjacencyProtocol :: resetPeerVerifier(void)
{
    int length = _farEntityName.length();

#ifndef NON_STD_STL
    _farEntityName.erase(0, (length-1));
#else
    _farEntityName.remove(0, (length-1));
#endif // NON_STD_STL

    _farEntityPort = 0;
    _farEntityInstance = 0;
    return;
}

//
// Function: updateFarEntity
//
// Description:
//     This method updates information considering the far entity
//

void gsmpAdjacencyProtocol :: updateFarEntity(const string &farEntityName_,
                                              pfUlong farEntityPort_,
                                              pfUlong farEntityInstance_)
{
    _farEntityName = farEntityName_;
    _farEntityPort = farEntityPort_;
    _farEntityInstance = farEntityInstance_;
    return;
}

//
// Function: updateFarEntity
//
// Description:
//

void gsmpAdjacencyProtocol :: updateFarEntity(
    gsmpAdjacencyProtocolMessage *message_)
{
    _farEntityName = message_->getSenderName();
    _farEntityPort = message_->getSenderPort();
    _farEntityInstance = message_->getSenderInstance();
    return;
}

//
// Function: resetFarEntity  
//
// Description:
//     This method deletes information considering the far entity
//

void gsmpAdjacencyProtocol :: resetFarEntity(void)
{
    pfUlong i;
    for (i = 0; i < gsmpMessage::GSMP_SWITCH_NAME_LENGTH; i++)
    {
        _farEntityName[i] = B0000_0000;
    }
    _farEntityPort = 0;
    _farEntityInstance = 0;
    return;
}

//
// Function: updateLastReceivedData
//
// Description:
//     Save the name, port and instance of the sender.
//

void gsmpAdjacencyProtocol :: updateLastReceivedData(
    gsmpAdjacencyProtocolMessage *message_)
{
    _lastReceivedSenderName = message_->getSenderName();
    _lastReceivedSenderPort = message_->getSenderPort();
    _lastReceivedSenderInstance = message_->getSenderInstance();
    _lastReceivedReceiverName = message_->getReceiverName();
    _lastReceivedReceiverPort = message_->getReceiverPort();
    _lastReceivedReceiverInstance = message_->getReceiverInstance();
    return;
}

// Conditions A, B and C have been described in RFC 1987 page 37 & 38

//
// Function: conditionA
//
// Description:
//     This method returns TRUE if peer verifier instance is equal to the
//     sender instance of the message. Otherwise FALSE will be returned.
//

bool gsmpAdjacencyProtocol :: conditionA(
    gsmpAdjacencyProtocolMessage *message_)
{
    pfUlong peerVerifierInstance = message_->getSenderInstance();
    bool value = (_farEntityInstance == peerVerifierInstance); 
    return value;
}

//
// Function: conditionB 
//
// Description:
//     This method returns TRUE if sender instance, sender port and sender name
//     fields of the message match with the values stored from previus message.
//     Otherwise FALSE will be returned
//
 
bool gsmpAdjacencyProtocol :: conditionB(
    gsmpAdjacencyProtocolMessage *message_)
{
    pfUlong peerVerifierInstance = message_->getSenderInstance();
    pfUlong peerVerifierPort = message_->getSenderPort();
    string peerVerifierName = message_->getSenderName();
    bool value = ((_farEntityInstance == peerVerifierInstance) &&
                       (_farEntityPort == peerVerifierPort) &&
                       (_farEntityName == peerVerifierName));
    return value;
}

//
// Function: conditionC
//
// Description:
//     This method returns TRUE if receiver instance, receiver port and
//     receiver name fields match with the sender instance, sender port
//     and sender name fields currently sent outgoing Adjacency Protocol
//     SYN, SYNACK and ACK message.
//

bool gsmpAdjacencyProtocol :: conditionC(
    gsmpAdjacencyProtocolMessage *message_)
{
    pfUlong receiverInstance = message_->getReceiverInstance();
    pfUlong receiverPort = message_->getReceiverPort();
    string receiverName = message_->getReceiverName();
    bool value = ((_nearEntityInstance == receiverInstance) &&
                       (_nearEntityPort == receiverPort) &&
                       (_nearEntityName == receiverName));
    return value;
}

//
// Function: releaseACKlock
//
// Description:
//     This method enables sending of Adjacency Protocol ACK messages.
//

void gsmpAdjacencyProtocol :: releaseACKlock(void)
{
    _ACKlock = false;
    return;
}

//
// Function: acquireACKlock 
//
// Description:
//     This method turns the ACK lock TRUE and returns FALSE
//     if the ACK lock is already TRUE
//

bool gsmpAdjacencyProtocol :: acquireACKlock(void)
{
    if (_ACKlock == true)
    {
        return false;
    }
    _ACKlock = true;
    return true;
} 

//
// Function: toAdjacencySYNSENTstate 
//
// Description:
//     This method changes the state of the protocol to
//     gsmpAdjacencySYNSENTstate
//

void gsmpAdjacencyProtocol :: toAdjacencySYNSENTstate(void)
{
    changeState(gsmpAdjacencySYNSENTstate::instance());
    return;
}

//
// Function: toAdjacencySYNRCVDstate 
//
// Description:
//     This method changes the state of the protocol to
//     gsmpAdjacencySYNRCVDstate
//

void gsmpAdjacencyProtocol :: toAdjacencySYNRCVDstate(void)
{
    changeState(gsmpAdjacencySYNRCVDstate::instance());
    return;
}

//
// Function: toAdjacencyESTABstate 
//
// Description:
//     This method changes the state of the protocol to
//     gsmpAdjacencyESTABstate
//

void gsmpAdjacencyProtocol :: toAdjacencyESTABstate(void)
{
    changeState(gsmpAdjacencyESTABstate::instance());
    return;
}

//
// Function: startTimer 
//
// Description:
//     A method to start the timer, which generates periodic SYN, SYNACK, ACK
//     and RSTACK messages.
//

void gsmpAdjacencyProtocol :: startTimer(void)
{
    _timerSYNC.start();
    return;
}

//
// Function: stopTimer 
//
// Description:
//     A method to stop the timer, which generates periodic SYN, SYNACK, ACK
//     and RSTACK messages.
//

void gsmpAdjacencyProtocol :: stopTimer(void)
{
    _timerSYNC.stop();
    return;
}

//
// Function: isTimerActive 
//
// Description:
//     This method returns true, if _timerSync is running.
//

bool gsmpAdjacencyProtocol :: isTimerActive(void) const
{
    bool returnValue = _timerSYNC.isActive();
    return returnValue;
}

//
// Function: startResyncTimer 
//
// Description:
//     A method to start the timer, which timeout indicates the lost of
//     synchronization.
//

void gsmpAdjacencyProtocol :: startResyncTimer(void)
{
    _resyncTimer.start();
    return;
}

//
// Function: stopResyncTimer 
//
// Description:
//     A method to start the timer, which timeout indicates the lost of
//     synchronization.
//

void gsmpAdjacencyProtocol :: stopResyncTimer(void)
{
    _resyncTimer.stop();
    return;
}

//
// Function: startRetryTimer 
//
// Description:
//     A method to start the timer, which timeout indicates the failure of
//     resynchronization.
//

void gsmpAdjacencyProtocol :: startRetryTimer(void)
{
    _retryTimer.start();
    return;
}

//
// Function: stopRetryTimer 
//
// Description:
//     A method to start the timer, which timeout indicates the failure of
//     resynchronization.
//

void gsmpAdjacencyProtocol :: stopRetryTimer(void)
{
    _retryTimer.stop();
    return;
}

//
// Function: resyncFailed
//
// Description:
//     A method to start the timer, which timeout indicates the failue of
//     resynchronization.
//

void gsmpAdjacencyProtocol :: resyncFailed(void)
{
    debugUser("Resynchronization failed: halting the Adjacency Protocol");
    stopTimer();
}

//
// Function: getESI 
//
// Description: 
//     This method uses a specific ioctl to provide the ESI to be used as
//     _nearEntityName. This method access directy the ATM interface to
//     provide a proper socket descriptor for ioctl.
//

void gsmpAdjacencyProtocol :: getESI(void)
{
    // This method should be applied only once in the switch controller
    if (_nearEntityName.length() == 0)
    {
        int s;
        struct atmif_sioc atmif;
        struct sockaddr_atmpvc addr;
        struct atm_qos qos;
        char buffer[ESI_LEN];

        // Open an ATM socket

        if ((s = socket(PF_ATMPVC, SOCK_DGRAM, ATM_AAL5)) < 0)
        {
            cerr << "Error in socket" << endl;
            perror("socket");
            exit(1);
        }
        
        // Set the QoS parameters. The traffic class ATM_NONE should be used,
        // but apparently it does not seem to work;
        memset(&qos, 0, sizeof(qos));
        qos.txtp.traffic_class = ATM_UBR;
        qos.txtp.max_sdu = 8192;
        qos.rxtp = qos.txtp;

        // Bind the traffic parameters and the socket.   
        if (setsockopt(s, SOL_ATM, SO_ATMQOS, &qos, sizeof(qos)) < 0)
        {
            cerr << "Error in setsockopt" << endl;
            perror("setsockopt");
            close(s);
            exit(1);
        }

        // Set the address parameters. The interface is defined as the
        // parameter of this method. VPI/VCI pair is obsolete and thus
        // may be freely selected (ANY).
        
        memset(&addr, 0, sizeof(addr));
        addr.sap_family = AF_ATMPVC;
        addr.sap_addr.itf = _nearEntityPort;
        addr.sap_addr.vpi = ATM_VPI_ANY;
        addr.sap_addr.vci = ATM_VCI_ANY;
        
        // Connect
        if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0)
        {
            cerr << "Error in connect" << endl;
            perror("connect");
            close(s);
            exit(1);
        }
        
        // Get the ESI using ioctl
        atmif.number = _nearEntityPort;
        atmif.length = ESI_LEN;
        atmif.arg = buffer;
        if (ioctl(s, ATM_GETESI, &atmif) < 0)
        {
            cerr << "Error in ioctl" << endl;
            perror("ioctl");
            exit(1);
        }

        // Close the socket
        close(s);
        
        // Set the information in _nearEntityName
        string esi((const char *)buffer, ESI_LEN);
        _nearEntityName = esi;
    }
    return;
}
