void server:: 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(); async_start_thread.reset(new thread_function(make_mfp(*this,&server::start_async_helper))); }
int rst_sockets(struct cpt_context *ctx) { int err; loff_t sec = ctx->sections[CPT_SECT_SOCKET]; loff_t endsec; cpt_object_t *obj; struct cpt_section_hdr h; if (sec == CPT_NULL) return 0; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) { eprintk_ctx("rst_sockets: ctx->pread: %d\n", err); return err; } if (h.cpt_section != CPT_SECT_SOCKET || h.cpt_hdrlen < sizeof(h)) { eprintk_ctx("rst_sockets: hdr err\n"); return -EINVAL; } /* The first pass: we create socket index and open listening sockets. */ endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { struct cpt_sock_image *sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, sec, sbuf, ctx); if (err) { eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); cpt_release_buf(ctx); return err; } if (sbuf->cpt_state == TCP_LISTEN) { err = open_listening_socket(sec, sbuf, ctx); cpt_release_buf(ctx); if (err) { eprintk_ctx("rst_sockets: open_listening_socket: %d\n", err); return err; } } else { cpt_release_buf(ctx); obj = alloc_cpt_object(GFP_KERNEL, ctx); if (obj == NULL) return -ENOMEM; cpt_obj_setindex(obj, sbuf->cpt_index, ctx); cpt_obj_setpos(obj, sec, ctx); obj->o_ppos = sbuf->cpt_file; intern_cpt_object(CPT_OBJ_SOCKET, obj, ctx); } sec += sbuf->cpt_next; } /* Pass 2: really restore sockets */ for_each_object(obj, CPT_OBJ_SOCKET) { struct cpt_sock_image *sbuf; if (obj->o_obj != NULL) continue; sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); if (err) { eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); cpt_release_buf(ctx); return err; } if (sbuf->cpt_state == TCP_LISTEN) BUG(); err = open_socket(obj, sbuf, ctx); cpt_release_buf(ctx); if (err) { eprintk_ctx("rst_sockets: open_socket: %d\n", err); return err; } } return 0; }
void server:: start_accepting_connections ( ) { open_listening_socket(); // determine the listening port bool port_assigned = false; listening_port_mutex.lock(); if (listening_port == 0) { port_assigned = true; listening_port = sock->get_listening_port(); } listening_port_mutex.unlock(); if (port_assigned) on_listening_port_assigned(); int status = 0; connection* client; bool exit = false; while ( true ) { // accept the next connection status = sock->accept(client,1000); // if there was an error then quit the loop if (status == OTHER_ERROR) { break; } shutting_down_mutex.lock(); // if we are shutting down then signal that we should quit the loop exit = shutting_down; shutting_down_mutex.unlock(); // if we should be shutting down if (exit) { // if a connection was opened then close it if (status == 0) delete client; break; } // if the accept timed out if (status == TIMEOUT) { continue; } // add this new connection to cons cons_mutex.lock(); connection* client_temp = client; try{cons.add(client_temp);} catch(...) { sock.reset(); delete client; cons_mutex.unlock(); // signal that we are not running start() anymore running_mutex.lock(); running = false; running_signaler.broadcast(); running_mutex.unlock(); clear(); throw; } cons_mutex.unlock(); // make a param structure param* temp = 0; try{ temp = new param ( *this, *client, get_graceful_close_timeout() ); } catch (...) { sock.reset(); delete client; running_mutex.lock(); running = false; running_signaler.broadcast(); running_mutex.unlock(); clear(); throw; } // if create_new_thread failed if (!create_new_thread(service_connection,temp)) { delete temp; // close the listening socket sock.reset(); // close the new connection and remove it from cons cons_mutex.lock(); connection* ctemp; if (cons.is_member(client)) { cons.remove(client,ctemp); } delete client; cons_mutex.unlock(); // signal that the listener has closed running_mutex.lock(); running = false; running_signaler.broadcast(); running_mutex.unlock(); // make sure the object is cleared clear(); // throw the exception throw dlib::thread_error( ECREATE_THREAD, "error occurred in server::start()\nunable to start thread" ); } // if we made the new thread then update thread_count else { // increment the thread count thread_count_mutex.lock(); ++thread_count; if (thread_count == 0) thread_count_zero.broadcast(); thread_count_mutex.unlock(); } // check if we have hit the maximum allowed number of connections max_connections_mutex.lock(); // if max_connections is zero or the loop is ending then skip this if (max_connections != 0) { // wait for thread_count to be less than max_connections thread_count_mutex.lock(); while (thread_count >= max_connections) { max_connections_mutex.unlock(); thread_count_signaler.wait(); max_connections_mutex.lock(); // if we are shutting down the quit the loop shutting_down_mutex.lock(); exit = shutting_down; shutting_down_mutex.unlock(); if (exit) break; } thread_count_mutex.unlock(); } max_connections_mutex.unlock(); if (exit) { break; } } //while ( true ) // close the socket sock.reset(); // signal that the listener has closed running_mutex.lock(); running = false; running_signaler.broadcast(); running_mutex.unlock(); // if there was an error with accept then throw an exception if (status == OTHER_ERROR) { // make sure the object is cleared clear(); // throw the exception throw dlib::socket_error( "error occurred in server::start()\nlistening socket returned error" ); } }