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)
{
dout_con<<getDesc()<<" serving at port "<<port<<std::endl;
try{
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)
@ -1597,6 +1605,9 @@ u32 Connection::Receive(u16 &peer_id, SharedBuffer<u8> &data)
if(m_bc_peerhandler)
m_bc_peerhandler->deletingPeer(&tmp, e.timeout);
continue; }
case CONNEVENT_BIND_FAILED:
throw ConnectionBindFailed("Failed to bind socket "
"(port already in use?)");
}
}
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
{
public:
@ -424,6 +432,7 @@ enum ConnectionEventType{
CONNEVENT_DATA_RECEIVED,
CONNEVENT_PEER_ADDED,
CONNEVENT_PEER_REMOVED,
CONNEVENT_BIND_FAILED,
};
struct ConnectionEvent
@ -447,6 +456,8 @@ struct ConnectionEvent
return "CONNEVENT_PEER_ADDED";
case CONNEVENT_PEER_REMOVED:
return "CONNEVENT_PEER_REMOVED";
case CONNEVENT_BIND_FAILED:
return "CONNEVENT_BIND_FAILED";
}
return "Invalid ConnectionEvent";
}
@ -470,6 +481,10 @@ struct ConnectionEvent
timeout = timeout_;
address = address_;
}
void bindFailed()
{
type = CONNEVENT_BIND_FAILED;
}
};
enum ConnectionCommandType{

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

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