Add the option to bind to a specific address 1131/head
authorShadowNinja <shadowninja@minetest.net>
Wed, 5 Feb 2014 20:24:46 +0000 (21:24 +0100)
committersapier <Sapier at GMX dot net>
Wed, 5 Feb 2014 20:24:46 +0000 (21:24 +0100)
12 files changed:
builtin/mainmenu.lua
minetest.conf.example
src/connection.cpp
src/connection.h
src/defaultsettings.cpp
src/game.cpp
src/main.cpp
src/server.cpp
src/server.h
src/socket.cpp
src/socket.h
src/test.cpp

index 5a5fe3b7f53efd50b33609e39755a1c2d6182e6e..f2649443b321ae8104c949398c06cbf370eb9c2f 100644 (file)
@@ -626,6 +626,9 @@ function tabbuilder.handle_server_buttons(fields)
                        gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
 
                        engine.setting_set("port",gamedata.port)
+                       if fields["te_serveraddr"] ~= nil then
+                               engine.setting_set("bind_address",fields["te_serveraddr"])
+                       end
 
                        menu.update_last_game(gamedata.selected_world)
                        engine.start()
@@ -950,11 +953,24 @@ function tabbuilder.tab_server()
                dump(engine.setting_getbool("enable_damage")) .. "]"..
                "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
                dump(engine.setting_getbool("server_announce")) .. "]"..
-               "field[0.8,3.2;3,0.5;te_playername;".. fgettext("Name") .. ";" ..
+               "field[0.8,3.2;3.5,0.5;te_playername;".. fgettext("Name") .. ";" ..
                engine.setting_get("name") .. "]" ..
-               "pwdfield[0.8,4.2;3,0.5;te_passwd;".. fgettext("Password") .. "]" ..
-               "field[0.8,5.2;3,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
-               engine.setting_get("port") .."]" ..
+               "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
+               
+       local bind_addr = engine.setting_get("bind_address")
+       if bind_addr ~= nil and bind_addr ~= "" then
+               retval = retval ..
+                       "field[0.8,5.2;2.25,0.5;te_serveraddr;".. fgettext("Bind Address") .. ";" ..
+                       engine.setting_get("bind_address") .."]" ..
+                       "field[3.05,5.2;1.25,0.5;te_serverport;".. fgettext("Port") .. ";" ..
+                       engine.setting_get("port") .."]"
+       else
+               retval = retval ..
+                       "field[0.8,5.2;3.5,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
+                       engine.setting_get("port") .."]"
+       end
+       
+       retval = retval ..
                "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
                menu.render_world_list() ..
                ";" .. index .. "]"
index 0234a1dcf3f82acb152452362a38d81fad542583..df70e013fdd94e727ffe817f38b511b9b16c429d 100644 (file)
 # Server stuff
 #
 # Network port to listen (UDP)
-#port =
+#port = 30000
+# Bind address
+#bind_address =
 # Name of server
 #server_name = Minetest server
 # Description of server
index 92f9f8ec263592e2dc3772de97830af271c62d0f..f8c68ed2ec7b59660f1321fc38f3f7735e2d73e7 100644 (file)
@@ -1597,8 +1597,8 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
                return;
        case CONNCMD_SERVE:
                LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SERVE port="
-                               <<c.port<<std::endl);
-               serve(c.port);
+                               <<c.address.serializeString()<<std::endl);
+               serve(c.address);
                return;
        case CONNCMD_CONNECT:
                LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_CONNECT"<<std::endl);
@@ -1631,11 +1631,12 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
        }
 }
 
