The acceptor now stores all the objects in a set, and registers a callback with the client, to be notified when the connection is closed. On notification the client is them removed from the set and the memory is released. When the acceptor is destroyed, it also closes and deleted all the connected clients.
128 lines
3.9 KiB
C++
128 lines
3.9 KiB
C++
/*
|
|
* blockingServerTCPTransport.cpp
|
|
*
|
|
* Created on: Jan 4, 2011
|
|
* Author: Miha Vitorovic
|
|
*/
|
|
|
|
/* pvAccess */
|
|
#include "blockingTCP.h"
|
|
#include "remote.h"
|
|
|
|
/* pvData */
|
|
#include <lock.h>
|
|
#include <byteBuffer.h>
|
|
|
|
/* EPICSv3 */
|
|
#include <errlog.h>
|
|
|
|
/* standard */
|
|
#include <map>
|
|
|
|
using namespace epics::pvData;
|
|
using std::map;
|
|
|
|
namespace epics {
|
|
namespace pvAccess {
|
|
|
|
BlockingServerTCPTransport::BlockingServerTCPTransport(
|
|
Context* context, SOCKET channel,
|
|
ResponseHandler* responseHandler, int receiveBufferSize) :
|
|
BlockingTCPTransport(context, channel, responseHandler,
|
|
receiveBufferSize, CA_DEFAULT_PRIORITY),
|
|
_introspectionRegistry(new IntrospectionRegistry(true)),
|
|
_lastChannelSID(0), _channels(
|
|
new map<int, ServerChannel*> ()), _channelsMutex(
|
|
new Mutex()), _notifyOnClose(NULL) {
|
|
// NOTE: priority not yet known, default priority is used to register/unregister
|
|
// TODO implement priorities in Reactor... not that user will
|
|
// change it.. still getPriority() must return "registered" priority!
|
|
|
|
start();
|
|
}
|
|
|
|
BlockingServerTCPTransport::~BlockingServerTCPTransport() {
|
|
delete _introspectionRegistry;
|
|
delete _channels;
|
|
delete _channelsMutex;
|
|
}
|
|
|
|
void BlockingServerTCPTransport::destroyAllChannels() {
|
|
Lock lock(_channelsMutex);
|
|
if(_channels->size()==0) return;
|
|
|
|
char ipAddrStr[64];
|
|
ipAddrToA(&_socketAddress->ia, ipAddrStr, sizeof(ipAddrStr));
|
|
|
|
errlogSevPrintf(
|
|
errlogInfo,
|
|
"Transport to %s still has %d channel(s) active and closing...",
|
|
ipAddrStr, _channels->size());
|
|
|
|
map<int, ServerChannel*>::iterator it = _channels->begin();
|
|
for(; it!=_channels->end(); it++)
|
|
it->second->destroy();
|
|
|
|
_channels->clear();
|
|
}
|
|
|
|
void BlockingServerTCPTransport::internalClose(bool force) {
|
|
BlockingTCPTransport::internalClose(force);
|
|
if(_notifyOnClose!=NULL) _notifyOnClose->transportClosed(this);
|
|
destroyAllChannels();
|
|
}
|
|
|
|
int BlockingServerTCPTransport::preallocateChannelSID() {
|
|
Lock lock(_channelsMutex);
|
|
// search first free (theoretically possible loop of death)
|
|
int sid = ++_lastChannelSID;
|
|
while(_channels->find(sid)!=_channels->end())
|
|
sid = ++_lastChannelSID;
|
|
return sid;
|
|
}
|
|
|
|
void BlockingServerTCPTransport::registerChannel(int sid,
|
|
ServerChannel* channel) {
|
|
Lock lock(_channelsMutex);
|
|
(*_channels)[sid] = channel;
|
|
}
|
|
|
|
void BlockingServerTCPTransport::unregisterChannel(int sid) {
|
|
Lock lock(_channelsMutex);
|
|
_channels->erase(sid);
|
|
}
|
|
|
|
ServerChannel* BlockingServerTCPTransport::getChannel(int sid) {
|
|
Lock lock(_channelsMutex);
|
|
|
|
map<int, ServerChannel*>::iterator it = _channels->find(sid);
|
|
if(it!=_channels->end()) return it->second;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int BlockingServerTCPTransport::getChannelCount() {
|
|
Lock lock(_channelsMutex);
|
|
return _channels->size();
|
|
}
|
|
|
|
void BlockingServerTCPTransport::send(ByteBuffer* buffer,
|
|
TransportSendControl* control) {
|
|
//
|
|
// send verification message
|
|
//
|
|
control->startMessage(1, 2*sizeof(int32));
|
|
|
|
// receive buffer size
|
|
buffer->putInt(getReceiveBufferSize());
|
|
|
|
// socket receive buffer size
|
|
buffer->putInt(getSocketReceiveBufferSize());
|
|
|
|
// send immediately
|
|
control->flush(true);
|
|
}
|
|
|
|
}
|
|
}
|