@@ -33,10 +33,6 @@ HTTPServer::HTTPServer() {
3333
3434 // Instance clientMap, relates Socket Descriptor to pointer to Client object
3535 clientMap = new map<SOCKET, Client*>();
36-
37- // Zero the file descriptor sets
38- FD_ZERO (&fd_master);
39- FD_ZERO (&fd_read);
4036}
4137
4238/* *
@@ -85,13 +81,17 @@ void HTTPServer::start(int port) {
8581 return ;
8682 }
8783
88- // Add the listening socket to the master set and the largest FD is now the listening socket
89- FD_SET (listenSocket, &fd_master);
90- fdmax = listenSocket;
91-
92- // Set select to timeout at 50 microseconds
93- timeout.tv_sec = 0 ;
94- timeout.tv_usec = 50 ;
84+ // Setup kqueue
85+ kqfd = kqueue ();
86+ if (kqfd == -1 ) {
87+ cout << " Could not create the kernel event queue!" << endl;
88+ return ;
89+ }
90+
91+ // Have kqueue watch the listen socket
92+ struct kevent kev;
93+ EV_SET (&kev, listenSocket, EVFILT_READ, EV_ADD, 0 , 0 , NULL ); // Fills kev
94+ kevent (kqfd, &kev, 1 , NULL , 0 , NULL );
9595
9696 cout << " Server started. Listening on port " << port << " ..." << endl;
9797
@@ -155,12 +155,10 @@ void HTTPServer::acceptConnection() {
155155 // Instance Client object
156156 Client *cl = new Client (clfd, clientAddr);
157157
158- // Add to the master FD set
159- FD_SET (clfd, &fd_master);
160-
161- // If the new client's handle is greater than the max, set the new max
162- if (clfd > fdmax)
163- fdmax = clfd;
158+ // Have kqueue track the new client socket (udata contains pointer to Client object)
159+ struct kevent kev;
160+ EV_SET (&kev, clfd, EVFILT_READ, EV_ADD, 0 , 0 , cl); // Fills kev
161+ kevent (kqfd, &kev, 1 , NULL , 0 , NULL );
164162
165163 // Add the client object to the client map
166164 clientMap->insert (std::pair<int , Client*>(clfd, cl));
@@ -175,35 +173,34 @@ void HTTPServer::acceptConnection() {
175173 * the listening socket
176174 */
177175void HTTPServer::process () {
178- int sret = 0 ;
176+ int nev = 0 ; // Number of changed events returned by kevent
177+ Client* cl = NULL ;
179178
180179 while (canRun) {
181- // Copy master set into fd_read for processing
182- fd_read = fd_master;
183-
184- // Populate read_fd set with client descriptors that are ready to be read
185- // return values: -1 = unsuccessful, 0 = timeout, > 0 - # of sockets that need to be read
186- sret = select (fdmax+1 , &fd_read, NULL , NULL , &timeout);
187- if (sret > 0 ) {
188- // Loop through all descriptors in the read_fd set and check to see if data needs to be processed
189- for (int i = 0 ; i <= fdmax; i++) {
190- // Socket i isn't ready to be read (not in the read set), continue
191- if (!FD_ISSET (i, &fd_read))
192- continue ;
193-
194- // A new client is waiting to be accepted on the listenSocket
195- if (listenSocket == i) {
196- acceptConnection ();
197- } else { // The descriptor is a client
198- Client *cl = getClient (i);
199- handleClient (cl);
200- }
201- }
202- } else if (sret < 0 ) {
203- cout << " Select failed!" << endl;
204- break ;
180+ // Get a list of changed socket descriptors (if any) in evlist
181+ // Timeout is NULL, kevent will wait for a change before returning
182+ nev = kevent (kqfd, NULL , 0 , evlist, QUEUE_SIZE, NULL );
183+
184+ if (nev > 0 ) {
185+ // Loop through only the sockets that have changed in the evlist array
186+ for (int i = 0 ; i < nev; i++) {
187+ if (evlist[i].ident == (unsigned int )listenSocket) { // A client is waiting to connect
188+ acceptConnection ();
189+ } else { // Client descriptor has triggered an event
190+ cl = (Client*)evlist[i].udata ;
191+ if (evlist[i].flags & EVFILT_READ) {
192+ handleClient (cl);
193+ } else if (evlist[i].flags & EV_EOF) {
194+ disconnectClient (cl);
195+ } else {
196+ // unhandled event
197+ }
198+ }
199+ }
200+ } else if (nev < 0 ) {
201+ cout << " kevent failed!" << endl; // should call errno..
205202 } else { // Timeout
206- usleep (100 );
203+ // usleep(100);
207204 }
208205 }
209206}
@@ -239,12 +236,9 @@ void HTTPServer::disconnectClient(Client *cl, bool mapErase) {
239236 if (cl == NULL )
240237 return ;
241238
242- // Close the socket descriptor
239+ // Close the socket descriptor (which will also remove from kqueue's event list on the next kevent call)
243240 close (cl->getSocket ());
244241
245- // Remove the client from the master FD map
246- FD_CLR (cl->getSocket (), &fd_master);
247-
248242 // Remove the client from the clientMap
249243 if (mapErase)
250244 clientMap->erase (cl->getSocket ());
0 commit comments