Proper handling of failing to bind server socket

This commit is contained in:
Perttu Ahola 2012-03-11 20:45:43 +02:00
parent d1d83d7e7f
commit 618314985d
4 changed files with 51 additions and 2 deletions

@ -986,8 +986,16 @@ nextpeer:
void Connection::serve(u16 port) void Connection::serve(u16 port)
{ {
dout_con<<getDesc()<<" serving at port "<<port<<std::endl; dout_con<<getDesc()<<" serving at port "<<port<<std::endl;
m_socket.Bind(port); try{
m_peer_id = PEER_ID_SERVER; m_socket.Bind(port);
m_peer_id = PEER_ID_SERVER;
}
catch(SocketException &e){
// Create event
ConnectionEvent e;
e.bindFailed();
putEvent(e);
}
} }
void Connection::connect(Address address) void Connection::connect(Address address)
@ -1597,6 +1605,9 @@ u32 Connection::Receive(u16 &peer_id, SharedBuffer<u8> &data)
if(m_bc_peerhandler) if(m_bc_peerhandler)
m_bc_peerhandler->deletingPeer(&tmp, e.timeout); m_bc_peerhandler->deletingPeer(&tmp, e.timeout);
continue; } continue; }
case CONNEVENT_BIND_FAILED:
throw ConnectionBindFailed("Failed to bind socket "
"(port already in use?)");
} }
} }
throw NoIncomingDataException("No incoming data"); throw NoIncomingDataException("No incoming data");

@ -59,6 +59,14 @@ public:
{} {}
}; };
class ConnectionBindFailed : public BaseException
{
public:
ConnectionBindFailed(const char *s):
BaseException(s)
{}
};
/*class ThrottlingException : public BaseException /*class ThrottlingException : public BaseException
{ {
public: public:
@ -424,6 +432,7 @@ enum ConnectionEventType{
CONNEVENT_DATA_RECEIVED, CONNEVENT_DATA_RECEIVED,
CONNEVENT_PEER_ADDED, CONNEVENT_PEER_ADDED,
CONNEVENT_PEER_REMOVED, CONNEVENT_PEER_REMOVED,
CONNEVENT_BIND_FAILED,
}; };
struct ConnectionEvent struct ConnectionEvent
@ -447,6 +456,8 @@ struct ConnectionEvent
return "CONNEVENT_PEER_ADDED"; return "CONNEVENT_PEER_ADDED";
case CONNEVENT_PEER_REMOVED: case CONNEVENT_PEER_REMOVED:
return "CONNEVENT_PEER_REMOVED"; return "CONNEVENT_PEER_REMOVED";
case CONNEVENT_BIND_FAILED:
return "CONNEVENT_BIND_FAILED";
} }
return "Invalid ConnectionEvent"; return "Invalid ConnectionEvent";
} }
@ -470,6 +481,10 @@ struct ConnectionEvent
timeout = timeout_; timeout = timeout_;
address = address_; address = address_;
} }
void bindFailed()
{
type = CONNEVENT_BIND_FAILED;
}
}; };
enum ConnectionCommandType{ enum ConnectionCommandType{

@ -109,6 +109,10 @@ void * ServerThread::Thread()
{ {
infostream<<"Server: PeerNotFoundException"<<std::endl; infostream<<"Server: PeerNotFoundException"<<std::endl;
} }
catch(con::ConnectionBindFailed &e)
{
m_server->setAsyncFatalError(e.what());
}
} }
END_DEBUG_EXCEPTION_HANDLER(errorstream) END_DEBUG_EXCEPTION_HANDLER(errorstream)
@ -837,6 +841,7 @@ Server::Server(
m_path_world(path_world), m_path_world(path_world),
m_path_config(path_config), m_path_config(path_config),
m_gamespec(gamespec), m_gamespec(gamespec),
m_async_fatal_error(""),
m_env(NULL), m_env(NULL),
m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this), m_con(PROTOCOL_ID, 512, CONNECTION_TIMEOUT, this),
m_authmanager(path_world+DIR_DELIM+"auth.txt"), m_authmanager(path_world+DIR_DELIM+"auth.txt"),
@ -865,6 +870,9 @@ Server::Server(
m_step_dtime_mutex.Init(); m_step_dtime_mutex.Init();
m_step_dtime = 0.0; m_step_dtime = 0.0;
if(path_world == "")
throw ServerError("Supplied empty world path");
if(!gamespec.isValid()) if(!gamespec.isValid())
throw ServerError("Supplied invalid gamespec"); throw ServerError("Supplied invalid gamespec");
@ -1079,6 +1087,8 @@ Server::~Server()
void Server::start(unsigned short port) void Server::start(unsigned short port)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
infostream<<"Starting server on port "<<port<<"..."<<std::endl;
// Stop thread if already running // Stop thread if already running
m_thread.stop(); m_thread.stop();
@ -1128,6 +1138,11 @@ void Server::step(float dtime)
JMutexAutoLock lock(m_step_dtime_mutex); JMutexAutoLock lock(m_step_dtime_mutex);
m_step_dtime += dtime; m_step_dtime += dtime;
} }
// Throw if fatal error occurred in thread
std::string async_err = m_async_fatal_error.get();
if(async_err != ""){
throw ServerError(async_err);
}
} }
void Server::AsyncRunStep() void Server::AsyncRunStep()

@ -545,6 +545,11 @@ public:
std::string getWorldPath(){ return m_path_world; } std::string getWorldPath(){ return m_path_world; }
void setAsyncFatalError(const std::string &error)
{
m_async_fatal_error.set(error);
}
private: private:
// con::PeerHandler implementation. // con::PeerHandler implementation.
@ -658,6 +663,9 @@ private:
// Equivalent of /usr/share/minetest/server // Equivalent of /usr/share/minetest/server
std::string m_path_share; std::string m_path_share;
// Thread can set; step() will throw as ServerError
MutexedVariable<std::string> m_async_fatal_error;
// Some timers // Some timers
float m_liquid_transform_timer; float m_liquid_transform_timer;
float m_print_info_timer; float m_print_info_timer;