diff --git a/client/client.cpp b/client/client.cpp index 6297ad38..b34010a0 100644 --- a/client/client.cpp +++ b/client/client.cpp @@ -32,7 +32,7 @@ static bool s_daemon = true; static bool s_install = false; static bool s_uninstall = false; static const char* s_logFilter = NULL; -static const char* s_serverName = NULL; +static CNetworkAddress s_serverAddress; // @@ -62,8 +62,6 @@ static CClient* s_client = NULL; static int realMain(CMutex* mutex) { - static const UInt16 port = 50001; // FIXME - try { // initialize threading library CThread::init(); @@ -75,11 +73,7 @@ static int realMain(CMutex* mutex) bool locked = true; try { - // initialize network library - CNetwork::init(); - // create client - CNetworkAddress addr(s_serverName, port); s_client = new CClient("secondary"); // FIXME // run client @@ -87,7 +81,7 @@ static int realMain(CMutex* mutex) mutex->unlock(); } locked = false; - s_client->run(addr); + s_client->run(s_serverAddress); locked = true; if (mutex != NULL) { mutex->lock(); @@ -194,9 +188,13 @@ static void help() "\n" "* marks defaults.\n" "\n" +"The server address is of the form: [][:]. The hostname\n" +"must be the address or hostname of the server. The port overrides the\n" +"default port, %d.\n" +"\n" "Where log messages go depends on the platform and whether or not the\n" "client is running as a "DAEMON".", - pname)); + pname, kDefaultPort)); } @@ -334,7 +332,16 @@ static void parse(int argc, const char** argv) pname, argv[i], pname)); bye(2); } - s_serverName = argv[i]; + + // save server address + try { + s_serverAddress = CNetworkAddress(argv[i], kDefaultPort); + } + catch (XSocketAddress&) { + log((CLOG_PRINT "%s: invalid server address" BYE, + pname, pname)); + bye(2); + } } // increase default filter level for daemon. the user must @@ -445,6 +452,9 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) // get program name pname = platform.getBasename(__argv[0]); + // initialize network library + CNetwork::init(); + // parse command line without reporting errors but recording if // the app would've exited. this is too avoid showing a dialog // box if we're being started as a service because we shouldn't @@ -504,7 +514,7 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) commandLine += s_logFilter; } commandLine += " "; - commandLine += s_serverName; + commandLine += s_serverAddress.getHostname().c_str(); // install if (!platform.installDaemon(DAEMON_NAME, @@ -560,6 +570,9 @@ int main(int argc, char** argv) // get program name pname = platform.getBasename(argv[0]); + // initialize network library + CNetwork::init(); + // parse command line parse(argc, const_cast(argv)); diff --git a/net/CNetwork.cpp b/net/CNetwork.cpp index 6bbf7511..30f68913 100644 --- a/net/CNetwork.cpp +++ b/net/CNetwork.cpp @@ -15,13 +15,9 @@ int (PASCAL FAR *CNetwork::ioctl)(CNetwork::Socket s, int cmd, ...); int (PASCAL FAR *CNetwork::getpeername)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen); int (PASCAL FAR *CNetwork::getsockname)(CNetwork::Socket s, CNetwork::Address FAR *name, CNetwork::AddressLength FAR * namelen); int (PASCAL FAR *CNetwork::getsockopt)(CNetwork::Socket s, int level, int optname, void FAR * optval, CNetwork::AddressLength FAR *optlen); -UInt32 (PASCAL FAR *CNetwork::swaphtonl)(UInt32 hostlong); -UInt16 (PASCAL FAR *CNetwork::swaphtons)(UInt16 hostshort); unsigned long (PASCAL FAR *CNetwork::inet_addr)(const char FAR * cp); char FAR * (PASCAL FAR *CNetwork::inet_ntoa)(struct in_addr in); int (PASCAL FAR *CNetwork::listen)(CNetwork::Socket s, int backlog); -UInt32 (PASCAL FAR *CNetwork::swapntohl)(UInt32 netlong); -UInt16 (PASCAL FAR *CNetwork::swapntohs)(UInt16 netshort); ssize_t (PASCAL FAR *CNetwork::read)(CNetwork::Socket s, void FAR * buf, size_t len); ssize_t (PASCAL FAR *CNetwork::recv)(CNetwork::Socket s, void FAR * buf, size_t len, int flags); ssize_t (PASCAL FAR *CNetwork::recvfrom)(CNetwork::Socket s, void FAR * buf, size_t len, int flags, CNetwork::Address FAR *from, CNetwork::AddressLength FAR * fromlen); @@ -113,6 +109,38 @@ void CNetwork::cleanup() } } +UInt32 CNetwork::swaphtonl(UInt32 v) +{ + static const union { UInt16 s; UInt8 b[2]; } s_endian = { 0x1234 }; + if (s_endian.b[0] == 0x34) + return ((v & 0xff000000lu) >> 24) | + ((v & 0x00ff0000lu) >> 8) | + ((v & 0x0000ff00lu) << 8) | + ((v & 0x000000fflu) << 24); + else + return v; +} + +UInt16 CNetwork::swaphtons(UInt16 v) +{ + static const union { UInt16 s; UInt8 b[2]; } s_endian = { 0x1234 }; + if (s_endian.b[0] == 0x34) + return ((v & 0xff00u) >> 8) | + ((v & 0x00ffu) << 8); + else + return v; +} + +UInt32 CNetwork::swapntohl(UInt32 v) +{ + return swaphtonl(v); +} + +UInt16 CNetwork::swapntohs(UInt16 v) +{ + return swaphtons(v); +} + #define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name) void CNetwork::init2(HMODULE module) @@ -141,13 +169,9 @@ void CNetwork::init2(HMODULE module) setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen)); setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen)); setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen)); - setfunc(swaphtonl, htonl, UInt32 (PASCAL FAR *)(UInt32 hostlong)); - setfunc(swaphtons, htons, UInt16 (PASCAL FAR *)(UInt16 hostshort)); setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp)); setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in)); setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog)); - setfunc(swapntohl, ntohl, UInt32 (PASCAL FAR *)(UInt32 netlong)); - setfunc(swapntohs, ntohs, UInt16 (PASCAL FAR *)(UInt16 netshort)); setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags)); setfunc(recvfrom, recvfrom, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen)); setfunc(send, send, ssize_t (PASCAL FAR *)(Socket s, const void FAR * buf, size_t len, int flags)); @@ -259,22 +283,22 @@ ssize_t PASCAL FAR CNetwork::write2(Socket s, #define setfunc(var, name, type) var = (type)::name -static UInt32 myhtonl(UInt32 v) +UInt32 CNetwork::swaphtonl(UInt32 v) { return htonl(v); } -static UInt16 myhtons(UInt16 v) +UInt16 CNetwork::swaphtons(UInt16 v) { return htons(v); } -static UInt32 myntohl(UInt32 v) +UInt32 CNetwork::swapntohl(UInt32 v) { return ntohl(v); } -static UInt16 myntohs(UInt16 v) +UInt16 CNetwork::swapntohs(UInt16 v) { return ntohs(v); } @@ -307,13 +331,9 @@ void CNetwork::init() setfunc(getpeername, getpeername, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen)); setfunc(getsockname, getsockname, int (PASCAL FAR *)(Socket s, Address FAR *name, AddressLength FAR * namelen)); setfunc(getsockopt, getsockopt, int (PASCAL FAR *)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen)); - setfunc(swaphtonl, myhtonl, UInt32 (PASCAL FAR *)(UInt32 hostlong)); - setfunc(swaphtons, myhtons, UInt16 (PASCAL FAR *)(UInt16 hostshort)); setfunc(inet_addr, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp)); setfunc(inet_ntoa, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in)); setfunc(listen, listen, int (PASCAL FAR *)(Socket s, int backlog)); - setfunc(swapntohl, myntohl, UInt32 (PASCAL FAR *)(UInt32 netlong)); - setfunc(swapntohs, myntohs, UInt16 (PASCAL FAR *)(UInt16 netshort)); setfunc(poll, poll, int (PASCAL FAR *)(CNetwork::PollEntry fds[], int nfds, int timeout)); setfunc(read, read, ssize_t (PASCAL FAR *)(CNetwork::Socket s, void FAR * buf, size_t len)); setfunc(recv, recv, ssize_t (PASCAL FAR *)(Socket s, void FAR * buf, size_t len, int flags)); diff --git a/net/CNetwork.h b/net/CNetwork.h index 696973da..1fa01afa 100644 --- a/net/CNetwork.h +++ b/net/CNetwork.h @@ -69,6 +69,12 @@ public: static void init(); static void cleanup(); + // byte swapping functions + static UInt32 swaphtonl(UInt32 hostlong); + static UInt16 swaphtons(UInt16 hostshort); + static UInt32 swapntohl(UInt32 netlong); + static UInt16 swapntohs(UInt16 netshort); + // constants static const int Error; @@ -100,7 +106,7 @@ public: kHNone = 0 }; - // socket interface + // socket interface (only available after init()) static Socket (PASCAL FAR *accept)(Socket s, Address FAR *addr, AddressLength FAR *addrlen); static int (PASCAL FAR *bind)(Socket s, const Address FAR *addr, AddressLength namelen); @@ -110,13 +116,9 @@ public: static int (PASCAL FAR *getpeername)(Socket s, Address FAR *name, AddressLength FAR * namelen); static int (PASCAL FAR *getsockname)(Socket s, Address FAR *name, AddressLength FAR * namelen); static int (PASCAL FAR *getsockopt)(Socket s, int level, int optname, void FAR * optval, AddressLength FAR *optlen); - static UInt32 (PASCAL FAR *swaphtonl)(UInt32 hostlong); - static UInt16 (PASCAL FAR *swaphtons)(UInt16 hostshort); static unsigned long (PASCAL FAR *inet_addr)(const char FAR * cp); static char FAR * (PASCAL FAR *inet_ntoa)(struct in_addr in); static int (PASCAL FAR *listen)(Socket s, int backlog); - static UInt32 (PASCAL FAR *swapntohl)(UInt32 netlong); - static UInt16 (PASCAL FAR *swapntohs)(UInt16 netshort); static ssize_t (PASCAL FAR *read)(Socket s, void FAR * buf, size_t len); static ssize_t (PASCAL FAR *recv)(Socket s, void FAR * buf, size_t len, int flags); static ssize_t (PASCAL FAR *recvfrom)(Socket s, void FAR * buf, size_t len, int flags, Address FAR *from, AddressLength FAR * fromlen); diff --git a/net/CNetworkAddress.cpp b/net/CNetworkAddress.cpp index 1d832475..0e07605e 100644 --- a/net/CNetworkAddress.cpp +++ b/net/CNetworkAddress.cpp @@ -1,26 +1,102 @@ #include "CNetworkAddress.h" +#include "CString.h" +#include // // CNetworkAddress // -CNetworkAddress::CNetworkAddress(UInt16 port) +CNetworkAddress::CNetworkAddress() : m_port(0) { - if (port == 0) - throw XSocketAddress(XSocketAddress::kBadPort, CString(), port); + // note -- make no calls to CNetwork socket interface here; + // we're often called prior to CNetwork::init(). - struct sockaddr_in* inetAddress = reinterpret_cast(&m_address); + struct sockaddr_in* inetAddress = reinterpret_cast< + struct sockaddr_in*>(&m_address); inetAddress->sin_family = AF_INET; - inetAddress->sin_port = CNetwork::swaphtons(port); + inetAddress->sin_port = CNetwork::swaphtons(m_port); inetAddress->sin_addr.s_addr = INADDR_ANY; memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); } -CNetworkAddress::CNetworkAddress(const CString& hostname, UInt16 port) +CNetworkAddress::CNetworkAddress(UInt16 port) : m_port(port) { - if (port == 0) - throw XSocketAddress(XSocketAddress::kBadPort, hostname, port); + if (port == 0) { + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } + struct sockaddr_in* inetAddress = reinterpret_cast< + struct sockaddr_in*>(&m_address); + inetAddress->sin_family = AF_INET; + inetAddress->sin_port = CNetwork::swaphtons(m_port); + inetAddress->sin_addr.s_addr = INADDR_ANY; + memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); +} + +CNetworkAddress::CNetworkAddress(const CString& hostname_, UInt16 port) : + m_hostname(hostname_), + m_port(port) +{ + CString hostname(m_hostname); + + if (port == 0) { + throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); + } + + // check for port suffix + CString::size_type i = hostname.rfind(':'); + if (i != CString::npos && i + 1 < hostname.size()) { + // found a colon. see if it looks like an IPv6 address. + bool colonNotation = false; + bool dotNotation = false; + bool doubleColon = false; + for (CString::size_type j = 0; j < i; ++j) { + if (hostname[j] == ':') { + colonNotation = true; + dotNotation = false; + if (hostname[j + 1] == ':') { + doubleColon = true; + } + } + else if (hostname[j] == '.' && colonNotation) { + dotNotation = true; + } + } + + // port suffix is ambiguous with IPv6 notation if there's + // a double colon and the end of the address is not in dot + // notation. in that case we assume it's not a port suffix. + // the user can replace the double colon with zeros to + // disambiguate. + if ((!doubleColon || dotNotation) || !colonNotation) { + char* end; + long suffixPort = strtol(hostname.c_str() + i + 1, &end, 10); + if (end == hostname.c_str() + i + 1 || *end != '\0' || + suffixPort <= 0 || suffixPort > 65535) { + // bogus port + throw XSocketAddress(XSocketAddress::kBadPort, + m_hostname, m_port); + } + else { + // good port + port = static_cast(suffixPort); + hostname.erase(i); + } + } + } + + // if hostname is empty then use wildcard address + if (hostname.empty()) { + struct sockaddr_in* inetAddress = reinterpret_cast< + struct sockaddr_in*>(&m_address); + inetAddress->sin_family = AF_INET; + inetAddress->sin_port = CNetwork::swaphtons(port); + inetAddress->sin_addr.s_addr = INADDR_ANY; + memset(inetAddress->sin_zero, 0, sizeof(inetAddress->sin_zero)); + return; + } + + // look up name struct hostent* hent = CNetwork::gethostbyname(hostname.c_str()); if (hent == NULL) { switch (CNetwork::gethosterror()) { @@ -37,7 +113,8 @@ CNetworkAddress::CNetworkAddress(const CString& hostname, UInt16 port) } } - struct sockaddr_in* inetAddress = reinterpret_cast(&m_address); + struct sockaddr_in* inetAddress = reinterpret_cast< + struct sockaddr_in*>(&m_address); inetAddress->sin_family = hent->h_addrtype; inetAddress->sin_port = CNetwork::swaphtons(port); memcpy(&inetAddress->sin_addr, hent->h_addr_list[0], hent->h_length); @@ -49,6 +126,11 @@ CNetworkAddress::~CNetworkAddress() // do nothing } +bool CNetworkAddress::isValid() const +{ + return (m_port != 0); +} + const CNetwork::Address* CNetworkAddress::getAddress() const { return &m_address; @@ -58,3 +140,13 @@ CNetwork::AddressLength CNetworkAddress::getAddressLength() const { return sizeof(m_address); } + +CString CNetworkAddress::getHostname() const +{ + return m_hostname; +} + +UInt16 CNetworkAddress::getPort() const +{ + return m_port; +} diff --git a/net/CNetworkAddress.h b/net/CNetworkAddress.h index 6b1729d5..08750e29 100644 --- a/net/CNetworkAddress.h +++ b/net/CNetworkAddress.h @@ -1,27 +1,48 @@ #ifndef CNETWORKADDRESS_H #define CNETWORKADDRESS_H -#include "BasicTypes.h" #include "CNetwork.h" #include "XSocket.h" - -class CString; +#include "CString.h" +#include "BasicTypes.h" class CNetworkAddress { public: + // invalid address + CNetworkAddress(); + + // wildcard address and given port. port must not be zero. CNetworkAddress(UInt16 port); + + // given address and port. if hostname can be parsed as numerical + // address then that's how it's used, otherwise the hostname is + // looked up. if lookup fails then it throws XSocketAddress. if + // hostname ends in ":[0-9]+" then that suffix is extracted and + // used as the port, overridding the port parameter. neither + // port may be zero. CNetworkAddress(const CString& hostname, UInt16 port); + ~CNetworkAddress(); // manipulators // accessors + // returns true if this is not the invalid address + bool isValid() const; + + // get the address const CNetwork::Address* getAddress() const; CNetwork::AddressLength getAddressLength() const; + // get the hostname and port (as provided in the c'tor) + CString getHostname() const; + UInt16 getPort() const; + private: CNetwork::Address m_address; + CString m_hostname; + UInt16 m_port; }; #endif diff --git a/net/XSocket.cpp b/net/XSocket.cpp index d5478908..983e9eae 100644 --- a/net/XSocket.cpp +++ b/net/XSocket.cpp @@ -5,7 +5,7 @@ // XSocketAddress::XSocketAddress(Error error, - const CString& hostname, SInt16 port) throw() : + const CString& hostname, UInt16 port) throw() : m_error(error), m_hostname(hostname), m_port(port) @@ -23,7 +23,7 @@ CString XSocketAddress::getHostname() const throw() return m_hostname; } -SInt16 XSocketAddress::getPort() const throw() +UInt16 XSocketAddress::getPort() const throw() { return m_port; } diff --git a/net/XSocket.h b/net/XSocket.h index 7a5cc6f5..1a83c99d 100644 --- a/net/XSocket.h +++ b/net/XSocket.h @@ -11,13 +11,13 @@ class XSocketAddress : public XSocket { public: enum Error { kUnknown, kNotFound, kNoAddress, kBadPort }; - XSocketAddress(Error, const CString& hostname, SInt16 port) throw(); + XSocketAddress(Error, const CString& hostname, UInt16 port) throw(); // accessors virtual Error getError() const throw(); virtual CString getHostname() const throw(); - virtual SInt16 getPort() const throw(); + virtual UInt16 getPort() const throw(); protected: // XBase overrides @@ -26,7 +26,7 @@ protected: private: Error m_error; CString m_hostname; - SInt16 m_port; + UInt16 m_port; }; class XSocketErrno : public XSocket, public MXErrno { diff --git a/server/CConfig.cpp b/server/CConfig.cpp index 84f8789c..4d82366d 100644 --- a/server/CConfig.cpp +++ b/server/CConfig.cpp @@ -1,4 +1,5 @@ #include "CConfig.h" +#include "ProtocolTypes.h" #include "stdistream.h" #include "stdostream.h" #include @@ -156,6 +157,16 @@ bool CConfig::disconnect(const CString& srcName, return true; } +void CConfig::setSynergyAddress(const CNetworkAddress& addr) +{ + m_synergyAddress = addr; +} + +void CConfig::setHTTPAddress(const CNetworkAddress& addr) +{ + m_httpAddress = addr; +} + bool CConfig::isValidScreenName(const CString& name) const { // name is valid if matches validname @@ -245,6 +256,16 @@ CString CConfig::getNeighbor(const CString& srcName, srcSide - kFirstDirection]); } +const CNetworkAddress& CConfig::getSynergyAddress() const +{ + return m_synergyAddress; +} + +const CNetworkAddress& CConfig::getHTTPAddress() const +{ + return m_httpAddress; +} + const char* CConfig::dirName(EDirection dir) { static const char* s_name[] = { "left", "right", "top", "bottom" }; @@ -277,6 +298,7 @@ bool CConfig::readLine(std::istream& s, CString& line) void CConfig::readSection(std::istream& s) { static const char s_section[] = "section:"; + static const char s_network[] = "network"; static const char s_screens[] = "screens"; static const char s_links[] = "links"; static const char s_aliases[] = "aliases"; @@ -304,7 +326,10 @@ void CConfig::readSection(std::istream& s) } // read section - if (name == s_screens) { + if (name == s_network) { + readSectionNetwork(s); + } + else if (name == s_screens) { readSectionScreens(s); } else if (name == s_links) { @@ -318,6 +343,61 @@ void CConfig::readSection(std::istream& s) } } +void CConfig::readSectionNetwork(std::istream& s) +{ + CString line; + CString name; + while (readLine(s, line)) { + // check for end of section + if (line == "end") { + return; + } + + // parse argument: `=' + CString::size_type i = line.find_first_of(" \t="); + if (i == 0) { + throw XConfigRead("missing argument name"); + } + if (i == CString::npos) { + throw XConfigRead("missing = in argument"); + } + CString name = line.substr(0, i); + i = line.find_first_not_of(" \t", i); + if (i == CString::npos || line[i] != '=') { + throw XConfigRead("missing = in argument"); + } + i = line.find_first_not_of(" \t", i + 1); + CString value; + if (i != CString::npos) { + value = line.substr(i); + } + if (value.empty()) { + throw XConfigRead("missing value after ="); + } + + if (name == "address") { + try { + m_synergyAddress = CNetworkAddress(value, kDefaultPort); + } + catch (XSocketAddress&) { + throw XConfigRead("invalid address argument"); + } + } + else if (name == "http") { + try { + m_httpAddress = CNetworkAddress(value, kDefaultPort + 1); + } + catch (XSocketAddress&) { + throw XConfigRead("invalid http argument"); + } + } + else { + throw XConfigRead("unknown argument"); + } + } + throw XConfigRead("unexpected end of screens section"); +} + void CConfig::readSectionScreens(std::istream& s) { CString line; @@ -493,6 +573,18 @@ std::istream& operator>>(std::istream& s, CConfig& config) std::ostream& operator<<(std::ostream& s, const CConfig& config) { + // network section + s << "section: network" << std::endl; + if (config.m_synergyAddress.isValid()) { + s << "\taddress=" << config.m_synergyAddress.getHostname().c_str() << + std::endl; + } + if (config.m_httpAddress.isValid()) { + s << "\thttp=" << config.m_httpAddress.getHostname().c_str() << + std::endl; + } + s << "end" << std::endl; + // screens section s << "section: screens" << std::endl; for (CConfig::const_iterator screen = config.begin(); diff --git a/server/CConfig.h b/server/CConfig.h index f97c7a0a..73f4a911 100644 --- a/server/CConfig.h +++ b/server/CConfig.h @@ -3,6 +3,7 @@ #include "BasicTypes.h" #include "CString.h" +#include "CNetworkAddress.h" #include "XBase.h" #include #include "stdmap.h" @@ -96,6 +97,11 @@ public: bool disconnect(const CString& srcName, EDirection srcSide); + // set the synergy and http listen addresses. there are no + // default addresses. + void setSynergyAddress(const CNetworkAddress&); + void setHTTPAddress(const CNetworkAddress&); + // accessors // returns true iff the given name is a valid screen name. @@ -120,6 +126,10 @@ public: // screen name. CString getNeighbor(const CString&, EDirection) const; + // get the listen addresses + const CNetworkAddress& getSynergyAddress() const; + const CNetworkAddress& getHTTPAddress() const; + // read/write a configuration. operator>> will throw XConfigRead // on error. friend std::istream& operator>>(std::istream&, CConfig&); @@ -131,6 +141,7 @@ public: private: static bool readLine(std::istream&, CString&); void readSection(std::istream&); + void readSectionNetwork(std::istream&); void readSectionScreens(std::istream&); void readSectionLinks(std::istream&); void readSectionAliases(std::istream&); @@ -140,6 +151,8 @@ private: CCellMap m_map; CNameMap m_nameToCanonicalName; + CNetworkAddress m_synergyAddress; + CNetworkAddress m_httpAddress; }; class XConfigRead : public XBase { diff --git a/server/CHTTPServer.cpp b/server/CHTTPServer.cpp index d85b0978..95cb6d43 100644 --- a/server/CHTTPServer.cpp +++ b/server/CHTTPServer.cpp @@ -308,6 +308,7 @@ void CHTTPServer::doProcessPostEditMap( // convert temporary screen map into a regular map CConfig config; + m_server->getConfig(&config); screens.convertTo(config); // set new screen map on server @@ -719,6 +720,8 @@ bool CHTTPServer::CScreenArray::convertFrom( void CHTTPServer::CScreenArray::convertTo( CConfig& config) const { + config.removeAllScreens(); + // add screens and find smallest box containing all screens SInt32 x0 = m_w, x1 = 0, y0 = m_h, y1 = 0; for (SInt32 y = 0; y < m_h; ++y) { diff --git a/server/CServer.cpp b/server/CServer.cpp index 85e65179..475bf5ef 100644 --- a/server/CServer.cpp +++ b/server/CServer.cpp @@ -83,13 +83,15 @@ void CServer::run() } } - // start listening for HTTP requests - m_httpServer = new CHTTPServer(this); - CThread(new TMethodJob(this, &CServer::acceptHTTPClients)); - // start listening for new clients CThread(new TMethodJob(this, &CServer::acceptClients)); + // start listening for HTTP requests + if (m_config.getHTTPAddress().isValid()) { + m_httpServer = new CHTTPServer(this); + CThread(new TMethodJob(this, &CServer::acceptHTTPClients)); + } + // handle events log((CLOG_DEBUG "starting event handling")); m_primary->run(); @@ -982,11 +984,10 @@ void CServer::acceptClients(void*) // bind to the desired port. keep retrying if we can't bind // the address immediately. CStopwatch timer; - CNetworkAddress addr(50001 /* FIXME -- m_port */); for (;;) { try { log((CLOG_DEBUG1 "binding listen socket")); - listen->bind(addr); + listen->bind(m_config.getSynergyAddress()); break; } catch (XSocketAddressInUse&) { @@ -1166,11 +1167,10 @@ void CServer::acceptHTTPClients(void*) // bind to the desired port. keep retrying if we can't bind // the address immediately. CStopwatch timer; - CNetworkAddress addr(50002 /* FIXME -- m_httpPort */); for (;;) { try { - log((CLOG_DEBUG1 "binding listen socket")); - listen->bind(addr); + log((CLOG_DEBUG1 "binding HTTP listen socket")); + listen->bind(m_config.getHTTPAddress()); break; } catch (XSocketAddressInUse&) { diff --git a/server/CServer.h b/server/CServer.h index 37b1eb8f..ab4c92a2 100644 --- a/server/CServer.h +++ b/server/CServer.h @@ -6,6 +6,7 @@ #include "MouseTypes.h" #include "CConfig.h" #include "CClipboard.h" +#include "CNetworkAddress.h" #include "CCondVar.h" #include "CMutex.h" #include "CString.h" diff --git a/server/server.cpp b/server/server.cpp index 2a54cb03..c0c553d5 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -39,6 +39,8 @@ static bool s_install = false; static bool s_uninstall = false; static const char* s_configFile = NULL; static const char* s_logFilter = NULL; +static CNetworkAddress s_synergyAddress; +static CNetworkAddress s_httpAddress; static CConfig s_config; @@ -67,6 +69,7 @@ static void logLock(bool lock) static CServer* s_server = NULL; +#include static int realMain(CMutex* mutex) { // s_serverLock should have mutex locked on entry @@ -82,15 +85,27 @@ static int realMain(CMutex* mutex) bool locked = true; try { - // initialize network library - CNetwork::init(); - // if configuration has no screens then add this system // as the default if (s_config.begin() == s_config.end()) { s_config.addScreen("primary"); } + // set the contact address, if provided, in the config. + // otherwise, if the config doesn't have an address, use + // the default. + if (s_synergyAddress.isValid()) { + s_config.setSynergyAddress(s_synergyAddress); + } + else if (!s_config.getSynergyAddress().isValid()) { + s_config.setSynergyAddress(CNetworkAddress(kDefaultPort)); + } + + // set HTTP address is provided + if (s_httpAddress.isValid()) { + s_config.setHTTPAddress(s_httpAddress); + } + // create server s_server = new CServer(); @@ -195,6 +210,7 @@ static void help() "\n" "Start the synergy mouse/keyboard sharing server.\n" "\n" +" -a, --address
listen for clients on the given address.\n" " -c, --config use the named configuration file instead\n" " where ~ represents the user's home directory.\n" " -d, --debug filter out log messages with priorty below level.\n" @@ -212,6 +228,11 @@ static void help() "\n" "* marks defaults.\n" "\n" +"The argument for --address is of the form: [][:]. The\n" +"hostname must be the address or hostname of an interface on the system.\n" +"The default is to listen on all interfaces. The port overrides the\n" +"default port, %d.\n" +"\n" "If no configuration file pathname is provided then the first of the\n" "following to load sets the configuration:\n" " %s\n" @@ -222,6 +243,7 @@ static void help() "Where log messages go depends on the platform and whether or not the\n" "server is running as a "DAEMON".", pname, + kDefaultPort, platform.addPathComponent( platform.getUserDirectory(), CONFIG_NAME).c_str(), @@ -265,6 +287,32 @@ static void parse(int argc, const char** argv) s_logFilter = argv[++i]; } + else if (isArg(i, argc, argv, "-a", "--address", 1)) { + // save listen address + try { + s_synergyAddress = CNetworkAddress(argv[i + 1], kDefaultPort); + } + catch (XSocketAddress&) { + log((CLOG_PRINT "%s: invalid address for `%s'" BYE, + pname, argv[i], pname)); + bye(2); + } + ++i; + } + + else if (isArg(i, argc, argv, NULL, "--http", 1)) { + // save listen address + try { + s_httpAddress = CNetworkAddress(argv[i + 1], kDefaultPort + 1); + } + catch (XSocketAddress&) { + log((CLOG_PRINT "%s: invalid address for `%s'" BYE, + pname, argv[i], pname)); + bye(2); + } + ++i; + } + else if (isArg(i, argc, argv, "-c", "--config", 1)) { // save configuration file path s_configFile = argv[++i]; @@ -527,6 +575,9 @@ int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) // get program name pname = platform.getBasename(__argv[0]); + // initialize network library + CNetwork::init(); + // parse command line without reporting errors but recording if // the app would've exited. this is too avoid showing a dialog // box if we're being started as a service because we shouldn't @@ -649,6 +700,9 @@ int main(int argc, char** argv) // get program name pname = platform.getBasename(argv[0]); + // initialize network library + CNetwork::init(); + // parse command line parse(argc, const_cast(argv)); diff --git a/synergy/ProtocolTypes.h b/synergy/ProtocolTypes.h index 32cd4e0b..b60fc831 100644 --- a/synergy/ProtocolTypes.h +++ b/synergy/ProtocolTypes.h @@ -7,6 +7,9 @@ static const SInt16 kProtocolMajorVersion = 0; static const SInt16 kProtocolMinorVersion = 1; +// contact port number +static const UInt16 kDefaultPort = 24800; + // // message codes (trailing NUL is not part of code). in comments, $n // refers to the n'th argument (counting from one). message codes are