Proper handling of failing to bind server socket
authorPerttu Ahola <celeron55@gmail.com>
Sun, 11 Mar 2012 18:45:43 +0000 (20:45 +0200)
committerPerttu Ahola <celeron55@gmail.com>
Sun, 11 Mar 2012 18:45:43 +0000 (20:45 +0200)
src/connection.cpp
src/connection.h
src/server.cpp
src/server.h

index 60c99dc73763b9aa3c5544f38b8a68194b940e91..58a0fb2bd9c3ef377f119dcea5982afbc9cd30b1 100644 (file)
@@ -986,8 +986,16 @@ nextpeer:
 void Connection::serve(u16 port)
 {
        dout_con<<getDesc()<<" serving at port "<<port<<std::endl;
-       m_socket.Bind(port);
-       m_peer_id = PEER_ID_SERVER;
+       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");
index 6d26e2e35e8cc632450fe478468b0b851f2156df..b793f580f90d4c73687d6b720c4a183f68b6e5b7 100644 (file)
@@ -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{
index 767de035f38905e54ac4c5ee801d5d150e7ee588..63bf794ab4ee191f15df762bcf380e470f556840 100644 (file)
@@ -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()
index 4948b8ba1de4540b2e8ecafa77a0ca1edfdcfdba..0b4c67deb10a0008cb3fb1a10ff8529760039232 100644 (file)
@@ -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;