@@ -43,7 +43,8 @@ HTTPServer::HTTPServer() {
4343HTTPServer::~HTTPServer () {
4444 // Loop through hostList and delete all ResourceHosts
4545 while (!hostList.empty ()) {
46- delete hostList.back ();
46+ ResourceHost* resHost = hostList.back ();
47+ delete resHost;
4748 hostList.pop_back ();
4849 }
4950 vhosts.clear ();
@@ -56,14 +57,15 @@ HTTPServer::~HTTPServer() {
5657 * @param port Port to listen on
5758 * @return True if initialization succeeded. False if otherwise
5859 */
59- void HTTPServer::start (int port) {
60- canRun = false ;
60+ bool HTTPServer::start (int port) {
61+ canRun = false ;
62+ listenPort = port;
6163
6264 // Create a handle for the listening socket, TCP
6365 listenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
6466 if (listenSocket == INVALID_SOCKET) {
6567 std::cout << " Could not create socket!" << std::endl;
66- return ;
68+ return false ;
6769 }
6870
6971 // Set socket as non blocking
@@ -73,50 +75,60 @@ void HTTPServer::start(int port) {
7375 // modify to support multiple address families (bottom): http://eradman.com/posts/kqueue-tcp.html
7476 memset (&serverAddr, 0 , sizeof (struct sockaddr_in )); // clear the struct
7577 serverAddr.sin_family = AF_INET; // Family: IP protocol
76- serverAddr.sin_port = htons (port ); // Set the port (convert from host to netbyte order)
78+ serverAddr.sin_port = htons (listenPort ); // Set the port (convert from host to netbyte order)
7779 serverAddr.sin_addr .s_addr = INADDR_ANY; // Let OS intelligently select the server's host address
7880
7981 // Bind: Assign the address to the socket
8082 if (bind (listenSocket, (struct sockaddr *)&serverAddr, sizeof (serverAddr)) != 0 ) {
8183 std::cout << " Failed to bind to the address!" << std::endl;
82- return ;
84+ return false ;
8385 }
8486
8587 // Listen: Put the socket in a listening state, ready to accept connections
8688 // Accept a backlog of the OS Maximum connections in the queue
8789 if (listen (listenSocket, SOMAXCONN) != 0 ) {
8890 std::cout << " Failed to put the socket in a listening state" << std::endl;
89- return ;
91+ return false ;
9092 }
9193
9294 // Setup kqueue
9395 kqfd = kqueue ();
9496 if (kqfd == -1 ) {
9597 std::cout << " Could not create the kernel event queue!" << std::endl;
96- return ;
98+ return false ;
9799 }
98100
99101 // Have kqueue watch the listen socket
100- struct kevent kev;
101- EV_SET (&kev, listenSocket, EVFILT_READ, EV_ADD, 0 , 0 , NULL ); // Fills kev
102- kevent (kqfd, &kev, 1 , NULL , 0 , NULL );
103-
104- std::cout << " Server started. Listening on port " << port << " ..." << std::endl;
102+ updateEvent (listenSocket, EVFILT_READ, EV_ADD, 0 , 0 , NULL );
105103
106- // Start processing
107104 canRun = true ;
108- process ();
105+ std::cout << " Server ready. Listening on port " << listenPort << " ..." << std::endl;
106+ return true ;
109107}
110108
111109/* *
112110 * Stop
113- * Cleanup all server resources created in start()
111+ * Disconnect all clients and cleanup all server resources created in start()
114112 */
115113void HTTPServer::stop () {
116114 canRun = false ;
117115
118- if (listenSocket != INVALID_SOCKET)
119- closeSockets ();
116+ if (listenSocket != INVALID_SOCKET) {
117+ // Close all open connections and delete Client's from memory
118+ for (auto & x : clientMap)
119+ disconnectClient (x.second , false );
120+
121+ // Clear the map
122+ clientMap.clear ();
123+
124+ // Remove listening socket from kqueue
125+ updateEvent (listenSocket, EVFILT_READ, EV_DELETE, 0 , 0 , NULL );
126+
127+ // Shudown the listening socket and release it to the OS
128+ shutdown (listenSocket, SHUT_RDWR);
129+ close (listenSocket);
130+ listenSocket = INVALID_SOCKET;
131+ }
120132
121133 if (kqfd != -1 ) {
122134 close (kqfd);
@@ -127,65 +139,14 @@ void HTTPServer::stop() {
127139}
128140
129141/* *
130- * Close Sockets
131- * Disconnect and delete all clients in the client map. Shutdown the listening socket
142+ * Update Event
143+ * Update the kqueue by creating the appropriate kevent structure
144+ * See kqueue documentation for parameter descriptions
132145 */
133- void HTTPServer::closeSockets () {
134- // Close all open connections and delete Client's from memory
135- for (auto & x : clientMap)
136- disconnectClient (x.second , false );
137-
138- // Clear the map
139- clientMap.clear ();
140-
141- // Remove listening socket from kqueue
146+ void HTTPServer::updateEvent (int ident, short filter, u_short flags, u_int fflags, int data, void *udata) {
142147 struct kevent kev;
143- EV_SET (&kev, listenSocket, EVFILT_READ, EV_DELETE, 0 , 0 , NULL );
148+ EV_SET (&kev, ident, filter, flags, fflags, data, udata );
144149 kevent (kqfd, &kev, 1 , NULL , 0 , NULL );
145-
146- // Shudown the listening socket and release it to the OS
147- shutdown (listenSocket, SHUT_RDWR);
148- close (listenSocket);
149- listenSocket = INVALID_SOCKET;
150- }
151-
152- /* *
153- * Accept Connection
154- * When a new connection is detected in runServer() this function is called. This attempts to accept the pending
155- * connection, instance a Client object, and add to the client Map
156- */
157- void HTTPServer::acceptConnection () {
158- // Setup new client with prelim address info
159- sockaddr_in clientAddr;
160- int clientAddrLen = sizeof (clientAddr);
161- int clfd = INVALID_SOCKET;
162-
163- // Accept the pending connection and retrive the client descriptor
164- clfd = accept (listenSocket, (sockaddr*)&clientAddr, (socklen_t *)&clientAddrLen);
165- if (clfd == INVALID_SOCKET)
166- return ;
167-
168- // Set socket as non blocking
169- fcntl (clfd, F_SETFL, O_NONBLOCK);
170-
171- // Instance Client object
172- Client *cl = new Client (clfd, clientAddr);
173-
174- // Add kqueue event to track the new client socket for READ events (enabled)
175- struct kevent read_kev;
176- EV_SET (&read_kev, clfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0 , 0 , NULL ); // Fills read_kev
177- kevent (kqfd, &read_kev, 1 , NULL , 0 , NULL );
178-
179- // Add kqueue event to track the new client socket for WRITE events (disabled)
180- struct kevent write_kev;
181- EV_SET (&write_kev, clfd, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0 , 0 , NULL ); // Fills write_kev
182- kevent (kqfd, &write_kev, 1 , NULL , 0 , NULL );
183-
184- // Add the client object to the client map
185- clientMap.insert (std::pair<int , Client*>(clfd, cl));
186-
187- // Print the client's IP on connect
188- std::cout << " [" << cl->getClientIP () << " ] connected" << std::endl;
189150}
190151
191152/* *
@@ -197,20 +158,20 @@ void HTTPServer::process() {
197158 int nev = 0 ; // Number of changed events returned by kevent
198159 Client* cl = NULL ;
199160 struct kevent read_kev, write_kev;
200-
161+
201162 while (canRun) {
202163 // Get a list of changed socket descriptors with a read event triggered in evList
203- // Timeout is NULL, kevent will wait for a change before returning
204- nev = kevent (kqfd, NULL , 0 , evList, QUEUE_SIZE, NULL );
164+ // Timeout set in the header
165+ nev = kevent (kqfd, NULL , 0 , evList, QUEUE_SIZE, &kqTimeout );
205166
206167 if (nev <= 0 )
207168 continue ;
208169
209- // Loop through only the sockets that have changed in the evList array
210- for (int i = 0 ; i < nev; i++) {
211- if (evList[i].ident == (unsigned int )listenSocket) { // A client is waiting to connect
212- acceptConnection ();
213- } else { // Client descriptor has triggered an event
170+ // Loop through only the sockets that have changed in the evList array
171+ for (int i = 0 ; i < nev; i++) {
172+ if (evList[i].ident == (unsigned int )listenSocket) { // A client is waiting to connect
173+ acceptConnection ();
174+ } else { // Client descriptor has triggered an event
214175 cl = getClient (evList[i].ident ); // ident contains the clients socket descriptor
215176 if (cl == NULL ) {
216177 std::cout << " Could not find client" << std::endl;
@@ -230,28 +191,57 @@ void HTTPServer::process() {
230191 if (evList[i].filter == EVFILT_READ) {
231192 // std::cout << "read filter " << evList[i].data << " bytes available" << std::endl;
232193 // Read and process any pending data on the wire
233- readClient (cl, evList[i].data ); // data contains the number of bytes waiting to be read
194+ readClient (cl, evList[i].data ); // data contains the number of bytes waiting to be read
234195
235196 // Have kqueue disable tracking of READ events and enable tracking of WRITE events
236- EV_SET (&read_kev, evList[i].ident , EVFILT_READ, EV_DISABLE, 0 , 0 , NULL );
237- EV_SET (&write_kev, evList[i].ident , EVFILT_WRITE, EV_ENABLE, 0 , 0 , NULL );
238- kevent (kqfd, &read_kev, 1 , NULL , 0 , NULL );
239- kevent (kqfd, &write_kev, 1 , NULL , 0 , NULL );
240- } else if ((evList[i].filter == EVFILT_WRITE)) {
197+ updateEvent (evList[i].ident , EVFILT_READ, EV_DISABLE, 0 , 0 , NULL );
198+ updateEvent (evList[i].ident , EVFILT_WRITE, EV_ENABLE, 0 , 0 , NULL );
199+ } else if (evList[i].filter == EVFILT_WRITE) {
241200 // std::cout << "write filter with " << evList[i].data << " bytes available" << std::endl;
242201 // Write any pending data to the client - writeClient returns true if there is additional data to send in the client queue
243202 if (!writeClient (cl, evList[i].data )) { // data contains number of bytes that can be written
244203 // std::cout << "switch back to read filter" << std::endl;
245204 // If theres nothing more to send, Have kqueue disable tracking of WRITE events and enable tracking of READ events
246- EV_SET (&read_kev, evList[i].ident , EVFILT_READ, EV_ENABLE, 0 , 0 , NULL );
247- EV_SET (&write_kev, evList[i].ident , EVFILT_WRITE, EV_DISABLE, 0 , 0 , NULL );
248- kevent (kqfd, &write_kev, 1 , NULL , 0 , NULL );
249- kevent (kqfd, &read_kev, 1 , NULL , 0 , NULL );
205+ updateEvent (evList[i].ident , EVFILT_READ, EV_ENABLE, 0 , 0 , NULL );
206+ updateEvent (evList[i].ident , EVFILT_WRITE, EV_DISABLE, 0 , 0 , NULL );
250207 }
251208 }
252- }
253- } // Pending event loop
254- } // Main while
209+ }
210+ } // Event loop
211+ } // canRun
212+ }
213+
214+ /* *
215+ * Accept Connection
216+ * When a new connection is detected in runServer() this function is called. This attempts to accept the pending
217+ * connection, instance a Client object, and add to the client Map
218+ */
219+ void HTTPServer::acceptConnection () {
220+ // Setup new client with prelim address info
221+ sockaddr_in clientAddr;
222+ int clientAddrLen = sizeof (clientAddr);
223+ int clfd = INVALID_SOCKET;
224+
225+ // Accept the pending connection and retrive the client descriptor
226+ clfd = accept (listenSocket, (sockaddr*)&clientAddr, (socklen_t *)&clientAddrLen);
227+ if (clfd == INVALID_SOCKET)
228+ return ;
229+
230+ // Set socket as non blocking
231+ fcntl (clfd, F_SETFL, O_NONBLOCK);
232+
233+ // Instance Client object
234+ Client *cl = new Client (clfd, clientAddr);
235+
236+ // Add kqueue event to track the new client socket for READ and WRITE events
237+ updateEvent (clfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0 , 0 , NULL );
238+ updateEvent (clfd, EVFILT_WRITE, EV_ADD | EV_DISABLE, 0 , 0 , NULL ); // Disabled initially
239+
240+ // Add the client object to the client map
241+ clientMap.insert (std::pair<int , Client*>(clfd, cl));
242+
243+ // Print the client's IP on connect
244+ std::cout << " [" << cl->getClientIP () << " ] connected" << std::endl;
255245}
256246
257247/* *
@@ -288,11 +278,8 @@ void HTTPServer::disconnectClient(Client *cl, bool mapErase) {
288278 std::cout << " [" << cl->getClientIP () << " ] disconnected" << std::endl;
289279
290280 // Remove socket events from kqueue
291- struct kevent read_kev, write_kev;
292- EV_SET (&read_kev, cl->getSocket (), EVFILT_READ, EV_DELETE, 0 , 0 , NULL );
293- EV_SET (&write_kev, cl->getSocket (), EVFILT_WRITE, EV_DELETE, 0 , 0 , NULL );
294- kevent (kqfd, &read_kev, 1 , NULL , 0 , NULL );
295- kevent (kqfd, &write_kev, 1 , NULL , 0 , NULL );
281+ updateEvent (cl->getSocket (), EVFILT_READ, EV_DELETE, 0 , 0 , NULL );
282+ updateEvent (cl->getSocket (), EVFILT_WRITE, EV_DELETE, 0 , 0 , NULL );
296283
297284 // Close the socket descriptor
298285 close (cl->getSocket ());
0 commit comments