diff --git a/Xcode/BZFlag.xcodeproj/Makefile.am b/Xcode/BZFlag.xcodeproj/Makefile.am new file mode 100644 index 0000000000..b9b35698f8 --- /dev/null +++ b/Xcode/BZFlag.xcodeproj/Makefile.am @@ -0,0 +1,5 @@ +EXTRA_DIST = \ + project.pbxproj + +MAINTAINERCLEANFILES = \ + Makefile.in diff --git a/data/l10n/bzflag_es.po b/data/l10n/bzflag_es.po index a2678d6cf5..a6d7e4d8fd 100644 --- a/data/l10n/bzflag_es.po +++ b/data/l10n/bzflag_es.po @@ -2024,7 +2024,7 @@ msgstr "<** Código de paquete UDP %x tamaño %x\n" msgid "Fallback to normal TCP receive" msgstr "Retraso en recepción TCP normal" -msgid "Communication error joining game [No immediate respose]." +msgid "Communication error joining game [No immediate response]." msgstr "Error de comunicación al unirse a la partida [No hay respuesta inmediata]." msgid "Server forced disconnection." diff --git a/data/l10n/bzflag_ru.po b/data/l10n/bzflag_ru.po index 164ae1128d..2d4ea62ae8 100644 --- a/data/l10n/bzflag_ru.po +++ b/data/l10n/bzflag_ru.po @@ -2323,7 +2323,7 @@ msgstr "<** UDP Kod paketa %x dlina %x\n" msgid "Fallback to normal TCP receive" msgstr "Vozvrat k obychnomu priyomu TCP" -msgid "Communication error joining game [No immediate respose]." +msgid "Communication error joining game [No immediate response]." msgstr "Oshibka ustanovki svyazi s igroj [net nemedlennogo otveta]" msgid "Server forced disconnection." diff --git a/data/l10n/bzflag_sk.po b/data/l10n/bzflag_sk.po index 1bb61db3c5..e8a6354b52 100644 --- a/data/l10n/bzflag_sk.po +++ b/data/l10n/bzflag_sk.po @@ -2312,7 +2312,7 @@ msgstr "<** UDP kod paketu %x Dlzka %x\n" msgid "Fallback to normal TCP receive" msgstr "Navrat k obycajnemu prijmu TCP" -msgid "Communication error joining game [No immediate respose]." +msgid "Communication error joining game [No immediate response]." msgstr "Chyba komunikacie pri pripajani sa k hre [Ziadna bezprostredna odpoved]." msgid "Server forced disconnection." diff --git a/data/l10n/bzflag_xx.po b/data/l10n/bzflag_xx.po index 352629fbe9..28f3e1f626 100644 --- a/data/l10n/bzflag_xx.po +++ b/data/l10n/bzflag_xx.po @@ -2370,7 +2370,7 @@ msgstr "" msgid "Fallback to normal TCP receive" msgstr "" -msgid "Communication error joining game [No immediate respose]." +msgid "Communication error joining game [No immediate response]." msgstr "" msgid "Server forced disconnection." diff --git a/include/Address.h b/include/Address.h index b5865f2d71..465720365b 100644 --- a/include/Address.h +++ b/include/Address.h @@ -33,11 +33,11 @@ #include "Pack.h" #include "Protocol.h" -typedef struct in_addr InAddr; // shorthand - // helpers char *sockaddr2iptext(const struct sockaddr *sa); char *sockaddr2iptextport(const struct sockaddr *sa); +bool splitNamePort(std::string nameport, std::string &name, int &port); +std::string joinNamePort(std::string name, int port); class Address { @@ -45,17 +45,25 @@ class Address Address(); Address(const std::string&); Address(const Address&); - Address(const InAddr&); // input in nbo - Address(const struct sockaddr_in&); // input in nbo + Address(const Address *); + Address(const struct sockaddr_in6*); // input in nbo ~Address(); Address& operator=(const Address&); - operator InAddr() const; bool operator==(const Address&) const; bool operator!=(const Address&) const; bool operator<(Address const&) const; + bool isMapped() const; bool isAny() const; bool isPrivate() const; + sockaddr *getAddr(); + sockaddr_in *getAddr_in(); + sockaddr_in6 *getAddr_in6(); + /* return port in network order */ + in_port_t getNPort() const; + std::string getIpText(); + std::string getIpTextPort(); + std::string getDotNotation() const; uint8_t getIPVersion() const; @@ -63,11 +71,12 @@ class Address const void* unpack(const void*); static Address getHostAddress(const std::string &hostname = std::string("")); - static std::string getHostByAddress(InAddr); static const std::string getHostName(const std::string &hostname = std::string("")); private: - std::vector addr; + struct sockaddr_in6 addr; + std::string iptext; + std::string iptextport; }; // FIXME - enum maybe? put into namespace or class cage? @@ -78,21 +87,6 @@ const PlayerId AdminPlayers = 252; const PlayerId FirstTeam = 251; const PlayerId LastRealPlayer = FirstTeam - NumTeams; -class ServerId -{ -public: - void* pack(void*) const; - const void* unpack(const void*); - - bool operator==(const ServerId&) const; - bool operator!=(const ServerId&) const; - -public: - // host and port in network byte order - struct sockaddr_in addr; - int16_t number; // local player number -}; - #endif // BZF_INET_ADDR_H // Local Variables: *** diff --git a/include/AresHandler.h b/include/AresHandler.h index dc81504dbb..5b31d007b1 100644 --- a/include/AresHandler.h +++ b/include/AresHandler.h @@ -43,10 +43,11 @@ class AresHandler { index = i; } - void queryHostname(const struct sockaddr *clientAddr); - void queryHost(const char *hostName); + void queryHostname(const sockaddr *); + void queryHost(const char *hostName, const char *service); const char *getHostname(); - ResolutionStatus getHostAddress(struct in_addr *clientAddr); + ResolutionStatus getHostAddress(in_addr *); + ResolutionStatus getHostAddr(sockaddr_in6 *); void setFd(fd_set *read_set, fd_set *write_set, int &maxFile); void process(fd_set *read_set, fd_set *write_set); ResolutionStatus getStatus() @@ -55,23 +56,25 @@ class AresHandler }; private: #if ARES_VERSION_MAJOR >= 1 && ARES_VERSION_MINOR >= 5 - static void staticCallback(void *arg, int statusCallback, int timeouts, - struct hostent *hostent); + static void staticHostCallback(void *arg, int statusCallback, int timeouts, hostent *); #else - static void staticCallback(void *arg, int statusCallback, - struct hostent *hostent); + static void staticHostCallback(void *arg, int statusCallback, hostent *); #endif - void callback(int status, struct hostent *hostent); + void callback(int status, hostent *); + + static void staticAddrInfoCallback(void *arg, int callbackStatus, int, ares_addrinfo *result); + void callback(int callbackStatus, ares_addrinfo *result); + int index; std::string hostName; in_addr hostAddress; + sockaddr_in6 hostAddr; ares_channel aresChannel; ResolutionStatus status; bool aresFailed; static bool globallyInited; - }; #endif diff --git a/include/NetHandler.h b/include/NetHandler.h index 86ab7c1aca..a32d9a20c2 100644 --- a/include/NetHandler.h +++ b/include/NetHandler.h @@ -75,10 +75,10 @@ class NetHandler a player Index, a unique pointer to a player the file descriptor for the TCP connection with the user. */ - NetHandler(PlayerInfo *_info, const struct sockaddr_in &_clientAddr, + NetHandler(PlayerInfo *_info, const struct sockaddr_in6 &_clientAddr, int _playerIndex, int _fd); - NetHandler(const struct sockaddr_in &_clientAddr, int _fd); + NetHandler(const struct sockaddr_in6 &_clientAddr, int _fd); /** The default destructor free all internal resources, and close the tcp connection @@ -90,7 +90,7 @@ class NetHandler InitHandlers needs the addr structure filled to point to the local port needed for udp communications */ - static bool initHandlers(struct sockaddr_in addr); + static bool initHandlers(Address addr); static void destroyHandlers(); /// General function to support the select statement @@ -117,7 +117,7 @@ class NetHandler udpLinkRequest report if the received message is a valid udpLinkRequest */ - static int udpReceive(char *buffer, struct sockaddr_in *uaddr, + static int udpReceive(char *buffer, struct sockaddr_in6 *uaddr, bool &udpLinkRequest); /** @@ -152,8 +152,7 @@ class NetHandler int sizeOfIP(); void* packAdminInfo(void *buf); static int whoIsAtIP(const std::string& IP); - in_addr getIPAddress(); - const char* getHostname(); + const char* getHostname(); bool reverseDNSDone(); size_t getTcpReadSize () @@ -181,9 +180,14 @@ class NetHandler { return fd; } - const struct sockaddr *getUADDR ( void ) + Address *getTaddr ( void ) { - return (const struct sockaddr *)&uaddr; + return &taddr; + } + + Address *getUaddr ( void ) + { + return &uaddr; } // Returns the time that the connection was accepted @@ -208,7 +212,7 @@ class NetHandler private: int send(const void *buffer, size_t length); void udpSend(const void *b, size_t l); - bool isMyUdpAddrPort(struct sockaddr_in uaddr); + bool isMyUaddr(const Address uaddr); #ifdef NETWORK_STATS void countMessage(uint16_t code, int len, int direction); void dumpMessageStats(); @@ -222,8 +226,8 @@ class NetHandler std::shared_ptr ares; PlayerInfo* info; - struct sockaddr_in taddr; - struct sockaddr_in uaddr; + Address taddr; + Address uaddr; int playerIndex; int fd; // socket file descriptor diff --git a/include/Ping.h b/include/Ping.h index 07745bce41..9b0557986e 100644 --- a/include/Ping.h +++ b/include/Ping.h @@ -36,8 +36,8 @@ class PingPacket PingPacket(); ~PingPacket(); - bool read(int fd, struct sockaddr_in*); - bool write(int fd, const struct sockaddr_in*) const; + bool read(int fd, struct sockaddr_in6*); + bool write(int fd, const struct sockaddr_in6*) const; void* pack(void*, const char* version) const; const void* unpack(const void*, char* version); @@ -48,12 +48,10 @@ class PingPacket bool readFromFile(std::istream& in); static void repackHexPlayerCounts(char*, int* counts); - static bool isRequest(int fd, struct sockaddr_in*); - static bool sendRequest(int fd, const struct sockaddr_in*); + static bool isRequest(int fd, struct sockaddr_in6*); + static bool sendRequest(int fd, const struct sockaddr_in6*); public: - ServerId serverId; - Address sourceAddr; uint16_t gameOptions; uint16_t gameType; uint16_t maxShots; diff --git a/include/Protocol.h b/include/Protocol.h index a0fcfa1ffa..73b4b9d62f 100644 --- a/include/Protocol.h +++ b/include/Protocol.h @@ -199,7 +199,6 @@ const uint16_t MsgLagPing = 0x7069; // 'pi' typedef uint8_t PlayerId; const int PlayerIdPLen = sizeof(PlayerId); -const int ServerIdPLen = 8; // 54 bytes const int PlayerUpdatePLenMax = diff --git a/include/ServerItem.h b/include/ServerItem.h index 6a8cf7aaa0..b3766ebeae 100644 --- a/include/ServerItem.h +++ b/include/ServerItem.h @@ -32,8 +32,6 @@ class ServerItem bool readFromFile(std::istream& in, int subrevision); // serialize in void setUpdateTime(); // set last updated to now int getPlayerCount() const; - void splitAddrTitle(std::string& addr, std::string& title) const; - std::string getAddrName() const; time_t getAgeMinutes() const; time_t getAgeSeconds() const; std::string getAgeString() const; // nifty formated age string diff --git a/include/ServerList.h b/include/ServerList.h index a0d12fdf54..fb6f7c2b65 100644 --- a/include/ServerList.h +++ b/include/ServerList.h @@ -54,7 +54,6 @@ class ServerList : cURLManager private: void readServerList(); - void addToListWithLookup(ServerItem&); void addCacheToList(); void _shutDown(); @@ -64,7 +63,7 @@ class ServerList : cURLManager std::vector servers; ServerListCache* serverCache; int pingBcastSocket; - struct sockaddr_in pingBcastAddr; + struct sockaddr_in6 pingBcastAddr; StartupInfo *startupInfo; }; diff --git a/include/ServerListCache.h b/include/ServerListCache.h index 410cec2f43..339f606a72 100644 --- a/include/ServerListCache.h +++ b/include/ServerListCache.h @@ -71,13 +71,13 @@ class ServerListCache /** search for some address in the cache. this is a wrapper that * allows access to the maps find method */ - SRV_STR_MAP::iterator find(const std::string &ServerAddress); + SRV_STR_MAP::iterator find(const std::string &namePort); /** add an entry to the cache list */ - void insert(const std::string &serverAddress, const ServerItem &info); + void insert(const std::string &namePort, const ServerItem &info); /** is given server in cache and marked as favorite? */ - bool isFavorite(const std::string &serverAddress) const; + bool isFavorite(const std::string &namePort) const; private: /** the full path of the file the cache is stored in **/ diff --git a/include/common.h b/include/common.h index 88ac04f698..fcd12da98c 100644 --- a/include/common.h +++ b/include/common.h @@ -208,6 +208,10 @@ extern int debugLevel; # include #endif +#ifndef in_port_t +# define in_port_t uint16_t +#endif + #ifdef HAVE_STDINT_H # include #else diff --git a/include/multicast.h b/include/multicast.h index e7dcb78545..b6028bf86c 100644 --- a/include/multicast.h +++ b/include/multicast.h @@ -36,12 +36,12 @@ * -1 if failed */ int openBroadcast(int port, const char* service, - struct sockaddr_in* addr); + struct sockaddr_in6* addr); int closeBroadcast(int fd); int sendBroadcast(int fd, const void* buffer, - int bufferLength, const struct sockaddr_in*); + int bufferLength, const struct sockaddr_in6*); int recvBroadcast(int fd, void* buffer, - int bufferLength, struct sockaddr_in*); + int bufferLength, struct sockaddr_in6*); #endif // __MULTICAST_H__ diff --git a/include/network.h b/include/network.h index 233cfdc823..b223bb0d96 100644 --- a/include/network.h +++ b/include/network.h @@ -64,6 +64,10 @@ extern "C" { } +# ifndef s6_addr16 +# define s6_addr16 u.Word +# endif + #else // !defined(_WIN32) // unistd has close(). It is poor encapsulation the close() is called from @@ -113,6 +117,10 @@ extern "C" { void bzfherror(const char* msg); } +# if defined(__APPLE__) && !defined(s6_addr16) +# define s6_addr16 __u6_addr.__u6_addr16 +# endif + #endif /* defined(_WIN32) */ // Can this happen? @@ -120,6 +128,10 @@ extern "C" { # define INADDR_NONE ((in_addr_t)0xffffffff) #endif +// Identifiers for IP address family that will be passed between server and client as a uint8_t +#define BZF_INET 4 +#define BZF_INET6 6 + // for all platforms extern "C" { void nerror(const char* msg); diff --git a/man/bzfs.6.in b/man/bzfs.6.in index 048f27ef18..efd34fedd4 100644 --- a/man/bzfs.6.in +++ b/man/bzfs.6.in @@ -266,6 +266,8 @@ than the first 50 lines of \fIfile\fR to the player. Server will listen for and respond to ``pings'' (sent via broadcast) on the given interface. Clients use this to find active servers on the network. This is the TCP/UDP/IP address the server will listen on. +Default is \fI::\fR which should accept IPv4 and IPv6 clients. Use +\fB-i 0.0.0.0\fR to support only IPv4 clients. .TP .B \-j Allows jumping. diff --git a/misc/bzfquery.pl b/misc/bzfquery.pl index cb6968ef15..276e7a5cb9 100755 --- a/misc/bzfquery.pl +++ b/misc/bzfquery.pl @@ -70,7 +70,7 @@ =head1 SEE ALSO # quit if version isn't valid die "not a bzflag server" if ($magic ne "BZFS"); -die "incompatible version" if ($protocol ne "0223"); +die "incompatible version" if ($protocol lt "0223"); # quit if rejected die "rejected by server" if ($id == 255); diff --git a/premake5.lua b/premake5.lua index 8cfead3378..8225e67c19 100644 --- a/premake5.lua +++ b/premake5.lua @@ -408,7 +408,7 @@ workspace(iif(_ACTION and string.find(_ACTION, "vs", 0), "-Wno-deprecated-declarations", "-Wno-inconsistent-missing-override" } xcodebuildsettings { ["CLANG_CXX_LIBRARY"] = "libc++", - ["MACOSX_DEPLOYMENT_TARGET"] = "10.9", + ["MACOSX_DEPLOYMENT_TARGET"] = "10.13", ["LD_RUNPATH_SEARCH_PATHS"] =" @executable_path/../PlugIns" } filter { "system:macosx", "action:xcode*" } diff --git a/src/bzadmin/BZAdminClient.cxx b/src/bzadmin/BZAdminClient.cxx index 7495a179c8..a1b7681c28 100644 --- a/src/bzadmin/BZAdminClient.cxx +++ b/src/bzadmin/BZAdminClient.cxx @@ -38,22 +38,25 @@ StartupInfo startupInfo; BZAdminClient::BZAdminClient(BZAdminUI* bzInterface) - : myTeam(ObserverTeam), sLink(Address(startupInfo.serverName), startupInfo.serverPort), valid(false), ui(bzInterface) + : myTeam(ObserverTeam), valid(false), ui(bzInterface) { + Address serverAddress = Address(joinNamePort(startupInfo.serverName, startupInfo.serverPort)); - if (sLink.getState() != ServerLink::Okay) + sLink = new ServerLink(serverAddress); + + if (sLink->getState() != ServerLink::Okay) { - switch (sLink.getState()) + switch (sLink->getState()) { case ServerLink::BadVersion: { - std::cout << "Incompatible server version " << sLink.getVersion(); + std::cout << "Incompatible server version " << sLink->getVersion(); break; } case ServerLink::Refused: { std::string banMessage = "Server Refused connection due to ban: "; - banMessage += sLink.getRejectionMessage(); + banMessage += sLink->getRejectionMessage(); std::cout << banMessage; break; } @@ -78,8 +81,8 @@ BZAdminClient::BZAdminClient(BZAdminUI* bzInterface) // won't really output anything, just gets token outputServerList(); } - sLink.sendEnter(TankPlayer, myTeam, 0, startupInfo.callsign, "bzadmin", startupInfo.token, "default"); - if (sLink.getState() != ServerLink::Okay) + sLink->sendEnter(TankPlayer, myTeam, 0, startupInfo.callsign, "bzadmin", startupInfo.token, "default"); + if (sLink->getState() != ServerLink::Okay) { std::cerr << "Rejected." << std::endl; return; @@ -87,7 +90,7 @@ BZAdminClient::BZAdminClient(BZAdminUI* bzInterface) std::string reason; uint16_t code, rejcode; - if (sLink.readEnter (reason, code, rejcode)) + if (sLink->readEnter (reason, code, rejcode)) valid = true; else std::cerr << reason << std::endl; @@ -137,7 +140,7 @@ BZAdminClient::BZAdminClient(BZAdminUI* bzInterface) PlayerId BZAdminClient::getMyId() { - return sLink.getId(); + return sLink->getId(); } @@ -148,7 +151,7 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() PlayerIdMap::iterator iter; // read until we have a package, or until we have waited 100 ms - if (sLink.read(code, len, inbuf, 100) == 1) + if (sLink->read(code, len, inbuf, 100) == 1) { lastMessage.first = ""; lastMessage.second = Default; @@ -161,6 +164,16 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() switch (code) { + case MsgUDPLinkEstablished: + // server got our initial UDP packet + sLink->enableOutboundUDP(); + break; + + case MsgUDPLinkRequest: + // we got server's initial UDP packet + sLink->confirmIncomingUDP(); + break; + case MsgNewRabbit: if (messageMask[MsgNewRabbit]) { @@ -303,7 +316,7 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() vbuf = nboUnpackUByte(vbuf, tmp); vbuf = nboUnpackUByte(vbuf, p); vbuf = a.unpack(vbuf); - players[p].ip = a.getDotNotation(); + players[p].ip = a.getIpTextPort(); if ((ui != NULL) && messageMask[MsgAdminInfo]) { ui->outputMessage("*** IPINFO: " + players[p].name + " from " + @@ -317,7 +330,7 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() vbuf = nboUnpackUByte(vbuf, tmp); vbuf = nboUnpackUByte(vbuf, p); vbuf = a.unpack(vbuf); - players[p].ip = a.getDotNotation(); + players[p].ip = a.getIpTextPort(); Team temp; if (messageMask[MsgAdminInfo]) { @@ -429,7 +442,7 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() PlayerId src; PlayerId dst; uint8_t mtype; - PlayerId me = sLink.getId(); + PlayerId me = sLink->getId(); vbuf = nboUnpackUByte(vbuf, src); vbuf = nboUnpackUByte(vbuf, dst); vbuf = nboUnpackUByte(vbuf, mtype); @@ -457,7 +470,7 @@ BZAdminClient::ServerCode BZAdminClient::checkMessage() return GotMessage; } - if (sLink.getState() != ServerLink::Okay) + if (sLink->getState() != ServerLink::Okay) { if (ui != NULL) ui->outputMessage("--- ERROR: Communication error", Red); @@ -613,7 +626,7 @@ void BZAdminClient::sendMessage(const std::string& msg, strncpy(buffer, msg.c_str(), MessageLen - 1); buffer[MessageLen - 1] = '\0'; nboPackString(buffer2 + 1, buffer, MessageLen); - sLink.send(MsgSendChat, sizeof(buffer2), buffer2); + sLink->send(MsgSendChat, sizeof(buffer2), buffer2); } @@ -687,8 +700,8 @@ void BZAdminClient::waitForServer() // this assumes that the order of messages isn't changed along the way bool tmp = messageMask[MsgReceiveChat]; messageMask[MsgReceiveChat] = true; - PlayerId me = sLink.getId(); - if (sLink.getState() == ServerLink::Okay) + PlayerId me = sLink->getId(); + if (sLink->getState() == ServerLink::Okay) { sendMessage("bzadminping", me); std::string expected = formatMessage("bzadminping", ChatMessage, me, me, NoTeam, me); diff --git a/src/bzadmin/BZAdminClient.h b/src/bzadmin/BZAdminClient.h index 4271923b90..2203423467 100644 --- a/src/bzadmin/BZAdminClient.h +++ b/src/bzadmin/BZAdminClient.h @@ -153,7 +153,7 @@ class BZAdminClient PlayerIdMap players; TeamColor myTeam; - ServerLink sLink; + ServerLink* sLink; std::pair lastMessage; bool valid; std::map messageMask; diff --git a/src/bzadmin/ServerLink.cxx b/src/bzadmin/ServerLink.cxx index bb39570e7a..0213e0c002 100644 --- a/src/bzadmin/ServerLink.cxx +++ b/src/bzadmin/ServerLink.cxx @@ -21,7 +21,7 @@ #define UDEBUGMSG false #endif -#define UDEBUG if (UDEBUGMSG) printf +#define UDEBUG if (UDEBUGMSG) logDebugMessage // system headers #include @@ -88,7 +88,7 @@ static const unsigned long endPacket = 0; ServerLink* ServerLink::server = NULL; -ServerLink::ServerLink(const Address& serverAddress, int port) +ServerLink::ServerLink(Address& serverAddress) { int i; @@ -113,18 +113,13 @@ ServerLink::ServerLink(const Address& serverAddress, int port) // open connection to server. first connect to given port. // don't wait too long. - int query = socket(AF_INET, SOCK_STREAM, 0); + int query = socket(serverAddress.getAddr()->sa_family, SOCK_STREAM, 0); if (query < 0) return; - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = serverAddress; - - UDEBUG("Remote %s\n", sockaddr2iptextport((const struct sockaddr *)&addr)); + logDebugMessage(4, "Remote %s\n", serverAddress.getIpTextPort().c_str()); // for UDP, used later - memcpy((unsigned char *)&usendaddr, (unsigned char *)&addr, sizeof(addr)); + memcpy((unsigned char *)&usendaddr, (unsigned char *)serverAddress.getAddr(), sizeof(struct sockaddr_in6)); bool okay = true; int fdMax = query; @@ -141,7 +136,7 @@ ServerLink::ServerLink(const Address& serverAddress, int port) close(query); return; } - if (connect(query, (CNCTType*)&addr, sizeof(addr)) < 0) + if (connect(query, serverAddress.getAddr(), sizeof(struct sockaddr_in6)) < 0) { if (getErrno() != EINPROGRESS) { @@ -176,8 +171,8 @@ ServerLink::ServerLink(const Address& serverAddress, int port) // Initialize structure conn.query = query; - conn.addr = (CNCTType*)&addr; - conn.saddr = sizeof(addr); + conn.addr = serverAddress.getAddr(); + conn.saddr = sizeof(struct sockaddr_in6); // Create event hConnected = CreateEvent(NULL, FALSE, FALSE, "Connected Event"); @@ -392,15 +387,15 @@ ServerLink::~ServerLink() #if defined(NETWORK_STATS) const float dt = float(TimeKeeper::getCurrent() - startTime); logDebugMessage(1, "Server network statistics:\n"); - logDebugMessage(1, " elapsed time : %f\n", dt); - logDebugMessage(1, " bytes sent : %d (%f/sec)\n", bytesSent, (float)bytesSent / dt); - logDebugMessage(1, " packets sent : %d (%f/sec)\n", packetsSent, (float)packetsSent / dt); + logDebugMessage(1, "\telapsed time : %f\n", dt); + logDebugMessage(1, "\tbytes sent : %d (%f/sec)\n", bytesSent, (float)bytesSent / dt); + logDebugMessage(1, "\tpackets sent : %d (%f/sec)\n", packetsSent, (float)packetsSent / dt); if (packetsSent != 0) - logDebugMessage(1, " bytes/packet : %f\n", (float)bytesSent / (float)packetsSent); - logDebugMessage(1, " bytes recieved : %d (%f/sec)\n", bytesReceived, (float)bytesReceived / dt); - logDebugMessage(1, " packets received: %d (%f/sec)\n", packetsReceived, (float)packetsReceived / dt); + logDebugMessage(1, "\tbytes/packet : %f\n", (float)bytesSent / (float)packetsSent); + logDebugMessage(1, "\tbytes recieved : %d (%f/sec)\n", bytesReceived, (float)bytesReceived / dt); + logDebugMessage(1, "\tpackets received: %d (%f/sec)\n", packetsReceived, (float)packetsReceived / dt); if (packetsReceived != 0) - logDebugMessage(1, " bytes/packet : %f\n", (float)bytesReceived / (float)packetsReceived); + logDebugMessage(1, "\tbytes/packet : %f\n", (float)bytesReceived / (float)packetsReceived); #endif } @@ -450,7 +445,7 @@ void ServerLink::send(uint16_t code, uint16_t len, const void* msg) #ifdef TESTLINK if ((random() % TESTQUALTIY) != 0) #endif - sendto(urecvfd, (const char *)msgbuf, (char*)buf - msgbuf, 0, &usendaddr, sizeof(usendaddr)); + sendto(urecvfd, (const char *)msgbuf, (char*)buf - msgbuf, 0, (sockaddr *)&usendaddr, sizeof(usendaddr)); // we don't care about errors yet return; } @@ -502,7 +497,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) { AddrLen recvlen = sizeof(urecvaddr); int n = recvfrom(urecvfd, ubuf, MaxPacketLen, 0, - &urecvaddr, (socklen_t*)&recvlen); + (sockaddr *)&urecvaddr, (socklen_t*)&recvlen); if (n > 0) { udpLength = n; @@ -522,7 +517,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) udpBufferPtr = (const char *)nboUnpackUShort(udpBufferPtr, code); // if (code != MsgPlayerUpdateSmall && code != MsgPlayerUpdate && code != MsgGameTime) // logDebugMessage(1,"rcvd %s len %d\n",MsgStrings::strMsgCode(code),len); - UDEBUG("<** UDP Packet Code %x Len %x\n", code, len); + UDEBUG(5,"<** UDP Packet Code %x Len %x\n", code, len); if (len > udpLength) { udpLength = 0; @@ -533,7 +528,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) udpLength -= len; return 1; } - if (UDEBUGMSG) printError("Fallback to normal TCP receive"); + //if (UDEBUGMSG) logDebugMessage(5,"Fallback to normal TCP receive"); len = 0; code = MsgNull; @@ -671,12 +666,15 @@ bool ServerLink::readEnter(std::string& reason, { if (this->read(code, len, msg, -1) < 0) { - reason = "Communication error joining game [No immediate respose]."; + reason = "Communication error joining game [No immediate response]."; return false; } if (code == MsgAccept) + { + sendUDPlinkRequest(); return true; + } else if (code == MsgSuperKill) { reason = "Server forced disconnection."; @@ -700,6 +698,73 @@ bool ServerLink::readEnter(std::string& reason, return true; } +void ServerLink::sendUDPlinkRequest() +{ + if ((server_abilities & CanDoUDP) != CanDoUDP) + return; // server does not support udp (future list server test) + + char msg[1]; + void* buf = msg; + + struct sockaddr_in6 serv_addr; + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin6_family = usendaddr.sin6_family; + + if ((urecvfd = socket(serv_addr.sin6_family, SOCK_DGRAM, 0)) < 0) + { + nerror("socket() failed"); + return; // we cannot comply + } + + AddrLen addr_len = sizeof(serv_addr); + if (getsockname(fd, (struct sockaddr*)&serv_addr, (socklen_t*)&addr_len) < 0) + { + nerror("Error: getsockname() failed, cannot get TCP port?"); + return; + } + if (bind(urecvfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) + { + nerror("Error: getsockname() failed, cannot get TCP port?"); + return; // we cannot get udp connection, bail out + } + + memcpy((char *)&urecvaddr, (char *)&serv_addr, sizeof(serv_addr)); + + if (debugLevel >= 1) + { + std::vector args; + args.push_back(sockaddr2iptextport((const sockaddr *)&serv_addr)); + printError("Network: Created local UDP downlink {1}", &args); + } + + buf = nboPackUByte(buf, id); + + if (BzfNetwork::setNonBlocking(urecvfd) < 0) + printError("Error: Unable to set NonBlocking for UDP receive socket"); + + send(MsgUDPLinkRequest, sizeof(msg), msg); +} + +// heard back from server that we can send udp +void ServerLink::enableOutboundUDP() +{ + ulinkup = true; + if (debugLevel >= 1) + printError("Server got our UDP, using UDP to server"); +} +// confirm that server can send us UDP +void ServerLink::confirmIncomingUDP() +{ + // This is really a hack. enableOutboundUDP will be setting this + // but frequently the udp handshake will finish first so might as + // well start with udp as soon as we can + ulinkup = true; + + if (debugLevel >= 1) + printError("Got server's UDP packet back, server using UDP"); + send(MsgUDPLinkEstablished, 0, NULL); +} + // Local Variables: *** // mode: C++ *** // tab-width: 4 *** diff --git a/src/bzadmin/ServerLink.h b/src/bzadmin/ServerLink.h index f24d35a3dc..dbf6e4f39a 100644 --- a/src/bzadmin/ServerLink.h +++ b/src/bzadmin/ServerLink.h @@ -49,7 +49,7 @@ class ServerLink HasMessageLink = 8 }; - ServerLink(const Address& serverAddress, int port = ServerPort); + ServerLink(Address&); ~ServerLink(); State getState() const; @@ -70,6 +70,7 @@ class ServerLink const char* token, const char* locale); bool readEnter(std::string& reason, uint16_t& code, uint16_t& rejcode); + void sendUDPlinkRequest(); static ServerLink* getServer(); // const static void setServer(ServerLink*); @@ -80,9 +81,9 @@ class ServerLink State state = SocketError; int fd = -1; - struct sockaddr usendaddr; + sockaddr_in6 usendaddr; int urecvfd; - struct sockaddr urecvaddr; // the clients udp listen address + sockaddr_in6 urecvaddr; // the clients udp listen address bool ulinkup; PlayerId id; diff --git a/src/bzadmin/bzadmin.cxx b/src/bzadmin/bzadmin.cxx index b43a08fd2b..d3001463fc 100644 --- a/src/bzadmin/bzadmin.cxx +++ b/src/bzadmin/bzadmin.cxx @@ -33,6 +33,7 @@ // causes persistent rebuilding to obtain build versioning #include "version.h" +// FIXME: add -d -dd -ddd etc command line option int debugLevel = 0; /** @file @@ -67,6 +68,9 @@ int main(int argc, char** argv) std::vector visibleMsgs; std::vector invisibleMsgs; + // FIXME add -ts micros and -utc to bzadmin + // setDebugTimestamp(true,true,true); + // no curses, use stdboth as default instead const UIMap& interfaces = UIMap::instance(); if (interfaces.find("curses") == interfaces.end()) @@ -104,7 +108,7 @@ int main(int argc, char** argv) // check that we have callsign and host in the right format and extract them { int atPos; - std::string callsign = "", password = "", serverName = ""; + std::string callsign = "", password = "", namePort = "", serverName = ""; if (!(op.getParameters().size() > 0 && (atPos = op.getParameters()[0].find('@')) > 0)) { @@ -138,17 +142,10 @@ int main(int argc, char** argv) password = callsign.substr(pPos + 1).c_str(); callsign = callsign.substr(0, pPos); } - serverName = op.getParameters()[0].substr(atPos + 1); - } - startupInfo.serverPort = ServerPort; - int cPos = serverName.find(':'); - if (cPos != -1) - { - long int serverPort = strtol(serverName.substr(cPos + 1).c_str(), (char **)NULL, 10); - if (serverPort > 0 && serverPort < 65536) - startupInfo.serverPort = (int) serverPort; - serverName = serverName.substr(0, cPos); + namePort = op.getParameters()[0].substr(atPos + 1); } + if (!splitNamePort(namePort, serverName, startupInfo.serverPort)) + return 1; // Flawfinder: ignore strncpy(startupInfo.callsign, callsign.c_str(), sizeof(startupInfo.callsign) - 1); // Flawfinder: ignore @@ -158,8 +155,7 @@ int main(int argc, char** argv) } std::cerr << "Connecting to " << startupInfo.callsign << "@" << - startupInfo.serverName << ":" << - startupInfo.serverPort; + joinNamePort(startupInfo.serverName, startupInfo.serverPort); // Check if password is not empty if (startupInfo.password[0]) std::cerr << " using central login"; diff --git a/src/bzflag/ServerLink.cxx b/src/bzflag/ServerLink.cxx index b3b6b1479c..12329672af 100644 --- a/src/bzflag/ServerLink.cxx +++ b/src/bzflag/ServerLink.cxx @@ -21,7 +21,7 @@ #define UDEBUGMSG false #endif -#define UDEBUG if (UDEBUGMSG) printf +#define UDEBUG if (UDEBUGMSG) logDebugMessage // system headers #include @@ -88,7 +88,7 @@ static const unsigned long endPacket = 0; ServerLink* ServerLink::server = NULL; -ServerLink::ServerLink(const Address& serverAddress, int port) +ServerLink::ServerLink(Address& serverAddress) { int i; @@ -113,18 +113,13 @@ ServerLink::ServerLink(const Address& serverAddress, int port) // open connection to server. first connect to given port. // don't wait too long. - int query = socket(AF_INET, SOCK_STREAM, 0); + int query = socket(serverAddress.getAddr()->sa_family, SOCK_STREAM, 0); if (query < 0) return; - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr = serverAddress; - - UDEBUG("Remote %s\n", sockaddr2iptextport((const struct sockaddr *)&addr)); + UDEBUG(4,"Remote %s\n", serverAddress.getIpTextPort().c_str()); // for UDP, used later - memcpy((unsigned char *)&usendaddr, (unsigned char *)&addr, sizeof(addr)); + memcpy((unsigned char *)&usendaddr, (unsigned char *)serverAddress.getAddr(), sizeof(struct sockaddr_in6)); bool okay = true; int fdMax = query; @@ -141,7 +136,7 @@ ServerLink::ServerLink(const Address& serverAddress, int port) close(query); return; } - if (connect(query, (CNCTType*)&addr, sizeof(addr)) < 0) + if (connect(query, serverAddress.getAddr(), sizeof(struct sockaddr_in6)) < 0) { if (getErrno() != EINPROGRESS) { @@ -176,8 +171,8 @@ ServerLink::ServerLink(const Address& serverAddress, int port) // Initialize structure conn.query = query; - conn.addr = (CNCTType*)&addr; - conn.saddr = sizeof(addr); + conn.addr = serverAddress.getAddr(); + conn.saddr = sizeof(struct sockaddr_in6); // Create event hConnected = CreateEvent(NULL, FALSE, FALSE, "Connected Event"); @@ -382,15 +377,15 @@ ServerLink::~ServerLink() #if defined(NETWORK_STATS) const float dt = float(TimeKeeper::getCurrent() - startTime); logDebugMessage(1, "Server network statistics:\n"); - logDebugMessage(1, " elapsed time : %f\n", dt); - logDebugMessage(1, " bytes sent : %d (%f/sec)\n", bytesSent, (float)bytesSent / dt); - logDebugMessage(1, " packets sent : %d (%f/sec)\n", packetsSent, (float)packetsSent / dt); + logDebugMessage(1, "\telapsed time : %f\n", dt); + logDebugMessage(1, "\tbytes sent : %d (%f/sec)\n", bytesSent, (float)bytesSent / dt); + logDebugMessage(1, "\tpackets sent : %d (%f/sec)\n", packetsSent, (float)packetsSent / dt); if (packetsSent != 0) - logDebugMessage(1, " bytes/packet : %f\n", (float)bytesSent / (float)packetsSent); - logDebugMessage(1, " bytes recieved : %d (%f/sec)\n", bytesReceived, (float)bytesReceived / dt); - logDebugMessage(1, " packets received: %d (%f/sec)\n", packetsReceived, (float)packetsReceived / dt); + logDebugMessage(1, "\tbytes/packet : %f\n", (float)bytesSent / (float)packetsSent); + logDebugMessage(1, "\tbytes recieved : %d (%f/sec)\n", bytesReceived, (float)bytesReceived / dt); + logDebugMessage(1, "\tpackets received: %d (%f/sec)\n", packetsReceived, (float)packetsReceived / dt); if (packetsReceived != 0) - logDebugMessage(1, " bytes/packet : %f\n", (float)bytesReceived / (float)packetsReceived); + logDebugMessage(1, "\tbytes/packet : %f\n", (float)bytesReceived / (float)packetsReceived); #endif } @@ -440,7 +435,7 @@ void ServerLink::send(uint16_t code, uint16_t len, const void* msg) #ifdef TESTLINK if ((random() % TESTQUALTIY) != 0) #endif - sendto(urecvfd, (const char *)msgbuf, (char*)buf - msgbuf, 0, &usendaddr, sizeof(usendaddr)); + sendto(urecvfd, (const char *)msgbuf, (char*)buf - msgbuf, 0, (sockaddr *)&usendaddr, sizeof(usendaddr)); // we don't care about errors yet return; } @@ -581,7 +576,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) { AddrLen recvlen = sizeof(urecvaddr); int n = recvfrom(urecvfd, ubuf, MaxPacketLen, 0, - &urecvaddr, (socklen_t*)&recvlen); + (sockaddr *)&urecvaddr, (socklen_t*)&recvlen); if (n > 0) { udpLength = n; @@ -601,7 +596,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) udpBufferPtr = (const char *)nboUnpackUShort(udpBufferPtr, code); // if (code != MsgPlayerUpdateSmall && code != MsgPlayerUpdate && code != MsgGameTime) // logDebugMessage(1,"rcvd %s len %d\n",MsgStrings::strMsgCode(code),len); - UDEBUG("<** UDP Packet Code %x Len %x\n", code, len); + UDEBUG(5,"<** UDP Packet Code %x Len %x\n", code, len); if (len > udpLength) { udpLength = 0; @@ -612,7 +607,7 @@ int ServerLink::read(uint16_t& code, uint16_t& len, void* msg, int blockTime) udpLength -= len; return 1; } - //if (UDEBUGMSG) printError("Fallback to normal TCP receive"); + //if (UDEBUGMSG) logDebugMessage(5,"Fallback to normal TCP receive"); len = 0; code = MsgNull; @@ -695,7 +690,7 @@ bool ServerLink::readEnter(std::string& reason, { if (this->read(code, len, msg, -1) < 0) { - reason = "Communication error joining game [No immediate respose]."; + reason = "Communication error joining game [No immediate response]."; return false; } @@ -848,38 +843,36 @@ void ServerLink::sendUDPlinkRequest() return; // server does not support udp (future list server test) char msg[1]; - unsigned short localPort; void* buf = msg; - struct sockaddr_in serv_addr; + struct sockaddr_in6 serv_addr; + serv_addr.sin6_family = usendaddr.sin6_family; - if ((urecvfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if ((urecvfd = socket(serv_addr.sin6_family, SOCK_DGRAM, 0)) < 0) { + nerror("socket() failed"); return; // we cannot comply } AddrLen addr_len = sizeof(serv_addr); if (getsockname(fd, (struct sockaddr*)&serv_addr, (socklen_t*)&addr_len) < 0) { - printError("Error: getsockname() failed, cannot get TCP port?"); + nerror("Error: getsockname() failed, cannot get TCP port?"); return; } if (bind(urecvfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) != 0) { - printError("Error: getsockname() failed, cannot get TCP port?"); + nerror("Error: getsockname() failed, cannot get TCP port?"); return; // we cannot get udp connection, bail out } - localPort = ntohs(serv_addr.sin_port); memcpy((char *)&urecvaddr, (char *)&serv_addr, sizeof(serv_addr)); if (debugLevel >= 1) { std::vector args; - char lps[10]; - sprintf(lps, "%d", localPort); - args.push_back(lps); - printError("Network: Created local UDP downlink port {1}", &args); + args.push_back(sockaddr2iptextport((const sockaddr *)&serv_addr)); + printError("Network: Created local UDP downlink {1}", &args); } buf = nboPackUByte(buf, id); diff --git a/src/bzflag/ServerLink.h b/src/bzflag/ServerLink.h index 8da9618f48..a896d41a71 100644 --- a/src/bzflag/ServerLink.h +++ b/src/bzflag/ServerLink.h @@ -51,7 +51,7 @@ class ServerLink HasMessageLink = 8 }; - ServerLink(const Address& serverAddress, int port = ServerPort); + ServerLink(Address& serverAddress); ~ServerLink(); State getState() const; @@ -102,9 +102,9 @@ class ServerLink State state = SocketError; int fd = -1; - struct sockaddr usendaddr; + sockaddr_in6 usendaddr; int urecvfd; - struct sockaddr urecvaddr; // the clients udp listen address + sockaddr_in6 urecvaddr; // the clients udp listen address bool ulinkup; PlayerId id; diff --git a/src/bzflag/ServerListFilter.cxx b/src/bzflag/ServerListFilter.cxx index fc25fb50a3..bee4a7fa1f 100644 --- a/src/bzflag/ServerListFilter.cxx +++ b/src/bzflag/ServerListFilter.cxx @@ -198,14 +198,12 @@ bool ServerListFilter::check(const ServerItem& item) const return true; // pattern filters - std::string addr, desc; - item.splitAddrTitle(addr, desc); - if (!addrPat.check(addr)) + if (!addrPat.check(item.name)) return false; - if (!descPat.check(desc)) + if (!descPat.check(item.description)) return false; - if (!addrDescPat.check(addr) && - !addrDescPat.check(desc)) + if (!addrDescPat.check(item.name) && + !addrDescPat.check(item.description)) return false; const PingPacket& p = item.ping; diff --git a/src/bzflag/ServerMenu.cxx b/src/bzflag/ServerMenu.cxx index 2c8c693c4c..f1bae1d9af 100644 --- a/src/bzflag/ServerMenu.cxx +++ b/src/bzflag/ServerMenu.cxx @@ -366,17 +366,16 @@ void ServerMenu::setFav(bool fav) if (selectedIndex < 0 || (int)serverList.size() <= selectedIndex) return; // no such entry (server list may be empty) const ServerItem& item = serverList.getServers()[selectedIndex]; - std::string addrname = item.getAddrName(); ServerListCache *cache = ServerListCache::get(); - ServerListCache::SRV_STR_MAP::iterator i = cache->find(addrname); + ServerListCache::SRV_STR_MAP::iterator i = cache->find(item.name); if (i != cache->end()) i->second.favorite = fav; else { // FIXME should not ever come here, but what to do? } - realServerList.markFav(addrname, fav); - serverList.markFav(addrname, fav); + realServerList.markFav(item.name, fav); + serverList.markFav(item.name, fav); setSelected(getSelected()+1, true); } @@ -495,17 +494,15 @@ void ServerMenu::setSelected(int index, bool forcerefresh) label->setColor(0.5f + rf * 0.5f, 0.5f + gf * 0.5f, 0.5f + bf * 0.5f); } - std::string addr, desc; - server.splitAddrTitle(addr, desc); if (server.favorite) fullLabel += ANSI_STR_FG_ORANGE; else fullLabel += ANSI_STR_FG_WHITE; - fullLabel += addr; - if (!desc.empty()) + fullLabel += server.name; + if (!server.description.empty()) { fullLabel += ANSI_STR_RESET " "; - fullLabel += desc; + fullLabel += stripAnsiCodes(server.description); } label->setString(fullLabel); label->setDarker(server.cached); @@ -806,10 +803,10 @@ void ServerMenu::execute() // update startup info StartupInfo* info = getStartupInfo(); - strncpy(info->serverName, serverList.getServers()[selectedIndex].name.c_str(), sizeof(info->serverName) - 1); + std::string serverName; + splitNamePort(serverList.getServers()[selectedIndex].name, serverName, info->serverPort); + strncpy(info->serverName, serverName.c_str(), sizeof(info->serverName) - 1); info->serverName[sizeof(info->serverName) - 1] = '\0'; - info->serverPort = ntohs((unsigned short) - serverList.getServers()[selectedIndex].ping.serverId.addr.sin_port); // all done HUDDialogStack::get()->pop(); diff --git a/src/bzflag/bzflag.cxx b/src/bzflag/bzflag.cxx index 5a2199fea3..9c7307bb4d 100644 --- a/src/bzflag/bzflag.cxx +++ b/src/bzflag/bzflag.cxx @@ -414,45 +414,23 @@ static void parse(int argc, char** argv) { // argv[i] = username:password@server:port // variables to store - std::string serverName, callsign, password; - int port; + std::string callsign, password, namePort, serverName; // start splitting stuff const std::string argument = std::string(argv[i]); const size_t atSplit = argument.find("@"); - const size_t portSplit = argument.rfind(":"); - const size_t passSplit = argument.find(":"); if (atSplit != std::string::npos) // we found an "@" { - if (portSplit != std::string::npos) // we have a port + callsign = argument.substr(0, atSplit); + const size_t passSplit = callsign.find(':'); + if (passSplit != std::string::npos) { - serverName = argument.substr(atSplit + 1, portSplit - atSplit - 1); - port = atoi(argument.substr(portSplit + 1, argument.length() - portSplit).c_str()); - - if (port < 1 || port > 65535) // invalid port - { - printFatalError("Bad port, using default %d.", ServerPort); - port = ServerPort; - } + password = callsign.substr(passSplit + 1).c_str(); + callsign = callsign.substr(0, passSplit); } - else //we don't have a port - { - serverName = argument.substr(atSplit + 1, argument.length() - atSplit); - port = ServerPort; - } - - if (portSplit != passSplit) // there's a password to parse - { - callsign = argument.substr(0, passSplit); - password = argument.substr(passSplit + 1, atSplit - passSplit - 1); - } - else // just a username - { - callsign = argument.substr(0, atSplit); - password = ""; - } - + if (!splitNamePort(argument.substr(atSplit + 1, argument.length() - atSplit), serverName, startupInfo.serverPort)) + printFatalError("Unable to parse server name %s", namePort.c_str()); // length checks and always truncate everything after the max length if (callsign.length() > sizeof(startupInfo.callsign)) { @@ -474,26 +452,11 @@ static void parse(int argc, char** argv) strcpy(startupInfo.callsign, callsign.c_str()); strcpy(startupInfo.password, password.c_str()); strcpy(startupInfo.serverName, serverName.c_str()); - startupInfo.serverPort = port; } else // there is no callsign/password so only a destination { - if (portSplit != std::string::npos) // we have a port - { - serverName = argument.substr(atSplit + 1, portSplit - atSplit - 1); - port = atoi(argument.substr(portSplit + 1, argument.length() - portSplit).c_str()); - - if (port < 1 || port > 65535) // invalid port - { - printFatalError("Bad port, using default %d.", ServerPort); - port = ServerPort; - } - } - else //we don't have a port - { - serverName = argument.substr(atSplit + 1, argument.length() - atSplit); - port = ServerPort; - } + if (!splitNamePort(argument, serverName, startupInfo.serverPort)) + printFatalError("Unable to parse server name %s", namePort.c_str()); // sanity check for length if (serverName.length() > sizeof(startupInfo.serverName)) @@ -503,7 +466,6 @@ static void parse(int argc, char** argv) } strcpy(startupInfo.serverName, serverName.c_str()); - startupInfo.serverPort = port; } startupInfo.autoConnect = true; // automatically connect on start up diff --git a/src/bzflag/playing.cxx b/src/bzflag/playing.cxx index 3d771084a5..fc76a547b9 100644 --- a/src/bzflag/playing.cxx +++ b/src/bzflag/playing.cxx @@ -1510,7 +1510,7 @@ static Player* addPlayer(PlayerId id, const void* msg, int showMessage) } -static void printIpInfo (const Player *_player, const Address& addr, +static void printIpInfo (const Player *_player, Address& addr, const std::string ¬e) { if (_player == NULL) @@ -1525,7 +1525,7 @@ static void printIpInfo (const Player *_player, const Address& addr, { colorStr = ColorStrings[CyanColor]; // replay observers } - const std::string addrStr = addr.getDotNotation(); + const std::string addrStr = addr.getIpTextPort(); std::string message = ColorStrings[CyanColor]; // default color message += "IPINFO: "; if (BZDBCache::colorful) message += colorStr; @@ -1563,7 +1563,7 @@ static bool removePlayer (PlayerId id) else { msg += " from "; - msg += addr.getDotNotation(); + msg += addr.getIpTextPort(); p->setIpAddress(addr); addMessage(p, msg); if (BZDB.evalInt("showips") > 1) @@ -3410,7 +3410,7 @@ static void handleServerMessage(bool human, uint16_t code, break; } } - message += " from " + ip.getDotNotation(); + message += " from " + ip.getIpTextPort(); tank->setIpAddress(ip); addMessage(tank, message); } @@ -4946,7 +4946,7 @@ static void addRobots() for (i = 0, j = 0; i < numRobotTanks; i++) { - robotServer[j] = new ServerLink(serverNetworkAddress, startupInfo.serverPort); + robotServer[j] = new ServerLink(serverNetworkAddress); if (!robotServer[j] || robotServer[j]->getState() != ServerLink::Okay) { delete robotServer[j]; @@ -5485,7 +5485,7 @@ static void joinInternetGame() ServerAccessList.reload(); std::vector nameAndIp; nameAndIp.push_back(startupInfo.serverName); - nameAndIp.push_back(serverNetworkAddress.getDotNotation()); + nameAndIp.push_back(serverNetworkAddress.getIpText()); if (!ServerAccessList.authorized(nameAndIp)) { HUDDialogStack::get()->setFailedMessage("Server Access Denied Locally"); @@ -5500,8 +5500,7 @@ static void joinInternetGame() } // open server - ServerLink* _serverLink = new ServerLink(serverNetworkAddress, - startupInfo.serverPort); + ServerLink* _serverLink = new ServerLink(serverNetworkAddress); #if defined(ROBOT) numRobots = 0; @@ -7009,13 +7008,16 @@ static void playingLoop() if (strcmp(startupInfo.token, "badtoken") == 0) startupInfo.token[0] = '\0'; - ares->queryHost(startupInfo.serverName); + ares->queryHost(startupInfo.serverName, TextUtils::itoa(startupInfo.serverPort).c_str()); waitingDNS = true; // don't try again joinRequested = false; } + struct sockaddr_in6 hostAddr; + memset(&hostAddr, 0, sizeof(hostAddr)); + if (waitingDNS) { fd_set readers, writers; @@ -7030,8 +7032,7 @@ static void playingLoop() &timeout); ares->process(&readers, &writers); - struct in_addr inAddress; - AresHandler::ResolutionStatus status = ares->getHostAddress(&inAddress); + AresHandler::ResolutionStatus status = ares->getHostAddr(&hostAddr); if (status == AresHandler::Failed) { HUDDialogStack::get()->setFailedMessage("Server not found"); @@ -7040,7 +7041,7 @@ static void playingLoop() else if (status == AresHandler::HbNSucceeded) { // now try connecting - serverNetworkAddress = Address(inAddress); + serverNetworkAddress = Address(&hostAddr); joinInternetGame(); waitingDNS = false; } diff --git a/src/bzflag/premake5.lua b/src/bzflag/premake5.lua index 78594a0820..ff3a6ad488 100644 --- a/src/bzflag/premake5.lua +++ b/src/bzflag/premake5.lua @@ -93,8 +93,10 @@ project "bzflag" "Carbon.framework", "Cocoa.framework", "CoreAudio.framework", + "CoreHaptics.framework", "CoreVideo.framework", "ForceFeedback.framework", + "GameController.framework", "iconv", "IOKit.framework", "Metal.framework", diff --git a/src/bzfs/AccessControlList.cxx b/src/bzfs/AccessControlList.cxx index 9535f676a8..f41af15421 100644 --- a/src/bzfs/AccessControlList.cxx +++ b/src/bzfs/AccessControlList.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -37,8 +38,7 @@ // bzfs specific headers #include "bzfs.h" - -void AccessControlList::ban(in_addr &ipAddr, const char *bannedBy, int period, +void AccessControlList::ban(const Address *ipAddr, const char *bannedBy, int period, unsigned char cidr, const char *reason, bool fromMaster) { @@ -55,6 +55,9 @@ void AccessControlList::ban(in_addr &ipAddr, const char *bannedBy, int period, bool AccessControlList::ban(std::string &ipList, const char *bannedBy, int period, const char *reason, bool fromMaster) { + ipList = std::regex_replace(ipList, std::regex("\\*\\.\\*\\.\\*$"), "0.0.0/8"); + ipList = std::regex_replace(ipList, std::regex("\\*\\.\\*$"), "0.0/16"); + ipList = std::regex_replace(ipList, std::regex("\\*$"), "0/24"); return ban(ipList.c_str(), bannedBy, period, reason,fromMaster); } @@ -67,14 +70,14 @@ bool AccessControlList::ban(const char *ipList, const char *bannedBy, int period char *pSep; bool added = false; - in_addr mask; + Address mask; unsigned char cidr; while ((pSep = strchr(pStart, ',')) != NULL) { *pSep = 0; if (convert(pStart, mask, cidr)) { - ban(mask, bannedBy, period, cidr, NULL, fromMaster); + ban(&mask, bannedBy, period, cidr, NULL, fromMaster); added = true; } *pSep = ','; @@ -82,7 +85,7 @@ bool AccessControlList::ban(const char *ipList, const char *bannedBy, int period } if (convert(pStart, mask, cidr)) { - ban(mask, bannedBy, period, cidr, reason, fromMaster); + ban(&mask, bannedBy, period, cidr, reason, fromMaster); added = true; } free(buf); @@ -116,7 +119,7 @@ void AccessControlList::idBan(std::string idpat, const char *bannedBy, int perio } -bool AccessControlList::unban(in_addr &ipAddr, unsigned char cidr) +bool AccessControlList::unban(const Address *ipAddr, unsigned char cidr) { banList_t::iterator it = std::remove(banList.begin(), banList.end(), BanInfo(ipAddr, "", 0, cidr)); if (it != banList.end()) @@ -141,18 +144,18 @@ bool AccessControlList::unban(const char *ipList) char *pSep; bool success = false; - in_addr mask; + Address mask; unsigned char cidr; while ((pSep = strchr(pStart, ',')) != NULL) { *pSep = 0; if (convert(pStart, mask, cidr)) - success|=unban(mask, cidr); + success|=unban(&mask, cidr); *pSep = ','; pStart = pSep + 1; } if (convert(pStart, mask, cidr)) - success|=unban(mask, cidr); + success|=unban(&mask, cidr); free(buf); return success; } @@ -182,7 +185,7 @@ bool AccessControlList::idUnban(std::string idpat) } -bool AccessControlList::validate(const in_addr &ipAddr, BanInfo *info) +bool AccessControlList::validate(Address &ipAddr, BanInfo *info) { expire(); @@ -254,56 +257,19 @@ static std::string makeGlobPattern(const char* str) return pattern; } -std::string AccessControlList::getBanMaskString(in_addr mask, unsigned char cidr) +std::string AccessControlList::getBanMaskString(Address *mask, unsigned char cidr) { - // Check for out of range CIDR - if (cidr == 0 || cidr > 32) - return ""; - - std::ostringstream os; - - // Generate /8, /16, and /24 in the wildcard format, and show /32 without - // a CIDR - if (cidr % 8 == 0) - { - os << (ntohl(mask.s_addr) >> 24) << '.'; - if (cidr == 8) - os << "*.*.*"; - else - { - os << ((ntohl(mask.s_addr) >> 16) & 0xff) << '.'; - if (cidr == 16) - os << "*.*"; - else - { - os << ((ntohl(mask.s_addr) >> 8) & 0xff) << '.'; - if (cidr == 24) - os << "*"; - else - os << (ntohl(mask.s_addr) & 0xff); - } - } - } - else - { - // Handle other CIDR values - mask.s_addr &= htonl(0xffffffff << (32 - cidr)); // zero out the host bits - - os << (ntohl(mask.s_addr) >> 24) << '.'; - os << ((ntohl(mask.s_addr) >> 16) & 0xff) << '.'; - os << ((ntohl(mask.s_addr) >> 8) & 0xff) << '.'; - os << (ntohl(mask.s_addr) & 0xff); - os << '/' << (unsigned int)cidr; - } - - return os.str(); + if ((mask->getAddr()->sa_family == AF_INET && cidr == 32) || + (mask->getAddr()->sa_family == AF_INET6 && cidr == 128)) + return mask->getIpText(); + return mask->getIpText() + "/" + std::to_string(cidr); } -void AccessControlList::sendBan(PlayerId id, const BanInfo &baninfo) +void AccessControlList::sendBan(PlayerId id, BanInfo &baninfo) { std::ostringstream os; - os << getBanMaskString(baninfo.addr, baninfo.cidr); + os << getBanMaskString(&baninfo.addr, baninfo.cidr); // print duration when < 1 year double duration = baninfo.banEnd - TimeKeeper::getCurrent(); @@ -337,9 +303,9 @@ void AccessControlList::sendBans(PlayerId id, const char* pattern) // masterbans first for (banList_t::iterator it = banList.begin(); it != banList.end(); ++it) { - const BanInfo& bi = *it; + BanInfo& bi = *it; if (bi.fromMaster && - (glob_match(glob, getBanMaskString(bi.addr, bi.cidr)) || + (glob_match(glob, getBanMaskString(&bi.addr, bi.cidr)) || glob_match(glob, TextUtils::toupper(bi.reason)) || glob_match(glob, TextUtils::toupper(bi.bannedBy)))) sendBan(id, *it); @@ -348,9 +314,9 @@ void AccessControlList::sendBans(PlayerId id, const char* pattern) // normal bans last for (banList_t::iterator it = banList.begin(); it != banList.end(); ++it) { - const BanInfo& bi = *it; + BanInfo& bi = *it; if (!bi.fromMaster && - (glob_match(glob, getBanMaskString(bi.addr, bi.cidr)) || + (glob_match(glob, getBanMaskString(&bi.addr, bi.cidr)) || glob_match(glob, TextUtils::toupper(bi.reason)) || glob_match(glob, TextUtils::toupper(bi.bannedBy)))) sendBan(id, *it); @@ -532,11 +498,11 @@ bool AccessControlList::load() else { // Handle CIDR ban formats - in_addr ip; + Address ip; unsigned char cidr; if (convert(ipAddress, ip, cidr)) { - ban(ip, (bannedBy.size() ? bannedBy.c_str(): NULL), banEnd, + ban(&ip, (bannedBy.size() ? bannedBy.c_str(): NULL), banEnd, cidr, (reason.size() > 0 ? reason.c_str() : NULL)); } else @@ -617,9 +583,6 @@ int AccessControlList::merge(const std::string& banData) } else { - std::string::size_type n; - while ((n = ipAddress.find('*')) != std::string::npos) - ipAddress.replace(n, 1, "255"); if (!ban(ipAddress, (bannedBy.size() ? bannedBy.c_str(): NULL), banEnd, (reason.size() > 0 ? reason.c_str() : NULL),true)) { @@ -643,12 +606,12 @@ void AccessControlList::save() std::cerr<<"Could not open "<fromMaster) // don't save stuff from the master list { // print address - os << getBanMaskString(it->addr, it->cidr) << '\n'; + os << getBanMaskString(&it->addr, it->cidr) << '\n'; // print ban end, banner, and reason if (it->banEnd.getSeconds() == @@ -761,7 +724,7 @@ std::vector > AccessControlList::listMasterB explain = TextUtils::format("%s (banned by %s)", bItr->reason.c_str(), bItr->bannedBy.c_str()); const std::pair - baninfo = std::make_pair(std::string(inet_ntoa(bItr->addr)), explain); + baninfo = std::make_pair(std::string(Address(bItr->addr).getIpText()), explain); bans.push_back(baninfo); } } @@ -793,19 +756,13 @@ std::vector > AccessControlList::listMasterB return bans; } -bool AccessControlList::convert(std::string ip, in_addr &mask, unsigned char &_cidr) +bool AccessControlList::convert(std::string ip, Address &mask, unsigned char &_cidr) { std::vector ipParts; - unsigned char b[4]; - unsigned char cidr = 32; // Check if we have a CIDR and pull it off if so if (ip.find("/") != std::string::npos) { - // CIDR bans can't also contain wildcards - if (ip.find("*") != std::string::npos) - return false; - // Split it into the IP and CIDR parts std::vector ipcidrParts = TextUtils::tokenize(ip, "/"); @@ -813,65 +770,48 @@ bool AccessControlList::convert(std::string ip, in_addr &mask, unsigned char &_c if (ipcidrParts.size() != 2) return false; - // Split the IP octets - ipParts = TextUtils::tokenize(ipcidrParts[0], "."); - - // If we do not have exactly four parts, bail - if (ipParts.size() != 4) - return false; - // Convert the CIDR string to a numeric value const int val = atoi(ipcidrParts[1].c_str()); - if (0 < val && val <= 32) - cidr = (unsigned char)val; - else - return false; - } - else - { - // Split the IP octets - ipParts = TextUtils::tokenize(ip, "."); - // If we do not have exactly four parts, bail - if (ipParts.size() != 4) - return false; + // parse the address + mask = Address(joinNamePort(ipcidrParts[0],0)); - // Check for wildcards - if (ipParts[3] == "*") + switch (mask.getAddr()->sa_family) { - cidr = 24; - ipParts[3] = "0"; - if (ipParts[2] == "*") - { - cidr = 16; - ipParts[2] = "0"; - if (ipParts[1] == "*") - { - cidr = 8; - ipParts[1] = "0"; - // Don't allow *.*.*.* - if (ipParts[0] == "*") - return false; - } - } + case AF_INET: + if (0 > val || val > 32) + return false; + break; + case AF_INET6: + if (0 > val || val > 128) + return false; + break; + default: + return false; } - } - for (int i = 0; i <= 3; i++) + _cidr = val; + return true; + } + else { - const int val = atoi(ipParts[i].c_str()); - if (0 <= val && val < 256) - b[i] = (unsigned char)val; - else + // parse the address + mask = Address(ip + ":0"); + + switch (mask.getAddr()->sa_family) + { + case AF_INET: + _cidr = 32; + return true; + case AF_INET6: + _cidr = 128; + return true; + default: return false; + } } - _cidr = cidr; - mask.s_addr= htonl(((unsigned int)b[0] << 24) | - ((unsigned int)b[1] << 16) | - ((unsigned int)b[2] << 8) | - (unsigned int)b[3]); - return true; + return false; } diff --git a/src/bzfs/AccessControlList.h b/src/bzfs/AccessControlList.h index 369927ab39..6139fc8597 100644 --- a/src/bzfs/AccessControlList.h +++ b/src/bzfs/AccessControlList.h @@ -29,15 +29,17 @@ struct BanInfo /** This constructor creates a new BanInfo with the address @c banAddr, the ban performer @c bannedBy, and the expiration time @c period minutes from now. */ - BanInfo(in_addr &banAddr, const char *_bannedBy = NULL, int period = 0, + BanInfo(const Address *banAddr, const char *_bannedBy = NULL, int period = 0, unsigned char _cidr = 32, bool isFromMaster = false ) { - memcpy( &addr, &banAddr, sizeof( in_addr )); + addr = Address(banAddr[0]); cidr = _cidr; + /* FIXME: // Zero out the host bits if (cidr > 0 && cidr < 32) addr.s_addr &= htonl(0xFFFFFFFFu << (32 - cidr)); + */ if (_bannedBy) bannedBy = _bannedBy; @@ -53,29 +55,86 @@ struct BanInfo /** BanInfos with same IP and CIDR are identical. */ bool operator==(const BanInfo &rhs) const { - return addr.s_addr == rhs.addr.s_addr && cidr == rhs.cidr; + return addr == rhs.addr && cidr == rhs.cidr; } /** Only BanInfos with the same IP and CIDR are identical. */ bool operator!=(const BanInfo &rhs) const { - return addr.s_addr != rhs.addr.s_addr || cidr != rhs.cidr; + return addr != rhs.addr || cidr != rhs.cidr; } - bool contains(const in_addr &checkAddr) + bool contains(Address &cAddr) { // CIDR of 0 matches everything - if (cidr < 1) return true; - // CIDR of 32 means it has to be an exact match - if (cidr >= 32 && addr.s_addr == checkAddr.s_addr) return true; - // Compare network bits - return !((addr.s_addr ^ checkAddr.s_addr) & htonl(0xFFFFFFFFu << (32 - cidr))); + if (cidr < 1) + return true; + // IPv4 CIDR of 32 means it has to be an exact match + if (cidr >= 32 && addr.getAddr()->sa_family == AF_INET) + return addr == cAddr; + // IPv6 CIDR of 128 means it has to be an exact match + if (cidr >= 128 && addr.getAddr()->sa_family == AF_INET6) + return addr == cAddr; + if (addr.getAddr()->sa_family == AF_INET && + cAddr.getAddr()->sa_family == AF_INET) + { + // both ipv4, ipv4 cidr mask check + const sockaddr_in *ip4a = addr.getAddr_in(); + const sockaddr_in *ip4b = cAddr.getAddr_in(); + return !((ip4a->sin_addr.s_addr ^ + ip4b->sin_addr.s_addr) & + htonl(0xFFFFFFFFu << (32 - cidr))); + } + if (addr.getAddr()->sa_family == AF_INET && + cAddr.isMapped()) + { + // cAddr is mapped ipv4 in ipv6 + const sockaddr_in *ip4 = addr.getAddr_in(); + // TODO: Check if this actually works + return !((((in_addr*)(cAddr.getAddr_in6()->sin6_addr.s6_addr + 12))->s_addr ^ + ip4->sin_addr.s_addr) & + htonl(0xFFFFFFFFu << (32 - cidr))); + } + if (addr.isMapped() && + cAddr.getAddr()->sa_family == AF_INET) + { + // addr is mapped ipv4 in ipv6 + // This should never happen. Masks should be in native format + const sockaddr_in *ip4 = cAddr.getAddr_in(); + // TODO: Check if this actually works + return !((((in_addr*)(addr.getAddr_in6()->sin6_addr.s6_addr + 12))->s_addr ^ + ip4->sin_addr.s_addr) & + htonl(0xFFFFFFFFu << (32 - cidr))); + } + // both are IPv6 + if (addr.getAddr()->sa_family == AF_INET6 && + cAddr.getAddr()->sa_family == AF_INET6) + { + // cidr mask excluding last partial byte if any + if (cidr >= 8 && memcmp( + &addr.getAddr_in6()->sin6_addr, + &cAddr.getAddr_in6()->sin6_addr, + cidr / 8 )) + return false; + // good up to the last byte, is that all? + if (!(cidr % 8)) + return true; + // compare bits in the last byte + // TODO: Check if this actually works + return (((addr.getAddr_in6()->sin6_addr.s6_addr[cidr / 8] ^ + cAddr.getAddr_in6()->sin6_addr.s6_addr[cidr / 8]) & + (uint8_t)(0xff << ((128 - cidr) % 8))) == 0); + } + logDebugMessage(5,"contains(%s) FIXME: did not test %s/%i\n", + cAddr.getIpText().c_str(), + addr.getIpText().c_str(), cidr); + return false; } - in_addr addr; - unsigned char cidr; - TimeKeeper banEnd; - std::string bannedBy; // Who did perform the ban - std::string reason; // reason for banning + Address addr; + uint8_t cidr; + TimeKeeper banEnd; + std::string bannedBy; // Who did perform the ban + std::string reason; // reason for banning bool fromMaster; // where the ban came from, local or master list. }; @@ -182,7 +241,7 @@ class AccessControlList /** This function will add a ban for the address @c ipAddr with the given parameters. If that address already is banned the old ban will be replaced. */ - void ban(in_addr &ipAddr, const char *bannedBy, int period = 0, + void ban(const Address *ipAddr, const char *bannedBy, int period = 0, unsigned char cidr = 32, const char *reason=NULL, bool fromMaster = false); @@ -213,7 +272,7 @@ class AccessControlList /** This function removes any ban for the address @c ipAddr. @returns @c true if there was a ban for that address, @c false if there wasn't. */ - bool unban(in_addr &ipAddr, unsigned char cidr); + bool unban(const Address *ipAddr, unsigned char cidr); /** This function unbans any addresses given in @c ipList, which should be a comma separated string in the same format as in the ban() functions. @@ -240,7 +299,7 @@ class AccessControlList /** This function checks if an address is "valid" or not. Valid in this case means that it has not been banned. @returns @c true if the address is valid, @c false if not. */ - bool validate(const in_addr &ipAddr, BanInfo *info = NULL); + bool validate(Address &ipAddr, BanInfo *info = NULL); /** This function checks that a hostname is "valid". In this case valid means "not banned". @@ -253,7 +312,7 @@ class AccessControlList bool idValidate(const char *idname, IdBanInfo *info = NULL); /** This function sends a textual list of the given IP ban to a player. */ - void sendBan(PlayerId id, const BanInfo&); + void sendBan(PlayerId id, BanInfo&); /** This function sends a textual list of all IP bans to a player. */ void sendBans(PlayerId id, const char* pattern); @@ -285,7 +344,7 @@ class AccessControlList presumably so it can be remerged */ void purgeMasters(void); - std::string getBanMaskString(in_addr mask, unsigned char cidr); + std::string getBanMaskString(Address *mask, unsigned char cidr); std::vector > listMasterBans(void) const; @@ -302,8 +361,8 @@ class AccessControlList private: /** This function converts a char* containing an IP mask to an - @c in_addr. */ - bool convert(std::string ip, in_addr &mask, unsigned char &cidr); + @c Address. */ + bool convert(std::string ip, Address &mask, unsigned char &cidr); /** This function checks all bans to see if any of them have expired, and removes those who have. */ diff --git a/src/bzfs/BanCommands.cxx b/src/bzfs/BanCommands.cxx index 037a6d7449..c7bfb14f42 100644 --- a/src/bzfs/BanCommands.cxx +++ b/src/bzfs/BanCommands.cxx @@ -591,8 +591,8 @@ bool CheckIPCommand::operator() (const char *message, return true; } - in_addr ip = Address(argv[1]); - BanInfo baninfo(ip); + Address ip(argv[1]); + BanInfo baninfo(&ip); const bool banned = !clOptions->acl.validate(ip, &baninfo); if (banned) @@ -859,11 +859,14 @@ bool BanCommand::operator() (const char *message, for (int i = 0; i < curMaxPlayers; i++) { GameKeeper::Player *tmpVictim = GameKeeper::Player::getPlayerByIndex(i); - if (tmpVictim && - !clOptions->acl.validate(tmpVictim->netHandler->getIPAddress())) + if (tmpVictim) { - // ignore the return code - doBanKick(tmpVictim, playerData, banEvent.reason.c_str()); + Address tmpAddr = tmpVictim->netHandler->getTaddr(); + if (!clOptions->acl.validate(tmpAddr)) + { + // ignore the return code + doBanKick(tmpVictim, playerData, banEvent.reason.c_str()); + } } } } diff --git a/src/bzfs/CmdLineOptions.cxx b/src/bzfs/CmdLineOptions.cxx index 07689d56e3..be0913017d 100644 --- a/src/bzfs/CmdLineOptions.cxx +++ b/src/bzfs/CmdLineOptions.cxx @@ -1418,6 +1418,7 @@ void parse(int argc, char **argv, CmdLineOptions &options, bool fromWorldFile) i++; } } + setDebugTimestamp (clOptions->timestampLog, clOptions->timestampMicros, clOptions->timestampUTC); } #ifdef HAVE_MINIUPNPC_MINIUPNPC_H else if (strcmp(argv[i], "-UPnP") == 0) @@ -1433,6 +1434,7 @@ void parse(int argc, char **argv, CmdLineOptions &options, bool fromWorldFile) // timestamp output options.timestampLog = true; options.timestampUTC = true; + setDebugTimestamp (clOptions->timestampLog, clOptions->timestampMicros, clOptions->timestampUTC); } else if (strcmp(argv[i], "-userdb") == 0) { @@ -1919,27 +1921,35 @@ void finalizeParsing(int UNUSED(argc), char **argv, // debugging logDebugMessage(1,"type: %d\n", options.gameType); - if (options.gameType == ClassicCTF) - logDebugMessage(1," capture the flag\n"); - if (options.gameType == RabbitChase) - logDebugMessage(1," rabbit chase\n"); - if (options.gameType == OpenFFA) - logDebugMessage(1," open free-for-all\n"); - if (options.gameType == TeamFFA) - logDebugMessage(1," teamed free-for-all\n"); - + switch (options.gameType) + { + case ClassicCTF: + logDebugMessage(1,"\tcapture the flag\n"); + break; + case RabbitChase: + logDebugMessage(1,"\trabbit chase\n"); + break; + case OpenFFA: + logDebugMessage(1,"\topen free-for-all\n"); + break; + case TeamFFA: + logDebugMessage(1,"\tteamed free-for-all\n"); + break; + default: + logDebugMessage(1,"\tunknown\n"); + } logDebugMessage(1,"options: %X\n", options.gameOptions); if (options.gameOptions & int(SuperFlagGameStyle)) - logDebugMessage(1," super flags allowed\n"); + logDebugMessage(1,"\tsuper flags allowed\n"); if (options.gameOptions & int(JumpingGameStyle)) - logDebugMessage(1," jumping allowed\n"); + logDebugMessage(1,"\tjumping allowed\n"); if (options.gameOptions & int(RicochetGameStyle)) - logDebugMessage(1," all shots ricochet\n"); + logDebugMessage(1,"\tall shots ricochet\n"); if (options.gameOptions & int(ShakableGameStyle)) - logDebugMessage(1," shakable bad flags: timeout=%f, wins=%i\n", + logDebugMessage(1,"\tshakable bad flags: timeout=%f, wins=%i\n", 0.1f * float(options.shakeTimeout), options.shakeWins); if (options.gameOptions & int(AntidoteGameStyle)) - logDebugMessage(1," antidote flags\n"); + logDebugMessage(1,"\tantidote flags\n"); return; } diff --git a/src/bzfs/GameKeeper.cxx b/src/bzfs/GameKeeper.cxx index 35f4c1ca7f..629c3c7b62 100644 --- a/src/bzfs/GameKeeper.cxx +++ b/src/bzfs/GameKeeper.cxx @@ -38,7 +38,7 @@ void PackPlayerInfo(MessageBuffer::Ptr msg, int playerIndex, uint8_t properties) } GameKeeper::Player::Player(int _playerIndex, - const struct sockaddr_in &clientAddr, int fd, + const struct sockaddr_in6 &clientAddr, int fd, tcpCallback _clientCallback) : _LSAState(start), _JoinState(waitingForAuthentication), diff --git a/src/bzfs/GameKeeper.h b/src/bzfs/GameKeeper.h index dccbd2651f..adc30bc951 100644 --- a/src/bzfs/GameKeeper.h +++ b/src/bzfs/GameKeeper.h @@ -69,7 +69,7 @@ class GameKeeper class Player { public: - Player(int _playerIndex, const struct sockaddr_in &clientAddr, int fd, tcpCallback _clientCallback); + Player(int _playerIndex, const struct sockaddr_in6 &clientAddr, int fd, tcpCallback _clientCallback); Player(int _playerIndex, NetHandler *handler, tcpCallback _clientCallback); Player(int _playerIndex, bz_ServerSidePlayerHandler *handler); ~Player(); diff --git a/src/bzfs/ListServerConnection.cxx b/src/bzfs/ListServerConnection.cxx index ab38f4712d..6d18b9c9ca 100644 --- a/src/bzfs/ListServerConnection.cxx +++ b/src/bzfs/ListServerConnection.cxx @@ -49,8 +49,9 @@ ListServerLink::ListServerLink(std::string listServerURL, publiclyDisconnected = false; - if (clOptions->pingInterface != "") - setInterface(clOptions->pingInterface); + //FIXME: we might be listening on :: but still only have ipv4 connectivity + //if (clOptions->pingInterface != "") + // setInterface(clOptions->pingInterface); publicizeAddress = publicizedAddress; publicizeDescription = publicizedTitle; @@ -223,7 +224,7 @@ void ListServerLink::finalization(char *data, unsigned int length, bool good) */ if (authReply) { - logDebugMessage(3,"Got: %s", base); + logDebugMessage(3,"Got: %s\n", base); char *group = (char *)NULL; // Isolate callsign from groups @@ -350,7 +351,7 @@ void ListServerLink::sendQueuedMessages() queuedRequest = true; if (nextMessageType == ListServerLink::ADD) { - logDebugMessage(3,"Queuing ADD message to list server\n"); + logDebugMessage(3,"Queuing ADD %s, players %i\n", publicizeAddress.c_str(), GameKeeper::Player::count()); bz_ListServerUpdateEvent_V1 updateEvent; updateEvent.address = publicizeAddress; @@ -365,7 +366,7 @@ void ListServerLink::sendQueuedMessages() } else if (nextMessageType == ListServerLink::REMOVE) { - logDebugMessage(3,"Queuing REMOVE message to list server\n"); + logDebugMessage(3,"Queuing REMOVE %s\n", publicizeAddress.c_str()); removeMe(publicizeAddress); } nextMessageType = ListServerLink::NONE; @@ -409,8 +410,7 @@ void ListServerLink::addMe(PingPacket pingInfo, playerData->_LSAState = GameKeeper::Player::checking; NetHandler* handler = playerData->netHandler.get(); msg += TextUtils::url_encode(playerData->player.getCallSign()); - Address addr = handler->getIPAddress(); - if (!addr.isPrivate()) + if (!handler->getTaddr()->isPrivate()) { msg += "@"; msg += handler->getTargetIP(); diff --git a/src/bzfs/RecordReplay.cxx b/src/bzfs/RecordReplay.cxx index 0ac67a26cb..132fa600de 100644 --- a/src/bzfs/RecordReplay.cxx +++ b/src/bzfs/RecordReplay.cxx @@ -1303,7 +1303,7 @@ bool Replay::sendPackets() } // for loop } // if (p->mode != HiddenPacket) else - logDebugMessage(4," skipping hidden packet\n"); + logDebugMessage(4,"\tskipping hidden packet\n"); p = nextPacket(); sent = true; diff --git a/src/bzfs/bzfs.cxx b/src/bzfs/bzfs.cxx index 2d0d4a9b4f..d561cc33d8 100644 --- a/src/bzfs/bzfs.cxx +++ b/src/bzfs/bzfs.cxx @@ -92,7 +92,7 @@ static bool doSpeedChecks = true; CmdLineOptions *clOptions; // server address to listen on -struct sockaddr_in serverAddr; +Address serverAddr; // well known service socket static int wksSocket; bool handlePings = true; @@ -545,11 +545,7 @@ std::string GetPlayerIPAddress( int i) if (!playerData || !playerData->netHandler) return tmp; - unsigned int address = (unsigned int)playerData->netHandler->getIPAddress().s_addr; - unsigned char* a = (unsigned char*)&address; - - tmp = TextUtils::format("%d.%d.%d.%d",(int)a[0],(int)a[1],(int)a[2],(int)a[3]); - return tmp; + return playerData->netHandler->getTargetIP(); } void sendPlayerUpdate(GameKeeper::Player* player) @@ -964,19 +960,18 @@ static bool serverStart() #ifdef SO_REUSEADDR #if defined(_WIN32) const BOOL optOn = TRUE; + const BOOL optOff = FALSE; BOOL opt; #else const int optOn = 1; + const int optOff = 0; int opt; #endif #endif maxFileDescriptor = 0; - serverAddr.sin_port = htons(clOptions->wksPort); - pingReply.serverId.addr = serverAddr; - // open well known service port - wksSocket = socket(AF_INET, SOCK_STREAM, 0); + wksSocket = socket(serverAddr.getAddr()->sa_family, SOCK_STREAM, 0); if (wksSocket == -1) { nerror("couldn't make connect socket"); @@ -992,7 +987,19 @@ static bool serverStart() return false; } #endif - if (bind(wksSocket, (const struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) + if (serverAddr.getAddr()->sa_family == AF_INET6) + { + /* for ipv6, accept connections for ipv4 as well */ + opt = optOff; + if (setsockopt(wksSocket, IPPROTO_IPV6, IPV6_V6ONLY, (SSOType)&opt, sizeof(opt)) < 0) + { + nerror("serverStart: setsockopt IPV6_V6ONLY"); + close(wksSocket); + return false; + } + } + + if (bind(wksSocket, serverAddr.getAddr(), sizeof(struct sockaddr_in6)) == -1) { nerror("couldn't bind connect socket"); close(wksSocket); @@ -1337,7 +1344,7 @@ static void acceptClient() { // client (not a player yet) is requesting service. // accept incoming connection on our well known port - struct sockaddr_in clientAddr; + struct sockaddr_in6 clientAddr; AddrLen addr_len = sizeof(clientAddr); int fd = accept(wksSocket, (struct sockaddr*)&clientAddr, &addr_len); if (fd == -1) @@ -1407,15 +1414,15 @@ static bool MakePlayer ( NetHandler *handler ) if (playerIndex != 0xff) { logDebugMessage(1,"Player [%d] accept() from %s on %i\n", playerIndex, - sockaddr2iptextport(handler->getUADDR()), handler->getFD()); + handler->getTargetIP(), handler->getFD()); if (playerIndex >= curMaxPlayers) curMaxPlayers = playerIndex+1; } else // full? reject by closing socket { - logDebugMessage(1,"all slots occupied, rejecting accept() from %s:%d on %i\n", - sockaddr2iptextport(handler->getUADDR()), handler->getFD()); + logDebugMessage(1,"all slots occupied, rejecting accept() from %s on %i\n", + handler->getTargetIP(), handler->getFD()); // send back 0xff before closing send(handler->getFD(), (const char*)buffer, sizeof(buffer), 0); @@ -1461,10 +1468,9 @@ void checkGameOn() } -static void respondToPing(Address addr) +static void respondToPing(void) { // reply with current game info - pingReply.sourceAddr = addr; // Total up rogue + rabbit + hunter teams pingReply.rogueCount = (uint8_t)team[0].team.size + (uint8_t)team[6].team.size + (uint8_t)team[7].team.size; pingReply.redCount = (uint8_t)team[1].team.size; @@ -2217,8 +2223,8 @@ void AddPlayer(int playerIndex, GameKeeper::Player *playerData) const bool playerIsAntiBanned = playerData->accessInfo.hasPerm(PlayerAccessInfo::antiban); // check against the ip ban list - in_addr playerIP = playerData->netHandler->getIPAddress(); - BanInfo info(playerIP); + Address playerIP(playerData->netHandler->getTaddr()); + BanInfo info(&playerIP); if (!playerIsAntiBanned && !clOptions->acl.validate(playerIP,&info)) { std::string rejectionMessage; @@ -4868,7 +4874,7 @@ static void handleCommand(int t, void *rawbuf, bool udp) playerData->hasEntered = true; playerData->accessInfo.setName(playerData->player.getCallSign()); std::string timeStamp = TimeKeeper::timestamp(); - logDebugMessage(1,"Player %s [%d] has joined from %s at %s with token \"%s\"\n", + logDebugMessage(1,"Player %s [%d] joined from %s at %s token \"%s\"\n", playerData->player.getCallSign(), t, handler->getTargetIP(), timeStamp.c_str(), playerData->player.getToken()); @@ -6063,7 +6069,8 @@ void rescanForBans ( bool isOperator, const char* callsign, int playerID ) for (int i = 0; i < curMaxPlayers; i++) { GameKeeper::Player *otherPlayer = GameKeeper::Player::getPlayerByIndex(i); - if (otherPlayer && !clOptions->acl.validate(otherPlayer->netHandler->getIPAddress())) + Address oAddr(otherPlayer->netHandler->getTaddr()); + if (otherPlayer && !clOptions->acl.validate(oAddr)) { // operators can override antiperms if (!isOperator) @@ -6171,18 +6178,6 @@ void sendBufferedNetDataForPeer (NetConnectedPeer &peer ) peer.sendChunks.pop_front(); } -std::string getIPFromHandler (NetHandler* netHandler) -{ - unsigned int address = (unsigned int)netHandler->getIPAddress().s_addr; - unsigned char* a = (unsigned char*)&address; - - static std::string strRet; - - strRet = TextUtils::format("%d.%d.%d.%d",(int)a[0],(int)a[1],(int)a[2],(int)a[3]); - - return strRet; -} - static void processConnectedPeer(NetConnectedPeer& peer, int UNUSED(sockFD), fd_set& UNUSED(read_set), fd_set& UNUSED(write_set)) { @@ -6253,7 +6248,7 @@ static void processConnectedPeer(NetConnectedPeer& peer, int UNUSED(sockFD), fd_ return; } - bz_AllowConnectionData_V1 data(getIPFromHandler(netHandler).c_str()); + bz_AllowConnectionData_V1 data(netHandler->getTargetIP()); worldEventManager.callEvents(&data); if (!data.allow) { @@ -6287,7 +6282,7 @@ static void processConnectedPeer(NetConnectedPeer& peer, int UNUSED(sockFD), fd_ } netHandler->flushData(); - bz_AllowConnectionData_V1 data(getIPFromHandler(netHandler).c_str()); + bz_AllowConnectionData_V1 data(netHandler->getTargetIP()); worldEventManager.callEvents(&data); if (!data.allow) { @@ -6296,8 +6291,8 @@ static void processConnectedPeer(NetConnectedPeer& peer, int UNUSED(sockFD), fd_ return; } - in_addr IP = netHandler->getIPAddress(); - BanInfo info(IP); + Address IP = netHandler->getTaddr(); + BanInfo info(&IP); if (!clOptions->acl.validate(IP, &info)) { logDebugMessage(2,"Peer %s banned\n", netHandler->getTargetIP()); @@ -6380,8 +6375,7 @@ void UPnP::setIGD() #endif if (!devlist) { - std::cerr << "No UPnP device found" - << std::endl; + logDebugMessage(1, "No UPnP device found\n"); return; } // Select a good IGD (Internet Gateway Device) @@ -6725,8 +6719,7 @@ int main(int argc, char **argv) if (clOptions->publicizeServer && clOptions->publicizedKey.empty()) { - logDebugMessage(0, - "\nWARNING: Publicly listed bzfs servers must register" + logDebugMessage(0,"\nWARNING: Publicly listed bzfs servers must register" " using the '-publickey 'option.\n\n"); } @@ -6747,10 +6740,6 @@ int main(int argc, char **argv) } #endif - // start listening and prepare world database - memset(&serverAddr, 0, sizeof(serverAddr)); - serverAddr.sin_family = AF_INET; - if (!defineWorld()) { #ifdef BZ_PLUGINS @@ -6870,12 +6859,13 @@ int main(int argc, char **argv) clOptions->wksPort = ntohs(service->s_port); } + if (clOptions->pingInterface == "") + clOptions->pingInterface = "::"; + serverAddr = Address(joinNamePort(clOptions->pingInterface, clOptions->wksPort)); + if (clOptions->UPnP) bzUPnP.start(); - if (clOptions->pingInterface != "") - serverAddr.sin_addr = Address::getHostAddress(clOptions->pingInterface); - // my address to publish. allow arguments to override (useful for // firewalls). use my official hostname if it appears to be // canonicalized, otherwise use my IP in dot notation. @@ -6887,8 +6877,8 @@ int main(int argc, char **argv) std::string generatedPublicAddress = Address::getHostName(); if (generatedPublicAddress.find('.') == std::string::npos) { - if (!Address(serverAddr.sin_addr).isAny() && !Address(serverAddr.sin_addr).isPrivate()) - generatedPublicAddress = Address(serverAddr.sin_addr).getDotNotation(); + if (!serverAddr.isAny() && !serverAddr.isPrivate()) + generatedPublicAddress = serverAddr.getIpTextPort(); else generatedPublicAddress = ""; } @@ -6923,13 +6913,10 @@ int main(int argc, char **argv) if (clOptions->rabbitSelection == RandomRabbitSelection) Score::setRandomRanking(); // print networking info - logDebugMessage(1,"\tlistening on %s\n", - sockaddr2iptextport((const struct sockaddr *)&serverAddr)); + logDebugMessage(1,"\tlistening on %s\n", serverAddr.getIpTextPort().c_str()); logDebugMessage(1,"\twith title of \"%s\"\n", clOptions->publicizedTitle.c_str()); // prep ping reply - pingReply.serverId.addr = serverAddr; - pingReply.serverId.number = 0; pingReply.gameType = clOptions->gameType; pingReply.gameOptions = clOptions->gameOptions; pingReply.maxPlayers = (uint8_t)maxRealPlayers; @@ -7763,7 +7750,7 @@ int main(int argc, char **argv) TimeKeeper receiveTime = TimeKeeper::getCurrent(); while (true) { - struct sockaddr_in uaddr; + struct sockaddr_in6 uaddr; unsigned char ubuf[MaxPacketLen]; bool udpLinkRequest; // interface to the UDP Receive routines @@ -7777,7 +7764,7 @@ int main(int argc, char **argv) // then ignore the ping. if (handlePings) { - respondToPing(Address(uaddr)); + respondToPing(); pingReply.write(NetHandler::getUdpSocket(), &uaddr); } continue; diff --git a/src/bzfs/bzfsAPI.cxx b/src/bzfs/bzfsAPI.cxx index c91709c7f3..4e4534ea8f 100644 --- a/src/bzfs/bzfsAPI.cxx +++ b/src/bzfs/bzfsAPI.cxx @@ -2410,7 +2410,7 @@ BZF_API const char* bz_getBanItem ( bz_eBanListType listType, unsigned int item { default: case eIPList: - API_BAN_ITEM = clOptions->acl.getBanMaskString(clOptions->acl.banList[item].addr, + API_BAN_ITEM = clOptions->acl.getBanMaskString(&clOptions->acl.banList[item].addr, clOptions->acl.banList[item].cidr).c_str(); break; diff --git a/src/common/ErrorHandler.cxx b/src/common/ErrorHandler.cxx index 40161555cf..f90c03f425 100644 --- a/src/common/ErrorHandler.cxx +++ b/src/common/ErrorHandler.cxx @@ -39,12 +39,20 @@ void printError(const std::string &fmt, const std::vectorempty()) - msg = pBdl->formatMessage(fmt, parms); + { + // FIXME: bzfs and bzadmin should init bundle + if ((parms != NULL) && !parms->empty()) + msg = parms->front(); + else + msg = fmt; + } else - msg = pBdl->getLocalString(fmt); + { + if ((parms != NULL) && !parms->empty()) + msg = pBdl->formatMessage(fmt, parms); + else + msg = pBdl->getLocalString(fmt); + } if (errorCallback) (*errorCallback)(msg.c_str()); #if defined(_WIN32) @@ -54,7 +62,8 @@ void printError(const std::string &fmt, const std::vector CURLM_OK) - logDebugMessage(1,"Error while adding easy handle from libcurl %d : %s\n", + logDebugMessage(1,"Error while adding easy handle from libcurl %d: %s\n", result, errorBuffer); added = true; } @@ -235,7 +235,7 @@ void cURLManager::removeHandle() return; CURLMcode result = curl_multi_remove_handle(multiHandle, easyHandle); if (result != CURLM_OK) - logDebugMessage(1,"Error while removing easy handle from libcurl %d : %s\n", + logDebugMessage(1,"Error while removing easy handle from libcurl %d: %s\n", result, errorBuffer); added = false; } @@ -274,7 +274,7 @@ int cURLManager::fdset(fd_set &read, fd_set &write) result = curl_multi_fdset(multiHandle, &read, &write, &exc, &max_fd); if (result != CURLM_OK) - logDebugMessage(1,"Error while doing multi_fdset from libcurl %d : %s\n", + logDebugMessage(1,"Error while doing multi_fdset from libcurl %d: %s\n", result, errorBuffer); return max_fd; } @@ -294,7 +294,7 @@ bool cURLManager::perform() break; } if (result != CURLM_OK) - logDebugMessage(1,"Error while doing multi_perform from libcurl %d : %s\n", + logDebugMessage(1,"Error while doing multi_perform from libcurl %d: %s\n", result, errorBuffer); int msgs_in_queue; @@ -322,7 +322,7 @@ bool cURLManager::perform() void cURLManager::infoComplete(CURLcode result) { if (result != CURLE_OK) - logDebugMessage(1,"File transfer terminated with error from libcurl %d : %s\n", + logDebugMessage(1,"File transfer terminated with error from libcurl %d: %s\n", result, errorBuffer); removeHandle(); finalization((char *)theData, theLen, result == CURLE_OK); @@ -339,7 +339,7 @@ bool cURLManager::getFileTime(time_t &t) result = curl_easy_getinfo(easyHandle, CURLINFO_FILETIME, &filetime); if (result) { - logDebugMessage(1,"CURLINFO_FILETIME error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLINFO_FILETIME error %d: %s\n", result, errorBuffer); return false; } t = (time_t)filetime; @@ -354,7 +354,7 @@ bool cURLManager::getFileSize(int &size) size = (int)mySize; if (result) { - logDebugMessage(1,"CURLINFO_SIZE_DOWNLOAD_T error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLINFO_SIZE_DOWNLOAD_T error %d: %s\n", result, errorBuffer); return false; } return true; @@ -371,19 +371,19 @@ void cURLManager::setTimeCondition(timeCondition condition, time_t &t) CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_TIMECONDITION error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLOPT_TIMECONDITION error %d: %s\n", result, errorBuffer); break; case ModifiedSince: result = curl_easy_setopt(easyHandle, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_TIMECONDITION error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLOPT_TIMECONDITION error %d: %s\n", result, errorBuffer); result = curl_easy_setopt(easyHandle, CURLOPT_TIMEVALUE, (long)t); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_TIMEVALUE error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLOPT_TIMEVALUE error %d: %s\n", result, errorBuffer); break; default: break; @@ -400,7 +400,7 @@ void cURLManager::setInterface(const std::string &_interfaceIP) CURLOPT_INTERFACE, interfaceIP.c_str()); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_SET_INTERFACE error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLOPT_SET_INTERFACE error %d: %s\n", result, errorBuffer); } void cURLManager::setUserAgent(const std::string &_userAgent) @@ -413,7 +413,7 @@ void cURLManager::setUserAgent(const std::string &_userAgent) CURLOPT_USERAGENT, userAgent.c_str()); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_SET_USERAGENT error %d : %s\n", result, errorBuffer); + logDebugMessage(1,"CURLOPT_SET_USERAGENT error %d: %s\n", result, errorBuffer); } void cURLManager::setDNSCachingTime(long time) @@ -424,7 +424,7 @@ void cURLManager::setDNSCachingTime(long time) CURLOPT_DNS_CACHE_TIMEOUT, (long)time); if (result != CURLE_OK) - logDebugMessage(1,"CURLOPT_SET_DNS_CACHE_TIMEOUT error %d : %s\n", + logDebugMessage(1,"CURLOPT_SET_DNS_CACHE_TIMEOUT error %d: %s\n", result, errorBuffer); } diff --git a/src/game/CollisionManager.cxx b/src/game/CollisionManager.cxx index 9d77becaa4..c3113ab660 100644 --- a/src/game/CollisionManager.cxx +++ b/src/game/CollisionManager.cxx @@ -498,21 +498,21 @@ void CollisionManager::load () logDebugMessage(2,"ColDet Octree obstacles = %i\n", FullList.count); for (i = 0; i < 3; i++) { - logDebugMessage(2," grid extent[%i] = %f, %f\n", i, gridExtents.mins[i], + logDebugMessage(2,"\tgrid extent[%i] = %f, %f\n", i, gridExtents.mins[i], gridExtents.maxs[i]); } for (i = 0; i < 3; i++) { - logDebugMessage(2," world extent[%i] = %f, %f\n", i, worldExtents.mins[i], + logDebugMessage(2,"\tworld extent[%i] = %f, %f\n", i, worldExtents.mins[i], worldExtents.maxs[i]); } - logDebugMessage(2,"ColDet Octree leaf nodes = %i\n", leafNodes); - logDebugMessage(2,"ColDet Octree total nodes = %i\n", totalNodes); - logDebugMessage(2,"ColDet Octree total elements = %i\n", totalElements); + logDebugMessage(2,"\tleaf nodes = %i\n", leafNodes); + logDebugMessage(2,"\ttotal nodes = %i\n", totalNodes); + logDebugMessage(2,"\ttotal elements = %i\n", totalElements); // print the timing info float elapsed = (float)(TimeKeeper::getCurrent() - startTime); - logDebugMessage(2,"Collision Octree processed in %.3f seconds.\n", elapsed); + logDebugMessage(2,"\tprocessed in %.3f seconds.\n", elapsed); // setup the split list diff --git a/src/game/NetHandler.cxx b/src/game/NetHandler.cxx index 0156afcf92..759abb1b21 100644 --- a/src/game/NetHandler.cxx +++ b/src/game/NetHandler.cxx @@ -52,12 +52,12 @@ void callNetworkDataLog ( bool send, bool udp, const unsigned char *data, unsig } bool NetHandler::pendingUDP = false; -bool NetHandler::initHandlers(struct sockaddr_in addr) +bool NetHandler::initHandlers(Address addr) { // udp socket int n; // we open a udp socket on the same port if alsoUDP - if ((udpSocket = (int) socket(AF_INET, SOCK_DGRAM, 0)) < 0) + if ((udpSocket = (int) socket(addr.getAddr()->sa_family, SOCK_DGRAM, 0)) < 0) { nerror("couldn't make udp connect socket"); return false; @@ -136,7 +136,7 @@ int NetHandler::getUdpSocket() return udpSocket; } -int NetHandler::udpReceive(char *buffer, struct sockaddr_in *uaddr, +int NetHandler::udpReceive(char *buffer, struct sockaddr_in6 *uaddr, bool &udpLinkRequest) { AddrLen recvlen = sizeof(*uaddr); @@ -145,13 +145,13 @@ int NetHandler::udpReceive(char *buffer, struct sockaddr_in *uaddr, uint16_t code; while (true) { - n = recvfrom(udpSocket, buffer, MaxUDPPacketLen, 0, (struct sockaddr *) uaddr, - &recvlen); + n = recvfrom(udpSocket, buffer, MaxUDPPacketLen, 0, + (struct sockaddr *) uaddr, &recvlen); if ((n < 0) || (n >= 4)) break; } // Error receiving data (or no data) - if (n < 0 || uaddr->sin_port < 1024) + if (n < 0 || uaddr->sin6_port < 1024) return -1; // read head @@ -171,9 +171,11 @@ int NetHandler::udpReceive(char *buffer, struct sockaddr_in *uaddr, int id(-1); // player index of the matched player int pi; udpLinkRequest = false; + Address packetAddress(uaddr); for (pi = 0; pi < maxHandlers; pi++) if (netPlayer[pi] && !netPlayer[pi]->closed - && netPlayer[pi]->isMyUdpAddrPort(*uaddr)) + && netPlayer[pi]->isMyUaddr(packetAddress) && + netPlayer[pi]->uaddr.getNPort() == uaddr->sin6_port) { id = pi; break; @@ -186,26 +188,25 @@ int NetHandler::udpReceive(char *buffer, struct sockaddr_in *uaddr, if ((index < maxHandlers) && netPlayer[index] && !netPlayer[index]->closed && !netPlayer[index]->udpin) { - if (!memcmp(&netPlayer[index]->uaddr.sin_addr, &uaddr->sin_addr, - sizeof(uaddr->sin_addr))) + if (netPlayer[index]->uaddr == packetAddress) { id = index; - if (uaddr->sin_port) - netPlayer[index]->uaddr.sin_port = uaddr->sin_port; + if (uaddr->sin6_port) + netPlayer[index]->uaddr.getAddr_in6()->sin6_port = uaddr->sin6_port; netPlayer[index]->udpin = true; udpLinkRequest = true; logDebugMessage(2,"Player slot %d inbound UDP up %s actual %d\n", index, sockaddr2iptextport((const struct sockaddr *)uaddr), - ntohs(uaddr->sin_port)); + ntohs(uaddr->sin6_port)); } else { // sockaddr2nameport has a single buffer - logDebugMessage(2,"Player slot %d inbound UDP rejected %s", + logDebugMessage(2,"Player slot %d inbound UDP rejected %s\n", index, sockaddr2iptextport((const struct sockaddr *)&netPlayer[index]->uaddr)); - logDebugMessage(2," different IP than %s\n", + logDebugMessage(2,"\tdifferent IP than %s\n", sockaddr2iptextport((const struct sockaddr *)uaddr)); } @@ -217,15 +218,14 @@ int NetHandler::udpReceive(char *buffer, struct sockaddr_in *uaddr, if (debugLevel < 4) return -1; // no match, discard packet - logDebugMessage(3,"uread() discard packet! %s choices p(l) h:p", + logDebugMessage(3,"uread() discard packet! %s choices p(l) h:p\n", sockaddr2iptextport((const struct sockaddr *)uaddr)); for (pi = 0; pi < maxHandlers; pi++) { if (netPlayer[pi] && !netPlayer[pi]->closed) - logDebugMessage(4," %d(%d-%d) %s", pi, netPlayer[pi]->udpin, netPlayer[pi]->udpout, + logDebugMessage(4,"\t%d(%d-%d) %s\n", pi, netPlayer[pi]->udpin, netPlayer[pi]->udpout, sockaddr2iptextport((const struct sockaddr *)uaddr)); } - logDebugMessage(3,"\n"); } else { @@ -271,10 +271,10 @@ void NetHandler::checkDNS(fd_set *read_set, fd_set *write_set) int NetHandler::udpSocket = -1; NetHandler *NetHandler::netPlayer[maxHandlers] = {NULL}; -NetHandler::NetHandler(PlayerInfo* _info, const struct sockaddr_in &clientAddr, +NetHandler::NetHandler(PlayerInfo* _info, const struct sockaddr_in6 &clientAddr, int _playerIndex, int _fd) - : ares(new AresHandler(_playerIndex)), info(_info), taddr(clientAddr), - uaddr(clientAddr), playerIndex(_playerIndex), fd(_fd), + : ares(new AresHandler(_playerIndex)), info(_info), taddr(&clientAddr), + uaddr(&clientAddr), playerIndex(_playerIndex), fd(_fd), tcplen(0), closed(false), outmsgOffset(0), outmsgSize(0), outmsgCapacity(0), outmsg(0), udpOutputLen(0), udpin(false), udpout(false), toBeKicked(false), @@ -306,17 +306,13 @@ NetHandler::NetHandler(PlayerInfo* _info, const struct sockaddr_in &clientAddr, ares->queryHostname((const struct sockaddr *) &clientAddr); } -NetHandler::NetHandler(const struct sockaddr_in &_clientAddr, int _fd) - : ares(0), info(0), playerIndex(-1), fd(_fd), +NetHandler::NetHandler(const struct sockaddr_in6 &_clientAddr, int _fd) + : ares(0), info(0), taddr(&_clientAddr), uaddr(&_clientAddr), playerIndex(-1), fd(_fd), tcplen(0), closed(false), outmsgOffset(0), outmsgSize(0), outmsgCapacity(0), outmsg(0), udpOutputLen(0), udpin(false), udpout(false), toBeKicked(false), time(TimeKeeper::getCurrent()) { - // store address information for player - memcpy(&taddr, &_clientAddr, sizeof(_clientAddr)); - memcpy(&uaddr, &_clientAddr, sizeof(_clientAddr)); - #ifdef NETWORK_STATS // initialize the inbound/outbound counters to zero @@ -750,18 +746,18 @@ void NetHandler::dumpMessageStats() for (direction = 0; direction <= 1; direction++) { total = 0; - logDebugMessage(1,"Player messages %s:", direction ? "out" : "in"); + logDebugMessage(1,"Player messages %s\n", direction ? "out" : "in"); for (MessageCountMap::iterator i = msg[direction].begin(); i != msg[direction].end(); ++i) { - logDebugMessage(1," %c%c:%u(%u)", i->first >> 8, i->first & 0xff, + logDebugMessage(1,"\t%c%c:%u(%u)\n", i->first >> 8, i->first & 0xff, i->second.count, i->second.maxSize); total += i->second.count; } - logDebugMessage(1," total:%u(%u) ", total, msgBytes[direction]); - logDebugMessage(1,"max msgs/bytes per second: %u/%u\n", + logDebugMessage(1,"\ttotal:%u(%u)\n", total, msgBytes[direction]); + logDebugMessage(1,"\tmax msgs/bytes per second: %u/%u\n", perSecondMaxMsg[direction], perSecondMaxBytes[direction]); } @@ -813,10 +809,10 @@ void NetHandler::udpSend(const void *b, size_t l) pendingUDP = true; } -bool NetHandler::isMyUdpAddrPort(struct sockaddr_in _uaddr) +/* compare IP portion of uaddr ONLY */ +bool NetHandler::isMyUaddr(const Address _uaddr) { - return udpin && (uaddr.sin_port == _uaddr.sin_port) && - (memcmp(&uaddr.sin_addr, &_uaddr.sin_addr, sizeof(uaddr.sin_addr)) == 0); + return udpin && (uaddr == _uaddr); } const std::string NetHandler::getPlayerHostInfo() @@ -842,7 +838,7 @@ const char* NetHandler::getTargetIP() int NetHandler::sizeOfIP() { - switch(taddr.sin_family) + switch(taddr.getAddr()->sa_family) { case AF_INET: // IPv4 is 1 byte for type and 4 bytes for IP = 5 @@ -856,7 +852,7 @@ int NetHandler::sizeOfIP() void *NetHandler::packAdminInfo(void *buf) { - buf = Address(taddr).pack(buf); + buf = taddr.pack(buf); return buf; } @@ -879,11 +875,6 @@ int NetHandler::whoIsAtIP(const std::string& IP) return position; } -in_addr NetHandler::getIPAddress() -{ - return uaddr.sin_addr; -} - const char *NetHandler::getHostname() { if (!ares) diff --git a/src/game/ServerItem.cxx b/src/game/ServerItem.cxx index 34c4bb1093..0e6e9993d5 100644 --- a/src/game/ServerItem.cxx +++ b/src/game/ServerItem.cxx @@ -41,12 +41,6 @@ void ServerItem::writeToFile(std::ostream& out) const strncpy(&buffer[0],description.c_str(),copyLength); out.write(buffer,sizeof(buffer)); - // write out name - memset(buffer,0,sizeof(buffer)); - copyLength = int(name.size() < ServerListCache::max_string ? name.size(): ServerListCache::max_string); - strncpy(&buffer[0],name.c_str(),copyLength); - out.write(buffer,sizeof(buffer)); - // write out pingpacket ping.writeToFile(out); @@ -69,12 +63,6 @@ bool ServerItem::readFromFile(std::istream& in, int subrevision) if ((size_t)in.gcount() < sizeof(buffer)) return false; // failed to read entire string description = buffer; - //read name - memset(buffer,0,sizeof(buffer)); - in.read(buffer,sizeof(buffer)); - if ((size_t)in.gcount() < sizeof(buffer)) return false; // failed to read entire string - name = buffer; - bool pingWorked = ping.readFromFile(in); if (!pingWorked) return false; // pingpacket failed to read @@ -211,11 +199,6 @@ int ServerItem::getPlayerCount() const return curPlayer; } -std::string ServerItem::getAddrName() const -{ - return TextUtils::format("%s:%d", name.c_str(), ntohs(ping.serverId.addr.sin_port)); -} - unsigned int ServerItem::getSortFactor() const { // if null ping we return a 0 player count @@ -241,20 +224,6 @@ unsigned int ServerItem::getSortFactor() const } -void ServerItem::splitAddrTitle(std::string& addr, std::string& title) const -{ - addr = stripAnsiCodes(description); - title = ""; - const std::string::size_type pos = addr.find_first_of(';'); - if (pos == std::string::npos) - return; - const std::string::size_type tpos = pos + 2; // skip the ';' and ' ' - if (addr.size() > tpos) - title = addr.substr(tpos); - addr.resize(pos); -} - - // Local Variables: *** // mode: C++ *** // tab-width: 4 *** diff --git a/src/game/ServerList.cxx b/src/game/ServerList.cxx index a468a879ca..5fef61ef22 100644 --- a/src/game/ServerList.cxx +++ b/src/game/ServerList.cxx @@ -43,7 +43,6 @@ ServerList::~ServerList() void ServerList::startServerPings(StartupInfo *info) { - // schedule lookup of server list url. dereference URL chain every // time instead of only first time just in case one of the pointers // has changed. @@ -120,29 +119,22 @@ void ServerList::readServerList() continue; } // parse server info - char *scan2, *name, *version, *infoServer, *address, *title; - name = base; - version = name; + char *namePort, *version, *infoServer, *description; + namePort = base; + version = namePort; while (*version && !isspace(*version)) version++; while (*version && isspace(*version)) *version++ = 0; infoServer = version; while (*infoServer && !isspace(*infoServer)) infoServer++; while (*infoServer && isspace(*infoServer)) *infoServer++ = 0; - address = infoServer; - while (*address && !isspace(*address)) address++; - while (*address && isspace(*address)) *address++ = 0; - title = address; - while (*title && !isspace(*title)) title++; - while (*title && isspace(*title)) *title++ = 0; + description = infoServer; + while (*description && !isspace(*description)) description++; + while (*description && isspace(*description)) *description++ = 0; // extract port number from address - int port = ServerPort; - scan2 = strchr(name, ':'); - if (scan2) - { - port = atoi(scan2 + 1); - *scan2 = 0; - } + int port; + std::string name; + splitNamePort(std::string(namePort), name, port); // check info if (strcmp(version, getServerVersion()) == 0 && @@ -152,41 +144,10 @@ void ServerList::readServerList() // store info ServerItem serverInfo; serverInfo.ping.unpackHex(infoServer); - int dot[4] = {127,0,0,1}; - if (sscanf(address, "%d.%d.%d.%d", dot+0, dot+1, dot+2, dot+3) == 4) - { - if (dot[0] >= 0 && dot[0] <= 255 && - dot[1] >= 0 && dot[1] <= 255 && - dot[2] >= 0 && dot[2] <= 255 && - dot[3] >= 0 && dot[3] <= 255) - { - serverInfo.ping.serverId.addr.sin_family = AF_INET; - unsigned char* paddr = (unsigned char*)&serverInfo.ping.serverId.addr.sin_addr.s_addr; - paddr[0] = (unsigned char)dot[0]; - paddr[1] = (unsigned char)dot[1]; - paddr[2] = (unsigned char)dot[2]; - paddr[3] = (unsigned char)dot[3]; - } - } - serverInfo.ping.serverId.addr.sin_port = htons((int16_t)port); - serverInfo.name = name; - - // construct description - serverInfo.description = serverInfo.name; - if (port != ServerPort) - { - char portBuf[20]; - sprintf(portBuf, "%d", port); - serverInfo.description += ":"; - serverInfo.description += portBuf; - } - if (strlen(title) > 0) - { - serverInfo.description += "; "; - serverInfo.description += title; - } - + serverInfo.name = joinNamePort(name, port); + serverInfo.description = description; serverInfo.cached = false; + // add to list & add it to the server cache addToList(serverInfo, true); } @@ -210,9 +171,7 @@ void ServerList::addToList(ServerItem info, bool doCache) for (i = 0; i < (int)servers.size(); i++) { ServerItem& server = servers[i]; - if (server.ping.serverId.addr.sin_addr.s_addr - == info.ping.serverId.addr.sin_addr.s_addr - && server.ping.serverId.addr.sin_port == info.ping.serverId.addr.sin_port) + if (server.name == info.name) { servers.erase(servers.begin() + i); // erase this item break; @@ -236,8 +195,7 @@ void ServerList::addToList(ServerItem info, bool doCache) } // mark server in current list if it is a favorite server - std::string serverAddress = info.getAddrName(); - if (serverCache->isFavorite(serverAddress)) + if (serverCache->isFavorite(info.name)) info.favorite = true; if (insertPoint == -1) // no spot to insert it into -- goes on back @@ -268,23 +226,23 @@ void ServerList::addToList(ServerItem info, bool doCache) info.setUpdateTime(); ServerListCache::SRV_STR_MAP::iterator iter; - iter = serverCache->find(serverAddress); // find entry to allow update + iter = serverCache->find(info.name); // find entry to allow update if (iter != serverCache->end()) // if we find it, update it iter->second = info; else { // insert into cache -- wasn't found - serverCache->insert(serverAddress, info); + serverCache->insert(info.name, info); } } } // mark server identified by host:port string as favorite -void ServerList::markFav(const std::string &serverAddress, bool fav) +void ServerList::markFav(const std::string &namePort, bool fav) { for (int i = 0; i < (int)servers.size(); i++) { - if (serverAddress == servers[i].getAddrName()) + if (namePort == servers[i].name) { servers[i].favorite = fav; break; @@ -301,7 +259,6 @@ void ServerList::checkEchos(StartupInfo *info) // lookup server list in phase 0 if (phase == 0) { - std::string url = info->listServerURL; std::string msg = "action=LIST&version="; @@ -348,39 +305,25 @@ void ServerList::checkEchos(StartupInfo *info) // check broadcast sockets ServerItem serverInfo; - sockaddr_in addr; + sockaddr_in6 addr; if (pingBcastSocket != -1 && FD_ISSET(pingBcastSocket, &read_set)) { if (serverInfo.ping.read(pingBcastSocket, &addr)) { - serverInfo.ping.serverId.addr = addr; serverInfo.cached = false; serverInfo.localDiscovery = true; - addToListWithLookup(serverInfo); + if (addr.sin6_port == htons(ServerPort)) + serverInfo.name = sockaddr2iptext((const sockaddr *)&addr); + else + serverInfo.name = sockaddr2iptextport((const sockaddr *)&addr); + serverInfo.description = sockaddr2iptextport((const sockaddr *)&addr); + addToList(serverInfo); } } } // end loop waiting for input/output on any list server } -void ServerList::addToListWithLookup(ServerItem& info) -{ - info.name = Address::getHostByAddress(info.ping.serverId.addr.sin_addr); - - // tack on port number to description if not default - info.description = info.name; - const int port = (int)ntohs((unsigned short)info.ping.serverId.addr.sin_port); - if (port != ServerPort) - { - char portBuf[20]; - sprintf(portBuf, "%d", port); - info.description += ":"; - info.description += portBuf; - } - - addToList(info); // do not cache network lan - etc. servers -} - // add the entire cache to the server list void ServerList::addCacheToList() { diff --git a/src/game/ServerListCache.cxx b/src/game/ServerListCache.cxx index 93a7f7a298..0aaaa03895 100644 --- a/src/game/ServerListCache.cxx +++ b/src/game/ServerListCache.cxx @@ -45,16 +45,16 @@ ServerListCache* ServerListCache::get() } -// insert a serverItem mapped by the serverAddress -void ServerListCache::insert(const std::string &serverAddress, const ServerItem &info) +// insert a serverItem mapped by namePort +void ServerListCache::insert(const std::string &namePort, const ServerItem &info) { - serverCache.insert(SRV_STR_MAP::value_type(serverAddress,info)); + serverCache.insert(SRV_STR_MAP::value_type(namePort,info)); } -ServerListCache::SRV_STR_MAP::iterator ServerListCache::find(const std::string &serverAddress) +ServerListCache::SRV_STR_MAP::iterator ServerListCache::find(const std::string &namePort) { - return serverCache.find(serverAddress); + return serverCache.find(namePort); } @@ -69,9 +69,9 @@ ServerListCache::SRV_STR_MAP::iterator ServerListCache::end() return serverCache.end(); } -bool ServerListCache::isFavorite(const std::string &serverAddress) const +bool ServerListCache::isFavorite(const std::string &namePort) const { - SRV_STR_MAP::const_iterator i = serverCache.find(serverAddress); + SRV_STR_MAP::const_iterator i = serverCache.find(namePort); return i!=serverCache.end() && i->second.favorite; } @@ -104,7 +104,6 @@ void ServerListCache::saveCache() char buffer[max_string+1]; for (SRV_STR_MAP::iterator iter = serverCache.begin(); iter != serverCache.end(); ++iter) { - // skip items that are more than 30 days old, but always save favorites if (!iter->second.favorite && iter->second.getAgeMinutes() > 60*24*30) continue; @@ -144,19 +143,18 @@ void ServerListCache::loadCache() char buffer[max_string+1]; while (inFile) { - std::string serverIndex; ServerItem info; inFile.read(buffer,sizeof(buffer)); //read the index of the map if ((size_t)inFile.gcount() < sizeof(buffer)) break; // failed to read entire string - serverIndex = buffer; + info.name = buffer; bool infoWorked = info.readFromFile(inFile, subrevision); // after a while it is doubtful that player counts are accurate if (info.getAgeMinutes() > (time_t)30) info.ping.zeroPlayerCounts(); if (!infoWorked) break; - serverCache.insert(SRV_STR_MAP::value_type(serverIndex,info)); + serverCache.insert(SRV_STR_MAP::value_type(info.name,info)); } inFile.close(); } diff --git a/src/net/Address.cxx b/src/net/Address.cxx index 23887361db..0bd6eb0353 100644 --- a/src/net/Address.cxx +++ b/src/net/Address.cxx @@ -19,6 +19,7 @@ // system headers #include #include +#include #include #if !defined(_WIN32) #include @@ -49,30 +50,37 @@ extern "C" int inet_aton(const char *, struct in_addr *); #endif // helper function, might want to live someplace else -static char iptextbuf[INET6_ADDRSTRLEN]; +static char iptext[INET6_ADDRSTRLEN]; +const char v4inv6[] = "::ffff:"; // remove this on v4 in v6 space char *sockaddr2iptext(const struct sockaddr *sa) { + const sockaddr_in6 *ip6 = (const sockaddr_in6 *)sa; + switch(sa->sa_family) { case AF_INET: - inet_ntop(AF_INET, &(((const struct sockaddr_in *)sa)->sin_addr), iptextbuf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET, &(((const struct sockaddr_in *)sa)->sin_addr), iptext, INET6_ADDRSTRLEN); break; case AF_INET6: - inet_ntop(AF_INET6, &(((const struct sockaddr_in6 *)sa)->sin6_addr), iptextbuf, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &(((const struct sockaddr_in6 *)sa)->sin6_addr), iptext, INET6_ADDRSTRLEN); + if (IN6_IS_ADDR_V4MAPPED(&ip6->sin6_addr)) + memmove(iptext,&iptext[sizeof(v4inv6) - 1], sizeof(iptext) - sizeof(v4inv6)); break; default: - strncpy(iptextbuf, "Unknown AF", 11); + strncpy(iptext, "Unknown AF", 11); } - return iptextbuf; + return iptext; } // address + []:port static char iptextport[INET6_ADDRSTRLEN + 8]; char *sockaddr2iptextport(const struct sockaddr *sa) { + const sockaddr_in6 *ip6 = (const sockaddr_in6 *)sa; + switch(sa->sa_family) { case AF_INET: @@ -80,48 +88,126 @@ char *sockaddr2iptextport(const struct sockaddr *sa) break; case AF_INET6: - sprintf(iptextport, "[%s]:%u", sockaddr2iptext(sa), ntohs(((const struct sockaddr_in6 *)sa)->sin6_port)); + if (IN6_IS_ADDR_V4MAPPED(&ip6->sin6_addr)) + sprintf(iptextport, "%s:%u", sockaddr2iptext(sa), ntohs(((const struct sockaddr_in6 *)sa)->sin6_port)); + else + sprintf(iptextport, "[%s]:%u", sockaddr2iptext(sa), ntohs(((const struct sockaddr_in6 *)sa)->sin6_port)); break; default: - strncpy(iptextport, "Unknown AF", 11); + sprintf(iptextport, "Unknown AF:%i", sa->sa_family); } return iptextport; } +bool splitNamePort(std::string namePort, std::string &name, int &port) +{ + std::smatch m; + + if (regex_search(namePort, m, std::regex("^\\[([a-fA-F0-9:]*)\\]:([0-9]*)$"))) + { + // [v6]:port + long int serverPort = strtol(m.str(2).c_str(), NULL, 10); + if (serverPort >= 0 && serverPort < 65536) + { + port = (int) serverPort; + name = m.str(1); + return true; + } + } + if (regex_search(namePort, m, std::regex("^([a-fA-F0-9:]*)$"))) + { + // bare v6 + port = ServerPort; + name = m.str(1); + return true; + } + size_t cPos = namePort.find(':'); + if (cPos != std::string::npos) + { + long int serverPort = strtol(namePort.substr(cPos + 1).c_str(), (char **)NULL, 10); + if (serverPort >= 0 && serverPort < 65536) + port = (int) serverPort; + name = namePort.substr(0, cPos); + } + else + { + name = namePort; + port = ServerPort; + return true; + } + return false; +} +std::string joinNamePort(std::string name, int port) +{ + if (regex_search(name, std::regex("^([a-fA-F0-9:]*)$"))) + return "[" + name + "]:" + std::to_string(port); + if (port == ServerPort) + return name; + return name + ":" + std::to_string(port); +} + // // Address // Address::Address() { - InAddr tempAddr; - - memset(&tempAddr, 0, sizeof(tempAddr)); - tempAddr.s_addr = htonl(INADDR_ANY); - addr.push_back(tempAddr); + memset(&addr, 0, sizeof(addr)); } -Address::Address(const std::string& name) +Address::Address(const std::string &_iptextport) { - Address a = getHostAddress(name); - addr.push_back(a.addr[0]); + struct addrinfo hints; + struct addrinfo *result; + + std::string tryiptext; + int port; + splitNamePort(_iptextport, tryiptext, port); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + // FIXME: make this non-blocking + int s = getaddrinfo(tryiptext.c_str(), std::to_string(port).c_str(), &hints, &result); + if (s == 0) + { + // FIXME: try other entries + memcpy(&addr, (const void *)result->ai_addr, sizeof(addr)); + freeaddrinfo(result); + logDebugMessage(5, "Address() got: %s from %s\n", + getIpTextPort().c_str(), _iptextport.c_str()); + return; + } + logDebugMessage(1, "Address() failure: %s\n",_iptextport.c_str()); + memset(&addr, 0, sizeof(addr)); + return; } -Address::Address(const Address& address) : addr(address.addr) +Address::Address(const Address *address) { - // do nothing + memcpy(&addr, (const void *)&address->addr, sizeof(addr)); + iptext = address->iptext; + iptextport = address->iptextport; } -Address::Address(const InAddr& _addr) +Address::Address(const Address &address) { - addr.push_back(_addr); + memcpy(&addr, (const void *)&address.addr, sizeof(addr)); + iptext = address.iptext; + iptextport = address.iptextport; } -Address::Address(const struct sockaddr_in& _addr) +Address::Address(const struct sockaddr_in6 *_addr) { - addr.push_back(_addr.sin_addr); + memcpy(&addr, (const void *)_addr, sizeof(addr)); + logDebugMessage(5, "Address() got: %s\n", getIpTextPort().c_str()); } Address::~Address() @@ -131,64 +217,181 @@ Address::~Address() Address& Address::operator=(const Address& address) { - addr.clear(); - addr.push_back(address.addr[0]); + memcpy(&addr, (const void *)&address.addr, sizeof(addr)); return *this; } -Address::operator InAddr() const -{ - return addr[0]; -} - bool Address::operator==(const Address& address) const { - return addr[0].s_addr == address.addr[0].s_addr; + // compare address ONLY, ignore port + if (addr.sin6_family == AF_INET6 && address.addr.sin6_family == AF_INET6) + return !memcmp(&addr.sin6_addr, &address.addr.sin6_addr, sizeof(addr.sin6_addr)); + if (addr.sin6_family == AF_INET && address.addr.sin6_family == AF_INET) + { + const sockaddr_in *ip4a = (const sockaddr_in *)&addr; + const sockaddr_in *ip4b = (const sockaddr_in *)&address.addr; + return ip4a->sin_addr.s_addr == ip4b->sin_addr.s_addr; + } + if (addr.sin6_family == AF_INET6 && + address.addr.sin6_family == AF_INET && + isMapped()) + { + // addr is mapped ipv4 in ipv6 + const sockaddr_in *ip4b = (const sockaddr_in *)&address.addr; + // TODO: Check if this actually works + return ((const in_addr*)(addr.sin6_addr.s6_addr + 12))->s_addr == ip4b->sin_addr.s_addr; + } + if (addr.sin6_family == AF_INET && + address.addr.sin6_family == AF_INET6 && + address.isMapped()) + { + // addrress.addr is mapped ipv4 in ipv6 + const sockaddr_in *ip4a = (const sockaddr_in *)&addr; + // TODO: Check if this actually works + return ip4a->sin_addr.s_addr == ((const in_addr*)(address.addr.sin6_addr.s6_addr + 12))->s_addr; + } + logDebugMessage(4,"Address== mixed family: %s\n", + sockaddr2iptextport((const struct sockaddr *)&address.addr)); + logDebugMessage(4,"\twith: %s\n", + sockaddr2iptextport((const struct sockaddr *)&addr)); + return false; } bool Address::operator!=(const Address& address) const { - return addr[0].s_addr != address.addr[0].s_addr; + return !operator==(address); } bool Address::operator<(Address const& address) const { - return addr[0].s_addr < address.addr[0].s_addr; + return memcmp(&addr, &address.addr, sizeof(addr)) < 0; } + +/* IPv4 mapped into different IPv6/96 address blocks */ +bool Address::isMapped() const +{ + switch(addr.sin6_family) + { + case AF_INET6: + // IPv4 mapped into ::ffff:a.b.c.d space + if (IN6_IS_ADDR_V4MAPPED(&addr.sin6_addr)) + return true; + // NAT64 common space 64:ff9b::8.8.8.8 + // TODO: Check if this actually works + else if ( + (addr.sin6_addr.s6_addr16[0] == 0x6400) && + (addr.sin6_addr.s6_addr16[1] == 0x9bff) && + (addr.sin6_addr.s6_addr16[2] == 0x0000) && + (addr.sin6_addr.s6_addr16[3] == 0x0000) && + (addr.sin6_addr.s6_addr16[4] == 0x0000) && + (addr.sin6_addr.s6_addr16[5] == 0x0000) + ) + return true; + return false; + default: + return false; + } +} + bool Address::isAny() const { - return addr[0].s_addr == htonl(INADDR_ANY); + switch(addr.sin6_family) + { + case AF_INET: + return ((const struct sockaddr_in*)&addr)->sin_addr.s_addr == htonl(INADDR_ANY); + + case AF_INET6: + // TODO: Check if this actually works + return IN6_ARE_ADDR_EQUAL(&in6addr_any, &addr.sin6_addr); + + default: + return false; + } } bool Address::isPrivate() const { - // 127.0.0.0/8 - if ((addr[0].s_addr & htonl(0xff000000u)) == htonl(0x7f000000u)) - return(true); - // 10.0.0.0/8 - if ((addr[0].s_addr & htonl(0xff000000u)) == htonl(0x0a000000u)) - return(true); - // 172.16.0.0/12 - if ((addr[0].s_addr & htonl(0xfff00000u)) == htonl(0xac100000u)) - return(true); - // 192.168.0.0/16 - if ((addr[0].s_addr & htonl(0xffff0000u)) == htonl(0xc0a80000u)) - return(true); - return(false); + uint32_t ip4 = ((const struct sockaddr_in *)&addr)->sin_addr.s_addr; + + switch(addr.sin6_family) + { + case AF_INET: + // 127.0.0.0/8 + if ((ip4 & htonl(0xff000000u)) == htonl(0x7f000000u)) + return true; + // 10.0.0.0/8 + if ((ip4 & htonl(0xff000000u)) == htonl(0x0a000000u)) + return true; + // 172.16.0.0/12 + if ((ip4 & htonl(0xfff00000u)) == htonl(0xac100000u)) + return true; + // 192.168.0.0/16 + if ((ip4 & htonl(0xffff0000u)) == htonl(0xc0a80000u)) + return true; + return false; + + case AF_INET6: + // fc00::/7 + // TODO: Check if this actually works + if ((addr.sin6_addr.s6_addr[0] == 0xfc) || (addr.sin6_addr.s6_addr[0] == 0xfd)) + return true; + // fe80::/10 + if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr)) + return true; + return false; + + default: + return false; + } +} + +sockaddr *Address::getAddr() +{ + return (sockaddr*)&addr; } -std::string Address::getDotNotation() const +sockaddr_in *Address::getAddr_in() { - return std::string(inet_ntoa(addr[0])); + // we don't check family. This is really just a cast. + return (sockaddr_in*)&addr; +} + +sockaddr_in6 *Address::getAddr_in6() +{ + // we don't check family. This is really just a cast. + return &addr; +} + +// Get the port in network byte order +in_port_t Address::getNPort() const +{ + return addr.sin6_port; +} + +std::string Address::getIpText() +{ + if (iptext.size() == 0) + iptext = sockaddr2iptext((const struct sockaddr *)&addr); + return iptext.c_str(); +} + +std::string Address::getIpTextPort() +{ + if (iptextport.size() == 0) + iptextport = sockaddr2iptextport((const struct sockaddr *)&addr); + return iptextport.c_str(); } uint8_t Address::getIPVersion() const { - return 4; + if (addr.sin6_family == AF_INET6) + return BZF_INET6; + return BZF_INET; } static const struct hostent* bz_gethostbyname(const std::string &name) { + // FIXME: convert to non-blocking ares call const struct hostent* hent = NULL; if (name.length() > 0) @@ -210,16 +413,11 @@ static const struct hostent* bz_gethostbyname(const std::string &name) Address Address::getHostAddress(const std::string &hname) { - Address a; - InAddr tempAddr; - int j; + Address a = new Address(); - if (hname.length() > 0 && inet_aton(hname.c_str(), &tempAddr) != 0) - { - a.addr.clear(); - a.addr.push_back(tempAddr); - return a; - } + // FIXME convert fron iptext without dns lookup + //if (hname.length() > 0 && inet_aton(hname.c_str(), &a.addr.sin_addr.s_addr != 0) + // return a; const struct hostent* hent = bz_gethostbyname(hname); if (!hent) @@ -228,28 +426,11 @@ Address Address::getHostAddress(const std::string &hname) return a; } - a.addr.clear(); - for (j=0; hent->h_addr_list[j] != NULL; j++) - { - ::memcpy(&tempAddr, hent->h_addr_list[j], sizeof(tempAddr)); - a.addr.push_back(tempAddr); - } + // FIXME: we only look at the first IP + //::memcpy(&addr, hent->h_addr_list[0], sizeof(addr)); return a; } -std::string Address::getHostByAddress(InAddr addr) -{ - int addrLen = sizeof(addr); - struct hostent* hent = gethostbyaddr((char*)&addr, addrLen, AF_INET); - - if (!hent) - { - // can't lookup name -- return in standard dot notation - return std::string(inet_ntoa(addr)); - } - return std::string(hent->h_name); -} - const std::string Address::getHostName(const std::string &hostname) // const { const struct hostent* hent = bz_gethostbyname(hostname); @@ -261,74 +442,69 @@ const std::string Address::getHostName(const std::string &hostname) // const void* Address::pack(void* _buf) const { unsigned char* buf = (unsigned char*)_buf; - buf = (unsigned char*)nboPackUByte(_buf, 4); - // everything in InAddr is already in network byte order - int32_t hostaddr = int32_t(addr[0].s_addr); - ::memcpy(buf, &hostaddr, sizeof(int32_t)); - buf += sizeof(int32_t); - return (void*)buf; -} -const void* Address::unpack(const void* _buf) -{ - const unsigned char* buf = (const unsigned char*)_buf; - InAddr tempAddr; - // FIXME - should actually parse the first byte to see if it's IPv4 or - // IPv6 - ++buf; - // everything in InAddr should be stored in network byte order - int32_t hostaddr; - ::memcpy(&hostaddr, buf, sizeof(int32_t)); - buf += sizeof(int32_t); - tempAddr.s_addr = u_long(hostaddr); - addr.clear(); - addr.push_back(tempAddr); - return buf; -} + // ipv4 pointer to simplfy code + const struct sockaddr_in *addr_in = (const struct sockaddr_in *)&addr; -// -// ServerId -// + buf = (unsigned char*)nboPackUByte(_buf, getIPVersion()); + // should already in network byte order + switch(addr.sin6_family) + { + case AF_INET: + ::memcpy(buf, &addr_in->sin_addr.s_addr, sizeof(in_addr_t)); + buf += sizeof(in_addr_t); + ::memcpy(buf, &addr_in->sin_port, sizeof(in_port_t)); + buf += sizeof(in_port_t); + break; -void* ServerId::pack(void* _buf) const -{ - // everything in ServerId is already in network byte order - unsigned char* buf = (unsigned char*)_buf; - assert(addr.sin_family == AF_INET); - ::memcpy(buf, &addr.sin_addr, sizeof(int32_t)); - buf += sizeof(int32_t); - ::memcpy(buf, &addr.sin_port, sizeof(int16_t)); - buf += sizeof(int16_t); - ::memcpy(buf, &number, sizeof(int16_t)); - buf += sizeof(int16_t); + case AF_INET6: + ::memcpy(buf, &addr.sin6_addr, sizeof(in6_addr)); + buf += sizeof(in6_addr); + ::memcpy(buf, &addr.sin6_port, sizeof(in_port_t)); + buf += sizeof(in_port_t); + break; + + default: + logDebugMessage(0,"Address(): unknown family %u\n", addr.sin6_family); + exit(EXIT_FAILURE); + } return (void*)buf; } -const void* ServerId::unpack(const void* _buf) +const void* Address::unpack(const void* _buf) { - // everything in ServerId should be stored in network byte order + // ipv4 pointer to simplfy code + struct sockaddr_in *addr_in = (struct sockaddr_in *)&addr; + const unsigned char* buf = (const unsigned char*)_buf; - addr.sin_family = AF_INET; - ::memcpy(&addr.sin_addr, buf, sizeof(int32_t)); - buf += sizeof(int32_t); - ::memcpy(&addr.sin_port, buf, sizeof(int16_t)); - buf += sizeof(int16_t); - ::memcpy(&number, buf, sizeof(int16_t)); - buf += sizeof(int16_t); - return buf; -} + memset(&addr, 0, sizeof(addr)); + uint8_t family; + buf = (const unsigned char*)nboUnpackUByte(buf, family); + switch(family) + { + case BZF_INET: + addr.sin6_family = AF_INET; + ::memcpy(&(addr_in->sin_addr), buf, sizeof(in_addr_t)); + buf += sizeof(in_addr_t); + ::memcpy(&addr_in->sin_port, buf, sizeof(in_port_t)); + buf += sizeof(in_port_t); + break; -bool ServerId::operator==(const ServerId& id) const -{ - return addr.sin_addr.s_addr == id.addr.sin_addr.s_addr && - addr.sin_port == id.addr.sin_port && - number == id.number; -} + case BZF_INET6: + addr.sin6_family = AF_INET6; + ::memcpy(&addr.sin6_addr, buf, sizeof(in6_addr)); + buf += sizeof(in6_addr); + ::memcpy(&addr.sin6_port, buf, sizeof(in_port_t)); + buf += sizeof(in_port_t); + break; -bool ServerId::operator!=(const ServerId& id) const -{ - return addr.sin_addr.s_addr != id.addr.sin_addr.s_addr || - addr.sin_port != id.addr.sin_port || number != id.number; + default: + logDebugMessage(0, "Address(): unknown family %u\n", addr.sin6_family); + exit(EXIT_FAILURE); + } + + // should be stored in network byte order + return buf; } // Local Variables: *** diff --git a/src/net/AresHandler.cxx b/src/net/AresHandler.cxx index e82afcfbe6..594077d895 100644 --- a/src/net/AresHandler.cxx +++ b/src/net/AresHandler.cxx @@ -82,15 +82,54 @@ void AresHandler::queryHostname(const struct sockaddr *clientAddr) { if (aresFailed) return; - + const sockaddr_in6 *ip6 = (const sockaddr_in6 *)clientAddr; status = HbAPending; // launch the asynchronous query to look up this hostname - ares_gethostbyaddr(aresChannel, &((const sockaddr_in *)clientAddr)->sin_addr, - sizeof(in_addr), clientAddr->sa_family, staticCallback, (void *)this); - logDebugMessage(2,"Player [%d] submitted reverse resolve query\n", index); + logDebugMessage(2,"Player [%d] submitting reverse resolve query\n", index); + if (clientAddr->sa_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&ip6->sin6_addr)) + { + // lookup wrapped v4 in v6 + const in_addr* clientV4Addr = (const in_addr*)(ip6->sin6_addr.s6_addr + 12); + ares_gethostbyaddr(aresChannel, clientV4Addr, sizeof(*clientV4Addr), AF_INET, staticHostCallback, (void *)this); + } + else + ares_gethostbyaddr(aresChannel, &((const sockaddr_in *)clientAddr)->sin_addr, + sizeof(in_addr), clientAddr->sa_family, staticHostCallback, (void *)this); +} + +#if ARES_VERSION_MAJOR >= 1 && ARES_VERSION_MINOR >= 5 +void AresHandler::staticHostCallback(void *arg, int callbackStatus, int, hostent *hostent) +#else +void AresHandler::staticHostCallback(void *arg, int callbackStatus, hostent *hostent) +#endif +{ + ((AresHandler *)arg)->callback(callbackStatus, hostent); +} + +void AresHandler::callback(int callbackStatus, struct hostent *hostent) +{ + if (callbackStatus == ARES_EDESTRUCTION) + return; + if (callbackStatus != ARES_SUCCESS) + { + logDebugMessage(1,"Player [%d] failed to resolve: error %d\n", index, + callbackStatus); + status = Failed; + } + else if (status == HbAPending) + { + hostName = strdup(hostent->h_name); + status = HbASucceeded; + logDebugMessage(2,"Player [%d] resolved to %s\n", index, hostName.c_str()); + } + else if (status == HbNPending) + { + memcpy(&hostAddress, hostent->h_addr_list[0], sizeof(hostAddress)); + status = HbNSucceeded; + } } -void AresHandler::queryHost(const char *name) +void AresHandler::queryHost(const char *name, const char *service) { if (aresFailed) return; @@ -102,30 +141,22 @@ void AresHandler::queryHost(const char *name) return; } - if (inet_aton(name, &hostAddress) != 0) - { - status = HbNSucceeded; - return; - } - // launch the asynchronous query to look up this hostname status = HbNPending; - ares_gethostbyname(aresChannel, name, AF_INET, staticCallback, - (void *)this); + + struct ares_addrinfo_hints hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + ares_getaddrinfo(aresChannel, name, service, &hints, staticAddrInfoCallback, (void *)this); } -#if ARES_VERSION_MAJOR >= 1 && ARES_VERSION_MINOR >= 5 -void AresHandler::staticCallback(void *arg, int callbackStatus, - int, struct hostent *hostent) -#else -void AresHandler::staticCallback(void *arg, int callbackStatus, - struct hostent *hostent) -#endif +void AresHandler::staticAddrInfoCallback(void *arg, int callbackStatus, int, ares_addrinfo *result) { - ((AresHandler *)arg)->callback(callbackStatus, hostent); + ((AresHandler *)arg)->callback(callbackStatus, result); } -void AresHandler::callback(int callbackStatus, struct hostent *hostent) +void AresHandler::callback(int callbackStatus, ares_addrinfo *result) { if (callbackStatus == ARES_EDESTRUCTION) return; @@ -135,15 +166,10 @@ void AresHandler::callback(int callbackStatus, struct hostent *hostent) callbackStatus); status = Failed; } - else if (status == HbAPending) - { - hostName = strdup(hostent->h_name); - status = HbASucceeded; - logDebugMessage(2,"Player [%d] resolved to %s\n", index, hostName.c_str()); - } else if (status == HbNPending) { - memcpy(&hostAddress, hostent->h_addr_list[0], sizeof(hostAddress)); + memcpy(&hostAddr, result->nodes->ai_addr, result->nodes->ai_addrlen); + ares_freeaddrinfo(result); status = HbNSucceeded; } } @@ -153,14 +179,20 @@ const char *AresHandler::getHostname() return hostName.c_str(); } -AresHandler::ResolutionStatus AresHandler::getHostAddress(struct in_addr - *clientAddr) +AresHandler::ResolutionStatus AresHandler::getHostAddress(in_addr *clientAddr) { if (status == HbNSucceeded) memcpy(clientAddr, &hostAddress, sizeof(hostAddress)); return status; } +AresHandler::ResolutionStatus AresHandler::getHostAddr(sockaddr_in6 *_hostAddr) +{ + if (status == HbNSucceeded) + memcpy(_hostAddr, &hostAddr, sizeof(hostAddr)); + return status; +} + void AresHandler::setFd(fd_set *read_set, fd_set *write_set, int &maxFile) { if (aresFailed) diff --git a/src/net/Ping.cxx b/src/net/Ping.cxx index f5567c2829..e5d3d7eaa2 100644 --- a/src/net/Ping.cxx +++ b/src/net/Ping.cxx @@ -31,7 +31,7 @@ // PingPacket // -const int PingPacket::PacketSize = ServerIdPLen + 52; +const int PingPacket::PacketSize = 52; PingPacket::PingPacket() : gameOptions(0), gameType(TeamFFA), maxShots(1), @@ -62,7 +62,7 @@ PingPacket::~PingPacket() // do nothing } -bool PingPacket::read(int fd, struct sockaddr_in* addr) +bool PingPacket::read(int fd, struct sockaddr_in6* addr) { char buffer[PacketSize], serverVersion[9]; uint16_t len, code; @@ -93,7 +93,7 @@ bool PingPacket::read(int fd, struct sockaddr_in* addr) } bool PingPacket::write(int fd, - const struct sockaddr_in* addr) const + const struct sockaddr_in6* addr) const { char buffer[PacketSize] = {0}; void* buf = buffer; @@ -104,7 +104,7 @@ bool PingPacket::write(int fd, } bool PingPacket::isRequest(int fd, - struct sockaddr_in* addr) + struct sockaddr_in6* addr) { if (fd < 0) return false; char buffer[6]; @@ -118,7 +118,7 @@ bool PingPacket::isRequest(int fd, } bool PingPacket::sendRequest(int fd, - const struct sockaddr_in* addr) + const struct sockaddr_in6* addr) { if (fd < 0 || !addr) return false; char buffer[6]; @@ -132,8 +132,6 @@ bool PingPacket::sendRequest(int fd, const void* PingPacket::unpack(const void* buf, char* version) { buf = nboUnpackString(buf, version, 8); - buf = serverId.unpack(buf); - buf = sourceAddr.unpack(buf); buf = nboUnpackUShort(buf, gameType); buf = nboUnpackUShort(buf, gameOptions); buf = nboUnpackUShort(buf, maxShots); @@ -161,8 +159,6 @@ const void* PingPacket::unpack(const void* buf, char* version) void* PingPacket::pack(void* buf, const char* version) const { buf = nboPackString(buf, version, 8); - buf = serverId.pack(buf); - buf = sourceAddr.pack(buf); buf = nboPackUShort(buf, gameType); buf = nboPackUShort(buf, gameOptions); buf = nboPackUShort(buf, maxShots); diff --git a/src/net/multicast.cxx b/src/net/multicast.cxx index f1749ff8f2..5f7e3852cd 100644 --- a/src/net/multicast.cxx +++ b/src/net/multicast.cxx @@ -29,9 +29,8 @@ /* common implementation headers */ #include "ErrorHandler.h" - int openBroadcast(int port, const char* service, - struct sockaddr_in* addr) + struct sockaddr_in6* addr) { #if defined(_WIN32) const BOOL optOn = TRUE; @@ -46,7 +45,6 @@ int openBroadcast(int port, const char* service, printError("openBroadcast: Must supply a return address structure!"); return -1; } - memset(addr, 0, sizeof(*addr)); /* lookup service and check port */ if (service) @@ -76,18 +74,19 @@ int openBroadcast(int port, const char* service, return -1; } + /* set address info */ + // FIXME: if we get IPv6, try fc00::/8 + memset(addr, 0, sizeof(*addr)); + addr->sin6_family = AF_INET; + /* open socket */ - fd = socket(AF_INET, SOCK_DGRAM, 0); + fd = socket(addr->sin6_family, SOCK_DGRAM, 0); if (fd < 0) { nerror("openBroadcast: socket"); return -1; } - /* set address info */ - addr->sin_family = AF_INET; - addr->sin_addr.s_addr = htonl(INADDR_ANY); - #if defined(SO_REUSEPORT) /* set reuse port */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, @@ -116,6 +115,13 @@ int openBroadcast(int port, const char* service, return -1; } + sockaddr_in6 bcastaddr; + socklen_t bcastaddrlen = sizeof(bcastaddr); + if (getsockname(fd, (sockaddr *)&bcastaddr, &bcastaddrlen)) + nerror("openBroadcast getsockname"); + ; + logDebugMessage(5, "BCast bind: %s\n", sockaddr2iptextport((sockaddr *)&bcastaddr)); + /* make broadcast */ if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, (SSOType)&optOn, sizeof(optOn)) < 0) @@ -126,8 +132,8 @@ int openBroadcast(int port, const char* service, } // address to send to is the broadcast address - addr->sin_addr.s_addr = INADDR_BROADCAST; - addr->sin_port = htons(port); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)addr)->sin_port = htons(port); #if defined(__linux__) // linux doesn't seem to like INADDR_BROADCAST, but it's okay @@ -166,13 +172,14 @@ int openBroadcast(int port, const char* service, // if the address is the loopback broadcast address then skip it const sockaddr_in* ifbaddr = (const sockaddr_in*) &req[i].ifr_ifru.ifru_broadaddr; + // FIXME: handle IPv6 if (ntohl(ifbaddr->sin_addr.s_addr) == 0x7ffffffflu) continue; if (ifbaddr->sin_addr.s_addr == 0) continue; // got the broadcast address on the interface - addr->sin_addr.s_addr = ifbaddr->sin_addr.s_addr; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = ifbaddr->sin_addr.s_addr; break; } @@ -204,8 +211,9 @@ int closeBroadcast(int fd) int sendBroadcast(int fd, const void* buffer, int bufferLength, - const struct sockaddr_in* addr) + const struct sockaddr_in6* addr) { + logDebugMessage(5, "BCast to: %s\n", sockaddr2iptextport((const struct sockaddr*)addr)); return sendto(fd, (const char*)buffer, bufferLength, 0, (const struct sockaddr*)addr, sizeof(*addr)); } @@ -228,13 +236,14 @@ int sendBroadcast(int fd, const void* buffer, #endif //WIN32 int recvBroadcast(int fd, void* buffer, int bufferLength, - struct sockaddr_in* addr) + struct sockaddr_in6* addr) { - struct sockaddr_in from; + struct sockaddr_in6 from; AddrLen fromLength = sizeof(from); int byteCount = recvfrom(fd, (char*)buffer, bufferLength, 0, (struct sockaddr*)&from, (socklen_t*) &fromLength); + logDebugMessage(5, "BCast from: %s\n", sockaddr2iptextport((const struct sockaddr*)&from)); if (byteCount < 0) { if (getErrno() == EWOULDBLOCK) diff --git a/src/obstacle/MeshObstacle.cxx b/src/obstacle/MeshObstacle.cxx index a585608150..57aa0acea4 100644 --- a/src/obstacle/MeshObstacle.cxx +++ b/src/obstacle/MeshObstacle.cxx @@ -696,7 +696,7 @@ void *MeshObstacle::pack(void *buf) const buf = nboPackInt(buf, 0); // for alignment to afvec2 logDebugMessage(4,"DrawInfo packing: length = %i, missing = %i\n", length, missing); - logDebugMessage(4," texcoordCount = %i, fakeTxcdCount = %i, rewindLen = %i\n", + logDebugMessage(4,"\ttexcoordCount = %i, fakeTxcdCount = %i, rewindLen = %i\n", texcoordCount, fakeTxcdCount, fullLength + (int)sizeof(afvec2)); } diff --git a/src/scene/Octree.cxx b/src/scene/Octree.cxx index 5bb99997f8..9b70c547e7 100644 --- a/src/scene/Octree.cxx +++ b/src/scene/Octree.cxx @@ -161,14 +161,14 @@ void Octree::addNodes(SceneNode** list, int listSize, int depth, int elements) logDebugMessage(2, "Octree scene nodes = %i\n", listSize); for (i = 0; i < 3; i++) - logDebugMessage(2, " grid extent[%i] = %f, %f\n", i, extents.mins[i], extents.maxs[i]); + logDebugMessage(2, "\tgrid extent[%i] = %f, %f\n", i, extents.mins[i], extents.maxs[i]); for (i = 0; i < 3; i++) - logDebugMessage(2, " visual extent[%i] = %f, %f\n", i, visualExtents.mins[i], visualExtents.maxs[i]); + logDebugMessage(2, "\tvisual extent[%i] = %f, %f\n", i, visualExtents.mins[i], visualExtents.maxs[i]); - logDebugMessage(2, "Octree leaf nodes = %i\n", leafNodes); - logDebugMessage(2, "Octree total nodes = %i\n", totalNodes); - logDebugMessage(2, "Octree total elements = %i\n", totalElements); + logDebugMessage(2, "\tleaf nodes = %i\n", leafNodes); + logDebugMessage(2, "\ttotal nodes = %i\n", totalNodes); + logDebugMessage(2, "\ttotal elements = %i\n", totalElements); return; }