From 6503f874806637dc61569e8c9c7aa8b23464d297 Mon Sep 17 00:00:00 2001 From: Davis King Date: Fri, 31 Aug 2012 21:47:41 -0400 Subject: [PATCH] Added the start_async() function to the server object. --- dlib/server/server_kernel_1.h | 138 ++++++++++++++++++++------- dlib/server/server_kernel_abstract.h | 27 ++++++ 2 files changed, 130 insertions(+), 35 deletions(-) diff --git a/dlib/server/server_kernel_1.h b/dlib/server/server_kernel_1.h index f13161c8e..bb3304c6c 100644 --- a/dlib/server/server_kernel_1.h +++ b/dlib/server/server_kernel_1.h @@ -11,6 +11,7 @@ #include #include "../algs.h" #include "../logger.h" +#include "../smart_pointers.h" namespace dlib @@ -135,9 +136,17 @@ namespace dlib int get_max_connections ( ) const; + void start_async ( + ); private: + void start_async_helper ( + ); + + void open_listening_socket ( + ); + virtual void on_connect ( connection& new_connection )=0; @@ -169,8 +178,8 @@ namespace dlib set_of_connections cons; mutex listening_port_mutex; mutex listening_ip_mutex; - mutex running_mutex; - signaler running_signaler; + rmutex running_mutex; + rsignaler running_signaler; mutex shutting_down_mutex; mutex cons_mutex; int thread_count; @@ -179,6 +188,8 @@ namespace dlib int max_connections; mutex max_connections_mutex; signaler thread_count_zero; + scoped_ptr async_start_thread; + scoped_ptr sock; // restricted functions @@ -324,47 +335,103 @@ namespace dlib typename set_of_connections > void server_kernel_1:: - start ( + start_async_helper ( ) { - - listener* sock; - int status = create_listener(sock,listening_port,listening_ip); - - // if there was an error then clear this object - if (status < 0) + try { - max_connections_mutex.lock(); - listening_port_mutex.lock(); - listening_ip_mutex.lock(); - listening_ip = ""; - listening_port = 0; - max_connections = 0; - listening_port_mutex.unlock(); - listening_ip_mutex.unlock(); - max_connections_mutex.unlock(); + start(); } - - - - // throw an exception for the error - if (status == PORTINUSE) + catch (std::exception& e) { - throw dlib::socket_error( - EPORT_IN_USE, - "error occurred in server_kernel_1::start()\nport already in use" + sdlog << LERROR << e.what(); + } + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + start_async ( + ) + { + auto_mutex lock(running_mutex); + if (running) + return; + + // Any exceptions likely to be thrown by the server are going to be + // thrown when trying to bind the port. So calling this here rather + // than in the thread we are about to make will cause start_async() + // to report errors back to the user in a very straight forward way. + open_listening_socket(); + + member_function_pointer<>::kernel_1a mfp; + mfp.set(*this,&server_kernel_1::start_async_helper); + async_start_thread.reset(new thread_function(mfp)); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + open_listening_socket ( + ) + { + if (!sock) + { + int status = create_listener(sock,listening_port,listening_ip); + + // if there was an error then clear this object + if (status < 0) + { + max_connections_mutex.lock(); + listening_port_mutex.lock(); + listening_ip_mutex.lock(); + listening_ip = ""; + listening_port = 0; + max_connections = 0; + listening_port_mutex.unlock(); + listening_ip_mutex.unlock(); + max_connections_mutex.unlock(); + } + + + + // throw an exception for the error + if (status == PORTINUSE) + { + throw dlib::socket_error( + EPORT_IN_USE, + "error occurred in server_kernel_1::start()\nport already in use" ); - } - else if (status == OTHER_ERROR) - { - throw dlib::socket_error( - "error occurred in server_kernel_1::start()\nunable to create listener" + } + else if (status == OTHER_ERROR) + { + throw dlib::socket_error( + "error occurred in server_kernel_1::start()\nunable to create listener" ); + } } running_mutex.lock(); running = true; running_mutex.unlock(); + } + +// ---------------------------------------------------------------------------------------- + + template < + typename set_of_connections + > + void server_kernel_1:: + start ( + ) + { + open_listening_socket(); // determine the listening port bool port_assigned = false; @@ -380,6 +447,7 @@ namespace dlib + int status = 0; connection* client; bool exit = false; @@ -430,7 +498,7 @@ namespace dlib try{cons.add(client_temp);} catch(...) { - delete sock; + sock.reset();; delete client; cons_mutex.unlock(); @@ -456,7 +524,7 @@ namespace dlib ); } catch (...) { - delete sock; + sock.reset(); delete client; running_mutex.lock(); running = false; @@ -472,7 +540,7 @@ namespace dlib { delete temp; // close the listening socket - delete sock; + sock.reset(); // close the new connection and remove it from cons cons_mutex.lock(); @@ -546,7 +614,7 @@ namespace dlib // close the socket - delete sock; + sock.reset(); // signal that the listener has closed running_mutex.lock(); diff --git a/dlib/server/server_kernel_abstract.h b/dlib/server/server_kernel_abstract.h index 95d2ef93c..651893819 100644 --- a/dlib/server/server_kernel_abstract.h +++ b/dlib/server/server_kernel_abstract.h @@ -136,6 +136,33 @@ namespace dlib will be unusable until clear() is called and succeeds !*/ + void start_async ( + ); + /*! + ensures + - starts listening on the port and ip specified by get_listening_ip() + and #get_listening_port() for new connections. + - if (get_listening_port() == 0) then + - a port to listen on will be automatically selected + - #get_listening_port() == the selected port being used + - if (get_listening_ip() == "" ) then + - all local IPs will be listened on + - does NOT block. That is, this function will return right away and + the server will run on a background thread until clear() or this + object's destructor is called (or until some kind of fatal error + occurs). + - if an error occurs in the background thread while the server is + running then it will shut itself down, set is_running() to false, and + log the error to a dlib::logger object. + - calling start_async() on a running server has no effect. + throws + - dlib::socket_error + start_async() will throw this exception if there is some problem binding + ports and/or starting the server. + If this happens then + - The server will be cleared and returned to its initial value. + !*/ + bool is_running ( ) const; /*!