/** * Starts the server and transits into daemon mode, if not in debug mode. * Loops forever, accepting stream (TCP) connections. * Child is forked when a client connects. * * @param flag user-provided flags. */ void run_server(struct flags* flag) { int server_sock; /* start listening for clients */ server_sock = setup_server_socket(flag); /* attach signal handlers */ if (signal(SIGCHLD, server_sig_handler) == SIG_ERR) { err(EXIT_FAILURE, "cannot catch SIGCHLD"); } if (signal(SIGHUP, server_sig_handler) == SIG_ERR) { err(EXIT_FAILURE, "cannot catch SIGCHUP"); } /* Start accepting connections */ listen(server_sock, BACKLOG); /* daemonize if not in debug mode */ if (!flag->dflag) { if (daemon(1, 1) < 0) { errx(EXIT_FAILURE, "cannot transit into daemon mode"); } } /* Handle clients */ do { accept_client(flag, server_sock); } while (1); close(server_sock); }
void run(global_config_struct *global_config) { global_resources_struct global_resources; setup_server_socket(global_config, &global_resources); global_resources.bases.transfer_buffer_size = global_config->transfer_buffer_size; setup_events(&global_resources); listen_server_socket(&global_resources); dispatch(&global_resources); close_all(&global_resources); }
//-- main() ///{{{1/////////////////////////////////////////// int main( int argc, char* argv[] ) { int serverPort = kServerPort; fd_set readfds; fd_set writefds; int maxFd, activity, sd; std::vector<ConnectionData> connections; // Did the user specify a port? if( 2 == argc ) { serverPort = atoi(argv[1]); } # if VERBOSE printf( "Attempting to bind to port %d\n", serverPort ); # endif // Set up listening socket - see setup_server_socket() for details. int listenfd = setup_server_socket( serverPort ); if( -1 == listenfd ) return 1; // loop forever while( 1 ) { FD_ZERO(&readfds); // Clear the read socket set FD_ZERO(&writefds); // Clear the read socket set FD_SET(listenfd, &readfds); // Add the listen socket to the read set maxFd = listenfd; // Initially add the listen socket as the maximum file descriptor // Add the client descriptors to the set. for(size_t i = 0; i < connections.size(); i++){ sd = connections[i].sock; if(sd > 0){ if(connections[i].state == eConnStateReceiving) //Add connections to the corresponding sets FD_SET(sd, &readfds); else if(connections[i].state == eConnStateSending) FD_SET(sd, &writefds); } if(sd > maxFd){ // Change maxFd if the file descriptor of the client is larger than the current maxium maxFd = sd; } } activity = select(maxFd + 1, &readfds, &writefds, NULL, NULL); // Perform select to find pending reads and writes if((activity < 0) && (errno != EINTR)){ // Check so that no errors occured. printf("select error \n"); // Should we have "else" } if(FD_ISSET(listenfd, &readfds)){ // If there is activity on the listening socket // Accept connection and add it to the list. if(acceptConnection(&connections, listenfd) == -1) continue; continue; } // Loop through all connections and check if they members of a set for(size_t i=0; i<connections.size(); i++){ sd = connections[i].sock; //Copy the socket descriptor bool processFurther = true; if(FD_ISSET(sd, &readfds)){ while( processFurther && connections[i].state == eConnStateReceiving ) processFurther = process_client_recv( connections[i] ); } else if(FD_ISSET(sd, &writefds)){ while( processFurther && connections[i].state == eConnStateSending ) processFurther = process_client_send( connections[i] ); } if(!processFurther){ // Close the socket if processing is finished close(connections[i].sock); connections[i].sock = -1; } } //Erase all invalid connections connections.erase(std::remove_if(connections.begin(), connections.end(), &is_invalid_connection),connections.end()); } // The program will never reach this part, but for demonstration purposes, // we'll clean up the server resources here and then exit nicely. close( listenfd ); return 0; }
// Construct a server socket. // @bind_addr A numeric IP address to be bound, or `NULL`. // @port TCP port number to be bound. // @on_accept Callback function. // @freebind true to turn on IP_FREEBIND socket option. // // This creates a socket and bind it to the given address and port. // If `bind_addr` is `NULL`, the socket will listen on any address. // Both IPv4 and IPv6 addresses are supported. // // For each new connection, `on_accept` is called to determine // if the new connection need to be closed immediately or // to be added to the reactor. If `on_accept` returns an empty // <std::unique_ptr>, the new connection is closed immediately. // Otherwise, the new connection is added to the reactor. tcp_server_socket(const char* bind_addr, std::uint16_t port, wrapper on_accept, bool freebind): resource( setup_server_socket(bind_addr, port, freebind) ), m_wrapper(on_accept) {}
//-- main() ///{{{1/////////////////////////////////////////// int main( int argc, char* argv[] ) { int serverPort = kServerPort; // did the user specify a port? if( 2 == argc ) { serverPort = atoi(argv[1]); } # if VERBOSE printf( "Attempting to bind to port %d\n", serverPort ); # endif // set up listening socket - see setup_server_socket() for details. int listenfd = setup_server_socket( serverPort ); if( -1 == listenfd ) return 1; // loop forever while( 1 ) { sockaddr_in clientAddr; socklen_t addrSize = sizeof(clientAddr); // accept a single incoming connection int clientfd = accept( listenfd, (sockaddr*)&clientAddr, &addrSize ); printf("Accepted a new client.. \n"); if( -1 == clientfd ) { perror( "accept() failed" ); continue; // attempt to accept a different client. } # if VERBOSE // print some information about the new client char buff[128]; printf( "Connection from %s:%d -> socket %d\n", inet_ntop( AF_INET, &clientAddr.sin_addr, buff, sizeof(buff) ), ntohs(clientAddr.sin_port), clientfd ); fflush( stdout ); # endif # if NONBLOCKING // enable non-blocking sends and receives on this socket if( !set_socket_nonblocking( clientfd ) ) continue; # endif // initialize connection data ConnectionData connData; memset( &connData, 0, sizeof(connData) ); connData.sock = clientfd; connData.state = eConnStateReceiving; // Repeatedly receive and re-send data from the connection. When // the connection closes, process_client_*() will return false, no // further processing is done. bool processFurther = true; while( processFurther ) { while( processFurther && connData.state == eConnStateReceiving ) processFurther = process_client_recv( connData ); while( processFurther && connData.state == eConnStateSending ) processFurther = process_client_send( connData ); } // done - close connection close( connData.sock ); } // The program will never reach this part, but for demonstration purposes, // we'll clean up the server resources here and then exit nicely. close( listenfd ); return 0; }