Add the option to bind to a specific address

This commit is contained in:
ShadowNinja 2014-02-05 21:24:46 +01:00 committed by sapier
parent 7f743178db
commit 85fe75d1cb
12 changed files with 118 additions and 40 deletions

@ -626,6 +626,9 @@ function tabbuilder.handle_server_buttons(fields)
gamedata.selected_world = filterlist.get_raw_index(worldlist,selected) gamedata.selected_world = filterlist.get_raw_index(worldlist,selected)
engine.setting_set("port",gamedata.port) 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) menu.update_last_game(gamedata.selected_world)
engine.start() engine.start()
@ -950,11 +953,24 @@ function tabbuilder.tab_server()
dump(engine.setting_getbool("enable_damage")) .. "]".. dump(engine.setting_getbool("enable_damage")) .. "]"..
"checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" .. "checkbox[0.5,1.15;cb_server_announce;".. fgettext("Public") .. ";" ..
dump(engine.setting_getbool("server_announce")) .. "]".. 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") .. "]" .. engine.setting_get("name") .. "]" ..
"pwdfield[0.8,4.2;3,0.5;te_passwd;".. fgettext("Password") .. "]" .. "pwdfield[0.8,4.2;3.5,0.5;te_passwd;".. fgettext("Password") .. "]"
"field[0.8,5.2;3,0.5;te_serverport;".. fgettext("Server Port") .. ";" ..
engine.setting_get("port") .."]" .. 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;" .. "textlist[4,0.25;7.5,3.7;srv_worlds;" ..
menu.render_world_list() .. menu.render_world_list() ..
";" .. index .. "]" ";" .. index .. "]"

@ -231,7 +231,9 @@
# Server stuff # Server stuff
# #
# Network port to listen (UDP) # Network port to listen (UDP)
#port = #port = 30000
# Bind address
#bind_address =
# Name of server # Name of server
#server_name = Minetest server #server_name = Minetest server
# Description of server # Description of server

@ -1597,8 +1597,8 @@ void ConnectionSendThread::processNonReliableCommand(ConnectionCommand &c)
return; return;
case CONNCMD_SERVE: case CONNCMD_SERVE:
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SERVE port=" LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_SERVE port="
<<c.port<<std::endl); <<c.address.serializeString()<<std::endl);
serve(c.port); serve(c.address);
return; return;
case CONNCMD_CONNECT: case CONNCMD_CONNECT:
LOG(dout_con<<m_connection->getDesc()<<" UDP processing CONNCMD_CONNECT"<<std::endl); 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{ try{
m_connection->m_udpSocket.Bind(port); m_connection->m_udpSocket.Bind(bind_address);
m_connection->SetPeerID(PEER_ID_SERVER); m_connection->SetPeerID(PEER_ID_SERVER);
} }
catch(SocketException &e){ catch(SocketException &e){
@ -1658,7 +1659,14 @@ void ConnectionSendThread::connect(Address address)
e.peerAdded(peer->id, peer->address); e.peerAdded(peer->id, peer->address);
m_connection->putEvent(e); 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 // Send a dummy packet to server with peer_id = PEER_ID_INEXISTENT
m_connection->SetPeerID(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); assert(channelnum < CHANNEL_COUNT);
PeerHelper peer = m_connection->getPeerNoEx(peer_id); PeerHelper peer = m_connection->getPeerNoEx(peer_id);
if(!peer) { if(!peer)
{
LOG(dout_con<<m_connection->getDesc()<<" peer: peer_id="<<peer_id LOG(dout_con<<m_connection->getDesc()<<" peer: peer_id="<<peer_id
<< ">>>NOT<<< found on sending packet" << ">>>NOT<<< found on sending packet"
<< ", channel " << (channelnum % 0xFF) << ", 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; ConnectionCommand c;
c.serve(port); c.serve(bind_addr);
putCommand(c); putCommand(c);
} }

@ -406,7 +406,6 @@ enum ConnectionCommandType{
struct ConnectionCommand struct ConnectionCommand
{ {
enum ConnectionCommandType type; enum ConnectionCommandType type;
u16 port;
Address address; Address address;
u16 peer_id; u16 peer_id;
u8 channelnum; u8 channelnum;
@ -416,10 +415,10 @@ struct ConnectionCommand
ConnectionCommand(): type(CONNCMD_NONE), peer_id(PEER_ID_INEXISTENT), reliable(false), raw(false) {} ConnectionCommand(): type(CONNCMD_NONE), peer_id(PEER_ID_INEXISTENT), reliable(false), raw(false) {}
void serve(u16 port_) void serve(Address address_)
{ {
type = CONNCMD_SERVE; type = CONNCMD_SERVE;
port = port_; address = address_;
} }
void connect(Address address_) void connect(Address address_)
{ {
@ -912,7 +911,7 @@ private:
void processReliableCommand (ConnectionCommand &c); void processReliableCommand (ConnectionCommand &c);
void processNonReliableCommand (ConnectionCommand &c); void processNonReliableCommand (ConnectionCommand &c);
void serve (u16 port); void serve (Address bind_address);
void connect (Address address); void connect (Address address);
void disconnect (); void disconnect ();
void disconnect_peer(u16 peer_id); void disconnect_peer(u16 peer_id);
@ -996,7 +995,7 @@ public:
void putCommand(ConnectionCommand &c); void putCommand(ConnectionCommand &c);
void SetTimeoutMs(int timeout){ m_bc_receive_timeout = timeout; } void SetTimeoutMs(int timeout){ m_bc_receive_timeout = timeout; }
void Serve(unsigned short port); void Serve(Address bind_addr);
void Connect(Address address); void Connect(Address address);
bool Connected(); bool Connected();
void Disconnect(); void Disconnect();

@ -175,6 +175,7 @@ void set_default_settings(Settings *settings)
settings->setDefault("workaround_window_size","5"); settings->setDefault("workaround_window_size","5");
settings->setDefault("max_packets_per_iteration","1024"); settings->setDefault("max_packets_per_iteration","1024");
settings->setDefault("port", "30000"); settings->setDefault("port", "30000");
settings->setDefault("bind_address","");
settings->setDefault("default_game", "minetest"); settings->setDefault("default_game", "minetest");
settings->setDefault("motd", ""); settings->setDefault("motd", "");
settings->setDefault("max_users", "15"); settings->setDefault("max_users", "15");

@ -909,8 +909,8 @@ bool nodePlacementPrediction(Client &client,
// Dont place node when player would be inside new node // Dont place node when player would be inside new node
// NOTE: This is to be eventually implemented by a mod as client-side Lua // NOTE: This is to be eventually implemented by a mod as client-side Lua
if (!nodedef->get(n).walkable || if (!nodedef->get(n).walkable ||
(client.checkPrivilege("noclip") && g_settings->getBool("noclip")) || (client.checkPrivilege("noclip") && g_settings->getBool("noclip")) ||
(nodedef->get(n).walkable && (nodedef->get(n).walkable &&
neighbourpos != player->getStandingNodePos() + v3s16(0,1,0) && neighbourpos != player->getStandingNodePos() + v3s16(0,1,0) &&
neighbourpos != player->getStandingNodePos() + v3s16(0,2,0))) { neighbourpos != player->getStandingNodePos() + v3s16(0,2,0))) {
@ -1029,7 +1029,27 @@ void the_game(
infostream<<"Creating server"<<std::endl; infostream<<"Creating server"<<std::endl;
server = new Server(map_dir, gamespec, server = new Server(map_dir, gamespec,
simple_singleplayer_mode); 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)) do{ // Client scope (breakable do-while(0))

@ -1024,6 +1024,21 @@ int main(int argc, char *argv[])
if(port == 0) if(port == 0)
port = 30000; 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 // World directory
std::string commanded_world = ""; std::string commanded_world = "";
if(cmd_args.exists("world")) if(cmd_args.exists("world"))
@ -1270,7 +1285,7 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
server.start(port); server.start(bind_addr);
// Run server // Run server
dedicated_server_loop(server, kill); dedicated_server_loop(server, kill);

@ -452,17 +452,18 @@ Server::~Server()
} }
} }
void Server::start(unsigned short port) void Server::start(Address bind_addr)
{ {
DSTACK(__FUNCTION_NAME); 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 // Stop thread if already running
m_thread->Stop(); m_thread->Stop();
// Initialize connection // Initialize connection
m_con.SetTimeoutMs(30); m_con.SetTimeoutMs(30);
m_con.Serve(port); m_con.Serve(bind_addr);
// Start thread // Start thread
m_thread->Start(); m_thread->Start();
@ -477,7 +478,8 @@ void Server::start(unsigned short port)
<<" \\/ \\/ \\/ \\/ \\/ "<<std::endl; <<" \\/ \\/ \\/ \\/ \\/ "<<std::endl;
actionstream<<"World at ["<<m_path_world<<"]"<<std::endl; actionstream<<"World at ["<<m_path_world<<"]"<<std::endl;
actionstream<<"Server for gameid=\""<<m_gamespec.id 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() void Server::stop()

@ -177,7 +177,7 @@ public:
bool simple_singleplayer_mode bool simple_singleplayer_mode
); );
~Server(); ~Server();
void start(unsigned short port); void start(Address bind_addr);
void stop(); void stop();
// This is mainly a way to pass the time to the server. // This is mainly a way to pass the time to the server.
// Actual processing is done in an another thread. // Actual processing is done in an another thread.

@ -92,24 +92,27 @@ void sockets_cleanup()
Address::Address() Address::Address()
{ {
m_addr_family = 0; m_addr_family = 0;
memset(&m_address, 0, sizeof m_address); memset(&m_address, 0, sizeof(m_address));
m_port = 0; m_port = 0;
} }
Address::Address(u32 address, u16 port) Address::Address(u32 address, u16 port)
{ {
memset(&m_address, 0, sizeof(m_address));
setAddress(address); setAddress(address);
setPort(port); setPort(port);
} }
Address::Address(u8 a, u8 b, u8 c, u8 d, u16 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); setAddress(a, b, c, d);
setPort(port); setPort(port);
} }
Address::Address(const IPv6AddressBytes * ipv6_bytes, u16 port) Address::Address(const IPv6AddressBytes * ipv6_bytes, u16 port)
{ {
memset(&m_address, 0, sizeof(m_address));
setAddress(ipv6_bytes); setAddress(ipv6_bytes);
setPort(port); setPort(port);
} }
@ -334,12 +337,20 @@ UDPSocket::~UDPSocket()
#endif #endif
} }
void UDPSocket::Bind(u16 port) void UDPSocket::Bind(Address addr)
{ {
if(socket_enable_debug_output) if(socket_enable_debug_output)
{ {
dstream << "UDPSocket(" << (int) m_handle << ")::Bind(): " 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) if(m_addr_family == AF_INET6)
@ -347,12 +358,12 @@ void UDPSocket::Bind(u16 port)
struct sockaddr_in6 address; struct sockaddr_in6 address;
memset(&address, 0, sizeof(address)); memset(&address, 0, sizeof(address));
address = addr.getAddress6();
address.sin6_family = AF_INET6; address.sin6_family = AF_INET6;
address.sin6_addr = in6addr_any; address.sin6_port = htons(addr.getPort());
address.sin6_port = htons(port);
if(bind(m_handle, (const struct sockaddr *) &address, if(bind(m_handle, (const struct sockaddr *) &address,
sizeof(struct sockaddr_in6)) < 0) sizeof(struct sockaddr_in6)) < 0)
{ {
dstream << (int) m_handle << ": Bind failed: " dstream << (int) m_handle << ": Bind failed: "
<< strerror(errno) << std::endl; << strerror(errno) << std::endl;
@ -364,9 +375,9 @@ void UDPSocket::Bind(u16 port)
struct sockaddr_in address; struct sockaddr_in address;
memset(&address, 0, sizeof(address)); memset(&address, 0, sizeof(address));
address = addr.getAddress();
address.sin_family = AF_INET; address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(addr.getPort());
address.sin_port = htons(port);
if(bind(m_handle, (const struct sockaddr *) &address, if(bind(m_handle, (const struct sockaddr *) &address,
sizeof(struct sockaddr_in)) < 0) sizeof(struct sockaddr_in)) < 0)

@ -115,7 +115,7 @@ class UDPSocket
public: public:
UDPSocket(bool ipv6); UDPSocket(bool ipv6);
~UDPSocket(); ~UDPSocket();
void Bind(unsigned short port); void Bind(Address addr);
//void Close(); //void Close();
//bool IsOpen(); //bool IsOpen();
void Send(const Address & destination, const void * data, int size); void Send(const Address & destination, const void * data, int size);

@ -1506,11 +1506,13 @@ struct TestSocket: public TestBase
void Run() void Run()
{ {
const int port = 30003; const int port = 30003;
Address address(0,0,0,0, port);
Address address6((IPv6AddressBytes*) NULL, port);
// IPv6 socket test // IPv6 socket test
{ {
UDPSocket socket6(true); UDPSocket socket6(true);
socket6.Bind(port); socket6.Bind(address6);
const char sendbuffer[] = "hello world!"; const char sendbuffer[] = "hello world!";
IPv6AddressBytes bytes; IPv6AddressBytes bytes;
@ -1536,7 +1538,7 @@ struct TestSocket: public TestBase
// IPv4 socket test // IPv4 socket test
{ {
UDPSocket socket(false); UDPSocket socket(false);
socket.Bind(port); socket.Bind(address);
const char sendbuffer[] = "hello world!"; const char sendbuffer[] = "hello world!";
socket.Send(Address(127,0,0,1,port), sendbuffer, sizeof(sendbuffer)); 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; infostream<<"** Creating server Connection"<<std::endl;
con::Connection server(proto_id, 512, 5.0, false, &hand_server); 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; infostream<<"** Creating client Connection"<<std::endl;
con::Connection client(proto_id, 512, 5.0, false, &hand_client); con::Connection client(proto_id, 512, 5.0, false, &hand_client);