55 * Initialize state and server variables
66 */
77HTTPServer::HTTPServer () {
8+ canRun = false ;
9+ thread = NULL ;
10+
811 listenSocket = INVALID_SOCKET;
912 memset (&serverAddr, 0 , sizeof (serverAddr)); // clear the struct
10- keepRunning = false ;
1113
1214 // Create a resource manager managing the VIRTUAL base path ./
1315 resMgr = new ResourceManager (" ./" , true );
@@ -28,22 +30,28 @@ HTTPServer::~HTTPServer() {
2830 if (listenSocket != INVALID_SOCKET)
2931 closeSockets ();
3032 delete clientMap;
33+
34+ if (thread != NULL )
35+ delete thread;
3136}
3237
3338/* *
34- * Init Socket
39+ * Start Server
3540 * Initialize the Server Socket by requesting a socket handle, binding, and going into a listening state
3641 *
3742 * @param port Port to listen on
3843 * @return True if initialization succeeded. False if otherwise
3944 */
40- bool HTTPServer::initSocket (int port) {
45+ void HTTPServer::start (int port) {
4146 // Create a handle for the listening socket, TCP
4247 listenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
4348 if (listenSocket == INVALID_SOCKET) {
4449 cout << " Could not create socket!" << endl;
45- return false ;
50+ return ;
4651 }
52+
53+ // Set socket as non blocking
54+ fcntl (listenSocket, F_SETFL, O_NONBLOCK);
4755
4856 // Populate the server address structure
4957 serverAddr.sin_family = AF_INET; // Family: IP protocol
@@ -53,23 +61,47 @@ bool HTTPServer::initSocket(int port) {
5361 // Bind: Assign the address to the socket
5462 if (bind (listenSocket, (sockaddr*)&serverAddr, sizeof (serverAddr)) != 0 ) {
5563 cout << " Failed to bind to the address!" << endl;
56- return false ;
64+ return ;
5765 }
5866
5967 // Listen: Put the socket in a listening state, ready to accept connections
6068 // Accept a backlog of the OS Maximum connections in the queue
6169 if (listen (listenSocket, SOMAXCONN) != 0 ) {
6270 cout << " Failed to put the socket in a listening state" << endl;
63- return false ;
71+ return ;
6472 }
6573
6674 // Add the listening socket to the master set and the largest FD is now the listening socket
6775 FD_SET (listenSocket, &fd_master);
6876 fdmax = listenSocket;
6977
70- keepRunning = true ;
78+ // Set select to timeout at 50 microseconds
79+ timeout.tv_sec = 0 ;
80+ timeout.tv_usec = 50 ;
81+
82+ cout << " Server started. Listening on port " << port << " ..." << endl;
83+
84+ // Spawn thread
85+ canRun = true ;
86+ thread = new boost::thread (boost::ref (*this ));
87+ }
88+
89+ /* *
90+ * Stop
91+ * Signal the server thread to stop running and shut down
92+ */
93+ void HTTPServer::stop () {
94+ runMutex.lock ();
95+ canRun = false ;
96+ runMutex.unlock ();
97+
98+ if (thread != NULL )
99+ thread->join ();
71100
72- return true ;
101+ // Safely shutdown the server and close all open connections and sockets
102+ closeSockets ();
103+
104+ cout << " Server shutdown!" << endl;
73105}
74106
75107/* *
@@ -107,6 +139,9 @@ void HTTPServer::acceptConnection() {
107139 clfd = accept (listenSocket, (sockaddr*)&clientAddr, (socklen_t *)&clientAddrLen);
108140 if (clfd == INVALID_SOCKET)
109141 return ;
142+
143+ // Set socket as non blocking
144+ fcntl (clfd, F_SETFL, O_NONBLOCK);
110145
111146 // Instance Client object
112147 Client *cl = new Client (clfd, clientAddr);
@@ -126,50 +161,49 @@ void HTTPServer::acceptConnection() {
126161}
127162
128163/* *
129- * Run Server
130- * Main server loop where the socket is initialized and the loop is started, checking for new messages or clients to be read with select()
131- * and handling them appropriately
164+ * Server Process
165+ * Main server processing function that checks for any new connections or data to read on
166+ * the listening socket
132167 */
133- void HTTPServer::runServer (int port) {
134- // Initialize the socket and put it into a listening state
135- if (!initSocket (port)) {
136- cout << " Failed to start server." << endl;
137- return ;
138- }
139-
140- cout << " Server started. Listening on port " << port << " ..." << endl;
141-
142- // Processing loop
143- while (keepRunning) {
144- usleep (1000 );
168+ void HTTPServer::operator () () {
169+ bool run = true ;
170+ int sret = 0 ;
171+
172+ while (run) {
173+ // Update the running state
174+ runMutex.lock ();
175+ run = canRun;
176+ runMutex.unlock ();
145177
146- // Copy master set into fd_read for processing
147- fd_read = fd_master;
148-
149- // Populate read_fd set with client descriptors that are ready to be read
150- if (select (fdmax+1 , &fd_read, NULL , NULL , NULL ) < 0 ) {
151- // printf("select failed!");
152- continue ;
153- }
154-
155- // Loop through all descriptors in the read_fd set and check to see if data needs to be processed
156- for (int i = 0 ; i <= fdmax; i++) {
157- // Socket i isn't ready to be read (not in the read set), continue
158- if (!FD_ISSET (i, &fd_read))
159- continue ;
160-
161- // A new client is waiting to be accepted on the listenSocket
162- if (listenSocket == i) {
163- acceptConnection ();
164- } else { // The descriptor is a client
165- Client *cl = getClient (i);
166- handleClient (cl);
167- }
168- }
169- }
170-
171- // Safely shutdown the server and close all open connections and sockets
172- closeSockets ();
178+ // Copy master set into fd_read for processing
179+ fd_read = fd_master;
180+
181+ // Populate read_fd set with client descriptors that are ready to be read
182+ // return values: -1 = unsuccessful, 0 = timeout, > 0 - # of sockets that need to be read
183+ sret = select (fdmax+1 , &fd_read, NULL , NULL , &timeout);
184+ if (sret > 0 ) {
185+ // Loop through all descriptors in the read_fd set and check to see if data needs to be processed
186+ for (int i = 0 ; i <= fdmax; i++) {
187+ // Socket i isn't ready to be read (not in the read set), continue
188+ if (!FD_ISSET (i, &fd_read))
189+ continue ;
190+
191+ // A new client is waiting to be accepted on the listenSocket
192+ if (listenSocket == i) {
193+ acceptConnection ();
194+ } else { // The descriptor is a client
195+ Client *cl = getClient (i);
196+ handleClient (cl);
197+ }
198+ }
199+ } else if (sret < 0 ) {
200+ cout << " Select failed!" << endl;
201+ break ;
202+ } else { // Timeout
203+ // Yield rest of time slice to CPU
204+ boost::this_thread::yield ();
205+ }
206+ }
173207}
174208
175209/* *
0 commit comments