added aliases to configuration. an alias is another name for

a screen.  it's expected that the server will want to accept
a given client under several names (e.g. the hostname and the
FQDN).
This commit is contained in:
crs 2002-06-08 23:24:40 +00:00
parent 562e3aebb5
commit 8b2a282eb5
4 changed files with 274 additions and 65 deletions

View File

@ -17,19 +17,29 @@ CConfig::~CConfig()
// do nothing // do nothing
} }
void CConfig::addScreen(const CString& name) bool CConfig::addScreen(const CString& name)
{ {
if (m_map.count(name) != 0) { // alias name must not exist
assert(0 && "name already in map"); // FIXME -- throw instead if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) {
return false;
} }
// add cell
m_map.insert(std::make_pair(name, CCell())); m_map.insert(std::make_pair(name, CCell()));
// add name
m_nameToCanonicalName.insert(std::make_pair(name, name));
return true;
} }
void CConfig::removeScreen(const CString& name) void CConfig::removeScreen(const CString& name)
{ {
CCellMap::iterator index = m_map.find(name); // get canonical name and find cell
CString canonical = getCanonicalName(name);
CCellMap::iterator index = m_map.find(canonical);
if (index == m_map.end()) { if (index == m_map.end()) {
assert(0 && "name not in map"); // FIXME -- throw instead return;
} }
// remove from map // remove from map
@ -39,42 +49,111 @@ void CConfig::removeScreen(const CString& name)
for (index = m_map.begin(); index != m_map.end(); ++index) { for (index = m_map.begin(); index != m_map.end(); ++index) {
CCell& cell = index->second; CCell& cell = index->second;
for (SInt32 i = 0; i <= kLastDirection - kFirstDirection; ++i) for (SInt32 i = 0; i <= kLastDirection - kFirstDirection; ++i)
if (cell.m_neighbor[i] == name) { if (getCanonicalName(cell.m_neighbor[i]) == canonical) {
cell.m_neighbor[i].erase(); cell.m_neighbor[i].erase();
} }
} }
// remove aliases (and canonical name)
for (CNameMap::iterator index = m_nameToCanonicalName.begin();
index != m_nameToCanonicalName.end(); ) {
if (index->second == canonical) {
m_nameToCanonicalName.erase(index++);
}
else {
++index;
}
}
} }
void CConfig::removeAllScreens() void CConfig::removeAllScreens()
{ {
m_map.clear(); m_map.clear();
m_nameToCanonicalName.clear();
} }
void CConfig::connect(const CString& srcName, bool CConfig::addAlias(const CString& canonical,
const CString& alias)
{
// alias name must not exist
if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) {
return false;
}
// canonical name must be known
if (m_nameToCanonicalName.find(canonical) == m_nameToCanonicalName.end()) {
return false;
}
// insert alias
m_nameToCanonicalName.insert(std::make_pair(alias, canonical));
return true;
}
bool CConfig::removeAlias(const CString& alias)
{
// must not be a canonical name
if (m_map.find(alias) != m_map.end()) {
return false;
}
// find alias
CNameMap::iterator index = m_nameToCanonicalName.find(alias);
if (index == m_nameToCanonicalName.end()) {
return false;
}
// remove alias
m_nameToCanonicalName.erase(index);
return true;
}
void CConfig::removeAllAliases()
{
// remove all names
m_nameToCanonicalName.clear();
// put the canonical names back in
for (CCellMap::iterator index = m_map.begin();
index != m_map.end(); ++index) {
m_nameToCanonicalName.insert(
std::make_pair(index->first, index->first));
}
}
bool CConfig::connect(const CString& srcName,
EDirection srcSide, EDirection srcSide,
const CString& dstName) const CString& dstName)
{ {
// find source cell // find source cell
CCellMap::iterator index = m_map.find(srcName); CCellMap::iterator index = m_map.find(getCanonicalName(srcName));
if (index == m_map.end()) { if (index == m_map.end()) {
assert(0 && "name not in map"); // FIXME -- throw instead return false;
} }
// connect side (overriding any previous connection) // connect side (overriding any previous connection). we
// canonicalize in getNeighbor() instead of here because the
// destination name doesn't have to exist yet.
index->second.m_neighbor[srcSide - kFirstDirection] = dstName; index->second.m_neighbor[srcSide - kFirstDirection] = dstName;
return true;
} }
void CConfig::disconnect(const CString& srcName, bool CConfig::disconnect(const CString& srcName,
EDirection srcSide) EDirection srcSide)
{ {
// find source cell // find source cell
CCellMap::iterator index = m_map.find(srcName); CCellMap::iterator index = m_map.find(srcName);
if (index == m_map.end()) { if (index == m_map.end()) {
assert(0 && "name not in map"); // FIXME -- throw instead return false;
} }
// disconnect side // disconnect side
index->second.m_neighbor[srcSide - kFirstDirection].erase(); index->second.m_neighbor[srcSide - kFirstDirection].erase();
return true;
} }
bool CConfig::isValidScreenName(const CString& name) const bool CConfig::isValidScreenName(const CString& name) const
@ -133,20 +212,37 @@ CConfig::const_iterator CConfig::end() const
bool CConfig::isScreen(const CString& name) const bool CConfig::isScreen(const CString& name) const
{ {
return (m_map.count(name) > 0); return (m_nameToCanonicalName.count(name) > 0);
}
bool CConfig::isCanonicalName(const CString& name) const
{
return CStringUtil::CaselessCmp::equal(getCanonicalName(name), name);
}
CString CConfig::getCanonicalName(const CString& name) const
{
CNameMap::const_iterator index = m_nameToCanonicalName.find(name);
if (index == m_nameToCanonicalName.end()) {
return CString();
}
else {
return index->second;
}
} }
CString CConfig::getNeighbor(const CString& srcName, CString CConfig::getNeighbor(const CString& srcName,
EDirection srcSide) const EDirection srcSide) const
{ {
// find source cell // find source cell
CCellMap::const_iterator index = m_map.find(srcName); CCellMap::const_iterator index = m_map.find(getCanonicalName(srcName));
if (index == m_map.end()) { if (index == m_map.end()) {
assert(0 && "name not in map"); // FIXME -- throw instead return CString();
} }
// return connection // return connection
return index->second.m_neighbor[srcSide - kFirstDirection]; return getCanonicalName(index->second.m_neighbor[
srcSide - kFirstDirection]);
} }
const char* CConfig::dirName(EDirection dir) const char* CConfig::dirName(EDirection dir)
@ -183,6 +279,7 @@ void CConfig::readSection(std::istream& s)
static const char s_section[] = "section:"; static const char s_section[] = "section:";
static const char s_screens[] = "screens"; static const char s_screens[] = "screens";
static const char s_links[] = "links"; static const char s_links[] = "links";
static const char s_aliases[] = "aliases";
CString line; CString line;
if (!readLine(s, line)) { if (!readLine(s, line)) {
@ -213,6 +310,9 @@ void CConfig::readSection(std::istream& s)
else if (name == s_links) { else if (name == s_links) {
readSectionLinks(s); readSectionLinks(s);
} }
else if (name == s_aliases) {
readSectionAliases(s);
}
else { else {
throw XConfigRead("unknown section name"); throw XConfigRead("unknown section name");
} }
@ -239,7 +339,9 @@ void CConfig::readSectionScreens(std::istream& s)
} }
// add the screen to the configuration // add the screen to the configuration
addScreen(name); if (!addScreen(name)) {
throw XConfigRead("duplicate screen name");
}
} }
else if (name.empty()) { else if (name.empty()) {
throw XConfigRead("argument before first screen"); throw XConfigRead("argument before first screen");
@ -266,10 +368,13 @@ void CConfig::readSectionLinks(std::istream& s)
// strip : // strip :
screen = line.substr(0, line.size() - 1); screen = line.substr(0, line.size() - 1);
// verify we known about the screen // verify we know about the screen
if (!isScreen(screen)) { if (!isScreen(screen)) {
throw XConfigRead("unknown screen name"); throw XConfigRead("unknown screen name");
} }
if (!isCanonicalName(screen)) {
throw XConfigRead("cannot use screen name alias here");
}
} }
else if (screen.empty()) { else if (screen.empty()) {
throw XConfigRead("argument before first screen"); throw XConfigRead("argument before first screen");
@ -328,6 +433,47 @@ void CConfig::readSectionLinks(std::istream& s)
throw XConfigRead("unexpected end of links section"); throw XConfigRead("unexpected end of links section");
} }
void CConfig::readSectionAliases(std::istream& s)
{
CString line;
CString screen;
while (readLine(s, line)) {
// check for end of section
if (line == "end") {
return;
}
// see if it's the next screen
if (line[line.size() - 1] == ':') {
// strip :
screen = line.substr(0, line.size() - 1);
// verify we know about the screen
if (!isScreen(screen)) {
throw XConfigRead("unknown screen name");
}
if (!isCanonicalName(screen)) {
throw XConfigRead("cannot use screen name alias here");
}
}
else if (screen.empty()) {
throw XConfigRead("argument before first screen");
}
else {
// verify validity of screen name
if (!isValidScreenName(line)) {
throw XConfigRead("invalid screen alias");
}
// add alias
if (!addAlias(screen, line)) {
throw XConfigRead("alias is duplicate screen name");
}
}
}
throw XConfigRead("unexpected end of aliases section");
}
// //
// CConfig I/O // CConfig I/O
@ -384,6 +530,33 @@ std::ostream& operator<<(std::ostream& s, const CConfig& config)
} }
s << "end" << std::endl; s << "end" << std::endl;
// aliases section (if there are any)
if (config.m_map.size() != config.m_nameToCanonicalName.size()) {
// map canonical to alias
CConfig::CNameMap aliases;
for (CConfig::CNameMap::const_iterator
index = config.m_nameToCanonicalName.begin();
index != config.m_nameToCanonicalName.end();
++index) {
if (index->first != index->second) {
aliases.insert(std::make_pair(index->second, index->first));
}
}
// dump it
CString screen;
s << "section: aliases" << std::endl;
for (CConfig::CNameMap::const_iterator index = aliases.begin();
index != aliases.end(); ++index) {
if (index->first != screen) {
screen = index->first;
s << "\t" << screen.c_str() << std::endl;
}
s << "\t\t" << index->second.c_str() << std::endl;
}
s << "end" << std::endl;
}
return s; return s;
} }