-void ConnectionSendThread::serve(u16 port)
+void ConnectionSendThread::serve(Address bind_address)
 {
-       LOG(dout_con<<m_connection->getDesc()<<"UDP serving at port "<<port<<std::endl);
+       LOG(dout_con<<m_connection->getDesc()
+                       <<"UDP serving at port " << bind_address.serializeString() <<std::endl);
        try{
-               m_connection->m_udpSocket.Bind(port);
+               m_connection->m_udpSocket.Bind(bind_address);
                m_connection->SetPeerID(PEER_ID_SERVER);
        }
        catch(SocketException &e){
@@ -1658,7 +1659,14 @@ void ConnectionSendThread::connect(Address address)
        e.peerAdded(peer->id, peer->address);
        m_connection->putEvent(e);
 
-       m_connection->m_udpSocket.Bind(0);
+       Address bind_addr;
+
+       if (address.isIPv6())
+               bind_addr.setAddress((IPv6AddressBytes*) NULL);
+       else
+               bind_addr.setAddress(0,0,0,0);
+
+       m_connection->m_udpSocket.Bind(bind_addr);
 
        // Send a dummy packet to server with peer_id = PEER_ID_INEXISTENT
        m_connection->SetPeerID(PEER_ID_INEXISTENT);
@@ -1716,7 +1724,8 @@ void ConnectionSendThread::send(u16 peer_id, u8 channelnum,
        assert(channelnum < CHANNEL_COUNT);
 
        PeerHelper peer = m_connection->getPeerNoEx(peer_id);
-       if(!peer) {
+       if(!peer)
+       {
                LOG(dout_con<<m_connection->getDesc()<<" peer: peer_id="<<peer_id
                                << ">>>NOT<<< found on sending packet"
                                << ", channel " << (channelnum % 0xFF)
@@ -2766,10 +2775,10 @@ void Connection::putCommand(ConnectionCommand &c)
        }
 }
 
-void Connection::Serve(unsigned short port)
+void Connection::Serve(Address bind_addr)
 {
        ConnectionCommand c;
-       c.serve(port);
+       c.serve(bind_addr);
        putCommand(c);
 }
 
index c9474032d1836a1be63b8d144a50f0e774d91e3f..9d646f4991740a7975d66ad569de17f09f7c4667 100644 (file)
@@ -406,7 +406,6 @@ enum ConnectionCommandType{
 struct ConnectionCommand
 {
        enum ConnectionCommandType type;
-       u16 port;
        Address address;
        u16 peer_id;
        u8 channelnum;
@@ -416,10 +415,10 @@ struct ConnectionCommand
 
        ConnectionCommand(): type(CONNCMD_NONE), peer_id(PEER_ID_INEXISTENT), reliable(false), raw(false) {}
 
-       void serve(u16 port_)
+       void serve(Address address_)
        {
                type = CONNCMD_SERVE;
-               port = port_;
+               address = address_;
        }
        void connect(Address address_)
        {
@@ -912,7 +911,7 @@ private:
 
        void processReliableCommand (ConnectionCommand &c);
        void processNonReliableCommand (ConnectionCommand &c);
-       void serve          (u16 port);
+       void serve          (Address bind_address);
        void connect        (Address address);
        void disconnect     ();
        void disconnect_peer(u16 peer_id);
@@ -996,7 +995,7 @@ public:
        void putCommand(ConnectionCommand &c);
        
        void SetTimeoutMs(int timeout){ m_bc_receive_timeout = timeout; }
-       void Serve(unsigned short port);
+       void Serve(Address bind_addr);
        void Connect(Address address);
        bool Connected();
        void Disconnect();
index bac5e0e2d91a1bfddb0723989065d22784f50c1b..9d1aadad90058308c4ff2573d6ab8596fd8d2fa6 100644 (file)
@@ -175,6 +175,7 @@ void set_default_settings(Settings *settings)
        settings->setDefault("workaround_window_size","5");
        settings->setDefault("max_packets_per_iteration","1024");
        settings->setDefault("port", "30000");
+       settings->setDefault("bind_address","");
        settings->setDefault("default_game", "minetest");
        settings->setDefault("motd", "");
        settings->setDefault("max_users", "15");
index 56519d30aa9dbfa40593315c7e028c8fcd239477..b540e3314eb73b7a205dd8d375c0db3da4803d02 100644 (file)
@@ -909,8 +909,8 @@ bool nodePlacementPrediction(Client &client,
 
                        // Dont place node when player would be inside new node
                        // NOTE: This is to be eventually implemented by a mod as client-side Lua
-                       if (!nodedef->get(n).walkable || 
-                               (client.checkPrivilege("noclip") && g_settings->getBool("noclip")) || 
+                       if (!nodedef->get(n).walkable ||
+                               (client.checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
                                (nodedef->get(n).walkable &&
                                neighbourpos != player->getStandingNodePos() + v3s16(0,1,0) &&
                                neighbourpos != player->getStandingNodePos() + v3s16(0,2,0))) {
@@ -1029,7 +1029,27 @@ void the_game(
                infostream<<"Creating server"<<std::endl;
                server = new Server(map_dir, gamespec,
                                simple_singleplayer_mode);
-               server->start(port);
+
+               std::string bind_str = g_settings->get("bind_address");
+               Address bind_addr(0,0,0,0, port);
+
+               if (bind_str != "")
+               {
+                       try {
+                               bind_addr.Resolve(bind_str.c_str());
+                               address = bind_str;
+                       } catch (ResolveError &e) {
+                               infostream << "Resolving bind address \"" << bind_str
+                                                  << "\" failed: " << e.what()
+                                                  << " -- Listening on all addresses." << std::endl;
+
+                               if (g_settings->getBool("ipv6_server")) {
+                                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
+                               }
+                       }
+               }
+
+               server->start(bind_addr);
        }
 
        do{ // Client scope (breakable do-while(0))
index 8186e26c8a70fcc6b7fd548c1d585a7385566356..b5de4b93fb4e4c5cdab40c142424717499a65e15 100644 (file)
@@ -1024,6 +1024,21 @@ int main(int argc, char *argv[])
        if(port == 0)
                port = 30000;
 
+       // Bind address
+       std::string bind_str = g_settings->get("bind_address");
+       Address bind_addr(0,0,0,0, port);
+       try {
+               bind_addr.Resolve(bind_str.c_str());
+       } catch (ResolveError &e) {
+               infostream << "Resolving bind address \"" << bind_str
+                          << "\" failed: " << e.what()
+                          << " -- Listening on all addresses." << std::endl;
+
+               if (g_settings->getBool("ipv6_server")) {
+                       bind_addr.setAddress((IPv6AddressBytes*) NULL);
+               }
+       }
+
        // World directory
        std::string commanded_world = "";
        if(cmd_args.exists("world"))
@@ -1270,7 +1285,7 @@ int main(int argc, char *argv[])
                        return 0;
                }
 
-               server.start(port);
+               server.start(bind_addr);
 
                // Run server
                dedicated_server_loop(server, kill);
index 00db9128d223bd21299224c2a7162caa8e0378ff..151bcada13b0fd70a2cb1dd44018734cec66dcdc 100644 (file)
@@ -452,17 +452,18 @@ Server::~Server()
        }
 }
 
-void Server::start(unsigned short port)
+void Server::start(Address bind_addr)
 {
        DSTACK(__FUNCTION_NAME);
-       infostream<<"Starting server on port "<<port<<"..."<<std::endl;
+       infostream<<"Starting server on "
+                       << bind_addr.serializeString() <<"..."<<std::endl;
 
        // Stop thread if already running
        m_thread->Stop();
 
        // Initialize connection
        m_con.SetTimeoutMs(30);
-       m_con.Serve(port);
+       m_con.Serve(bind_addr);
 
        // Start thread
        m_thread->Start();
@@ -477,7 +478,8 @@ void Server::start(unsigned short port)
        <<"      \\/        \\/     \\/          \\/     \\/        "<<std::endl;
        actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
        actionstream<<"Server for gameid=\""<<m_gamespec.id
-                       <<"\" listening on port "<<port<<"."<<std::endl;
+                       <<"\" listening on "<<bind_addr.serializeString()<<":"
+                       <<bind_addr.getPort() << "."<<std::endl;
 }
 
 void Server::stop()
index 19bedf74a0dc1df2fdbcbc1980af4710efbcb725..54078defc33d8fb9cb81be067ed1911de0e8e93a 100644 (file)
@@ -177,7 +177,7 @@ public:
                bool simple_singleplayer_mode
        );
        ~Server();
-       void start(unsigned short port);
+       void start(Address bind_addr);
        void stop();
        // This is mainly a way to pass the time to the server.
        // Actual processing is done in an another thread.
index 78ff364e50cc427b8cf640a43925731daf3a34e0..00856fb0094133890cf6754ef073d560591ef7a5 100644 (file)
@@ -92,24 +92,27 @@ void sockets_cleanup()
 Address::Address()
 {
        m_addr_family = 0;
-       memset(&m_address, 0, sizeof m_address);
+       memset(&m_address, 0, sizeof(m_address));
        m_port = 0;
 }
 
 Address::Address(u32 address, u16 port)
 {
+       memset(&m_address, 0, sizeof(m_address));
        setAddress(address);
        setPort(port);
 }
 
 Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port)
 {
+       memset(&m_address, 0, sizeof(m_address));
        setAddress(a, b, c, d);
        setPort(port);
 }
 
 Address::Address(const IPv6AddressBytes * ipv6_bytes, u16 port)
 {
+       memset(&m_address, 0, sizeof(m_address));
        setAddress(ipv6_bytes);
        setPort(port);
 }
@@ -334,12 +337,20 @@ UDPSocket::~UDPSocket()
 #endif
 }
 
-void UDPSocket::Bind(u16 port)
+void UDPSocket::Bind(Address addr)
 {
        if(socket_enable_debug_output)
        {
                dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): "
-                       << "port=" << port << std::endl;
+                       << addr.serializeString() << ":"
+                       << addr.getPort() << std::endl;
+       }
+
+       if (addr.getFamily() != m_addr_family)
+       {
+               char errmsg[] = "Socket and bind address families do not match";
+               errorstream << "Bind failed: " << errmsg << std::endl;
+               throw SocketException(errmsg);
        }
 
        if(m_addr_family == AF_INET6)
@@ -347,12 +358,12 @@ void UDPSocket::Bind(u16 port)
                struct sockaddr_in6 address;
                memset(&address, 0, sizeof(address));
 
+               address             = addr.getAddress6();
                address.sin6_family = AF_INET6;
-               address.sin6_addr   = in6addr_any;
-               address.sin6_port   = htons(port);
+               address.sin6_port   = htons(addr.getPort());
 
                if(bind(m_handle, (const struct sockaddr *) &address,
-                       sizeof(struct sockaddr_in6)) < 0)
+                               sizeof(struct sockaddr_in6)) < 0)
                {
                        dstream << (int) m_handle << ": Bind failed: "
                                << strerror(errno) << std::endl;
@@ -364,9 +375,9 @@ void UDPSocket::Bind(u16 port)
                struct sockaddr_in address;
                memset(&address, 0, sizeof(address));
 
+               address                 = addr.getAddress();
                address.sin_family      = AF_INET;
-               address.sin_addr.s_addr = INADDR_ANY;
-               address.sin_port        = htons(port);
+               address.sin_port        = htons(addr.getPort());
 
                if(bind(m_handle, (const struct sockaddr *) &address,
                        sizeof(struct sockaddr_in)) < 0)
index ba88b0142882b643f5f6cac1ddf64828747d2724..7d35a32da0e793a91b0dc70b75e9918bd21a6be0 100644 (file)
@@ -115,7 +115,7 @@ class UDPSocket
 public:
        UDPSocket(bool ipv6);
        ~UDPSocket();
-       void Bind(unsigned short port);
+       void Bind(Address addr);
        //void Close();
        //bool IsOpen();
        void Send(const Address & destination, const void * data, int size);
index c969c0951a76f72e859d7f88d9b723677eb7657a..dd26919473292b11f67c4eeea9f07c3a5384205f 100644 (file)
@@ -1506,11 +1506,13 @@ struct TestSocket: public TestBase
        void Run()
        {
                const int port = 30003;
+               Address address(0,0,0,0, port);
+               Address address6((IPv6AddressBytes*) NULL, port);
 
                // IPv6 socket test
                {
                        UDPSocket socket6(true);
-                       socket6.Bind(port);
+                       socket6.Bind(address6);
 
                        const char sendbuffer[] = "hello world!";
                        IPv6AddressBytes bytes;
@@ -1536,7 +1538,7 @@ struct TestSocket: public TestBase
                // IPv4 socket test
                {
                        UDPSocket socket(false);
-                       socket.Bind(port);
+                       socket.Bind(address);
 
                        const char sendbuffer[] = "hello world!";
                        socket.Send(Address(127,0,0,1,port), sendbuffer, sizeof(sendbuffer));
@@ -1656,7 +1658,8 @@ struct TestConnection: public TestBase
                
                infostream<<"** Creating server Connection"<<std::endl;
                con::Connection server(proto_id, 512, 5.0, false, &hand_server);
-               server.Serve(30001);
+               Address address(0,0,0,0, 30001);
+               server.Serve(address);
                
                infostream<<"** Creating client Connection"<<std::endl;
                con::Connection client(proto_id, 512, 5.0, false, &hand_client);