View File

@ -6,6 +6,7 @@
#include "XBase.h" #include "XBase.h"
#include <iosfwd> #include <iosfwd>
#include "stdmap.h" #include "stdmap.h"
#include "stdset.h"
class CConfig; class CConfig;
@ -66,18 +67,33 @@ public:
// manipulators // manipulators
// note that case is preserved in screen names but is ignored when // note that case is preserved in screen names but is ignored when
// comparing names. // comparing names. screen names and their aliases share a
// namespace and must be unique.
// add/remove screens // add/remove screens. addScreen() returns false if the name
void addScreen(const CString& name); // already exists. the remove methods automatically remove
// aliases for the named screen and disconnect any connections
// to the removed screen(s).
bool addScreen(const CString& name);
void removeScreen(const CString& name); void removeScreen(const CString& name);
void removeAllScreens(); void removeAllScreens();
// connect edges // add/remove alias for a screen name. an alias can be used
void connect(const CString& srcName, // any place the canonical screen name can (except addScreen).
// addAlias() returns false if the alias name already exists
// or the canonical name is unknown. removeAlias() fails if
// the alias is unknown or a canonical name.
bool addAlias(const CString& canonical,
const CString& alias);
bool removeAlias(const CString& alias);
void removeAllAliases();
// connect/disconnect edges. both return false if srcName is
// unknown.
bool connect(const CString& srcName,
EDirection srcSide, EDirection srcSide,
const CString& dstName); const CString& dstName);
void disconnect(const CString& srcName, bool disconnect(const CString& srcName,
EDirection srcSide); EDirection srcSide);
// accessors // accessors
@ -85,15 +101,23 @@ public:
// returns true iff the given name is a valid screen name. // returns true iff the given name is a valid screen name.
bool isValidScreenName(const CString&) const; bool isValidScreenName(const CString&) const;
// iterators over screen names // iterators over (canonical) screen names
const_iterator begin() const; const_iterator begin() const;
const_iterator end() const; const_iterator end() const;
// returns true iff name names a screen // returns true iff name names a screen
bool isScreen(const CString& name) const; bool isScreen(const CString& name) const;
// returns true iff name is the canonical name of a screen
bool isCanonicalName(const CString& name) const;
// returns the canonical name of a screen or the empty string if
// the name is unknown. returns the canonical name if one is given.
CString getCanonicalName(const CString& name) const;
// get the neighbor in the given direction. returns the empty string // get the neighbor in the given direction. returns the empty string
// if there is no neighbor in that direction. // if there is no neighbor in that direction. returns the canonical
// screen name.
CString getNeighbor(const CString&, EDirection) const; CString getNeighbor(const CString&, EDirection) const;
// read/write a configuration. operator>> will throw XConfigRead // read/write a configuration. operator>> will throw XConfigRead
@ -109,9 +133,13 @@ private:
void readSection(std::istream&); void readSection(std::istream&);
void readSectionScreens(std::istream&); void readSectionScreens(std::istream&);
void readSectionLinks(std::istream&); void readSectionLinks(std::istream&);
void readSectionAliases(std::istream&);
private: private:
typedef std::map<CString, CString, CStringUtil::CaselessCmp> CNameMap;
CCellMap m_map; CCellMap m_map;
CNameMap m_nameToCanonicalName;
}; };
class XConfigRead : public XBase { class XConfigRead : public XBase {

View File

@ -171,38 +171,31 @@ bool CServer::setConfig(const CConfig& config)
} }
// get the set of screens that are connected but are being // get the set of screens that are connected but are being
// dropped from the configuration. don't add the primary // dropped from the configuration (or who's canonical name
// screen. also tell the secondary screen to disconnect. // is changing). don't add the primary screen. also tell
// the secondary screen to disconnect.
for (CScreenList::const_iterator index = m_screens.begin(); for (CScreenList::const_iterator index = m_screens.begin();
index != m_screens.end(); ++index) { index != m_screens.end(); ++index) {
if (!config.isScreen(index->first) && if (index->second != m_primaryInfo &&
index->second != m_primaryInfo) { !config.isCanonicalName(index->first)) {
assert(index->second->m_protocol != NULL); assert(index->second->m_protocol != NULL);
index->second->m_protocol->sendClose(); index->second->m_protocol->sendClose();
threads.push_back(index->second->m_thread); threads.push_back(index->second->m_thread);
} }
} }
}
// wait a moment to allow each secondary screen to close // wait a moment to allow each secondary screen to close
// its connection before we close it (to avoid having our // its connection before we close it (to avoid having our
// socket enter TIME_WAIT). // socket enter TIME_WAIT).
if (threads.size() > 0) { if (threads.size() > 0) {
CThread::sleep(1.0); CThread::sleep(1.0);
} }
// cancel the old secondary screen threads // cancel the old secondary screen threads
for (CThreads::iterator index = threads.begin(); for (CThreads::iterator index = threads.begin();
index != threads.end(); ++index) { index != threads.end(); ++index) {
index->cancel(); index->cancel();
}
// cut over
m_config = config;
// tell primary screen about reconfiguration
if (m_primary != NULL) {
m_primary->onConfigure();
}
} }
// wait for old secondary screen threads to disconnect. must // wait for old secondary screen threads to disconnect. must
@ -213,6 +206,15 @@ bool CServer::setConfig(const CConfig& config)
index->wait(); index->wait();
} }
// cut over
CLock lock(&m_mutex);
m_config = config;
// tell primary screen about reconfiguration
if (m_primary != NULL) {
m_primary->onConfigure();
}
return true; return true;
} }
@ -280,7 +282,8 @@ void CServer::setInfoNoLock(const CString& screen,
assert(zoneSize >= 0); assert(zoneSize >= 0);
// screen must be connected // screen must be connected
CScreenList::iterator index = m_screens.find(screen); CString screenName = m_config.getCanonicalName(screen);
CScreenList::iterator index = m_screens.find(screenName);
if (index == m_screens.end()) { if (index == m_screens.end()) {
throw XBadClient(); throw XBadClient();
} }
@ -339,14 +342,15 @@ void CServer::grabClipboardNoLock(
CClipboardInfo& clipboard = m_clipboards[id]; CClipboardInfo& clipboard = m_clipboards[id];
// screen must be connected // screen must be connected
CScreenList::iterator index = m_screens.find(screen); CString screenName = m_config.getCanonicalName(screen);
CScreenList::iterator index = m_screens.find(screenName);
if (index == m_screens.end()) { if (index == m_screens.end()) {
throw XBadClient(); throw XBadClient();
} }
// ignore grab if sequence number is old. always allow primary // ignore grab if sequence number is old. always allow primary
// screen to grab. // screen to grab.
if (screen != m_primaryInfo->m_name && if (screenName != m_primaryInfo->m_name &&
seqNum < clipboard.m_clipboardSeqNum) { seqNum < clipboard.m_clipboardSeqNum) {
log((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", screen.c_str(), id)); log((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", screen.c_str(), id));
return; return;
@ -354,7 +358,7 @@ void CServer::grabClipboardNoLock(
// mark screen as owning clipboard // mark screen as owning clipboard
log((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", screen.c_str(), id, clipboard.m_clipboardOwner.c_str())); log((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", screen.c_str(), id, clipboard.m_clipboardOwner.c_str()));
clipboard.m_clipboardOwner = screen; clipboard.m_clipboardOwner = screenName;
clipboard.m_clipboardSeqNum = seqNum; clipboard.m_clipboardSeqNum = seqNum;
// no screens have the new clipboard except the sender // no screens have the new clipboard except the sender
@ -363,7 +367,7 @@ void CServer::grabClipboardNoLock(
// tell all other screens to take ownership of clipboard // tell all other screens to take ownership of clipboard
for (index = m_screens.begin(); index != m_screens.end(); ++index) { for (index = m_screens.begin(); index != m_screens.end(); ++index) {
if (index->first != screen) { if (index->first != screenName) {
CScreenInfo* info = index->second; CScreenInfo* info = index->second;
if (info->m_protocol == NULL) { if (info->m_protocol == NULL) {
m_primary->grabClipboard(id); m_primary->grabClipboard(id);
@ -1460,19 +1464,21 @@ CServer::CScreenInfo* CServer::addConnection(
CLock lock(&m_mutex); CLock lock(&m_mutex);
// can only have one screen with a given name at any given time
if (m_screens.count(name) != 0) {
throw XDuplicateClient(name);
}
// name must be in our configuration // name must be in our configuration
if (!m_config.isScreen(name)) { if (!m_config.isScreen(name)) {
throw XUnknownClient(name); throw XUnknownClient(name);
} }
CString screenName = m_config.getCanonicalName(name);
// can only have one screen with a given name at any given time
if (m_screens.count(screenName) != 0) {
throw XDuplicateClient(name);
}
// save screen info // save screen info
CScreenInfo* newScreen = new CScreenInfo(name, protocol); CScreenInfo* newScreen = new CScreenInfo(screenName, protocol);
m_screens.insert(std::make_pair(name, newScreen)); m_screens.insert(std::make_pair(screenName, newScreen));
log((CLOG_DEBUG "added connection \"%s\" (\"%s\")", name.c_str(), screenName.c_str()));
return newScreen; return newScreen;
} }
@ -1483,7 +1489,8 @@ void CServer::removeConnection(const CString& name)
CLock lock(&m_mutex); CLock lock(&m_mutex);
// find screen info // find screen info
CScreenList::iterator index = m_screens.find(name); CString screenName = m_config.getCanonicalName(name);
CScreenList::iterator index = m_screens.find(screenName);
assert(index != m_screens.end()); assert(index != m_screens.end());
// if this is active screen then we have to jump off of it // if this is active screen then we have to jump off of it

View File

@ -394,14 +394,15 @@ static bool loadConfig(const char* pathname, bool require)
log((CLOG_DEBUG "configuration read successfully")); log((CLOG_DEBUG "configuration read successfully"));
return true; return true;
} }
catch (XConfigRead&) { catch (XConfigRead& e) {
if (require) { if (require) {
log((CLOG_PRINT "%s: cannot read configuration '%s'", log((CLOG_PRINT "%s: cannot read configuration '%s': %s",
pname, pathname)); pname, pathname, e.what()));
bye(3); bye(3);
} }
else { else {
log((CLOG_DEBUG "cannot read configuration \"%s\"", pathname)); log((CLOG_DEBUG "cannot read configuration \"%s\": %s",
pathname, e.what()));
} }
} }
return false; return false;