-/* $Id: httpd.js,v 1.31 2006/08/19 11:43:12 mmondor Exp $ */
+/* $Id: httpd.js,v 1.32 2006/08/20 02:40:24 mmondor Exp $ */
/*
* Copyright (c) 2005-2006, Matthew Mondor
* Server identification
*/
const SERVER_VERSION = 'mmondor_js_httpd/0.1.0 (NetBSD)';
-const SERVER_CVSID = '$Id: httpd.js,v 1.31 2006/08/19 11:43:12 mmondor Exp $';
+const SERVER_CVSID = '$Id: httpd.js,v 1.32 2006/08/20 02:40:24 mmondor Exp $';
fd.set = set;
fd.appserv = s;
- poll_set_add(fd);
+ pollset.add(fd);
} catch (x) {
err.put(x + " in appserv_connect()\n");
return false;
/*
- * To know how many connections we are currently serving and limit them
- * XXX Could possibly also be integrated into the FD object prototype
+ * Connections limits management
*/
-var counters_connections = 0;
-var counters_addresses = {};
-
-function counters_inc(fd)
+function CLimits(maxtotal, maxaddr)
{
- var addr, addrcnt;
+ this.connections = 0;
+ this.addresses = {};
+ this.maxtotal = maxtotal;
+ this.maxaddr = maxaddr;
+}
- if (counters_connections >= options.max_connections)
- return false;
+CLimits.prototype = {
+ add: function(fd)
+ {
+ var addr, addrcnt;
- addr = fd.client_addr;
- if ((addrcnt = counters_addresses[addr]) != undefined &&
- addrcnt >= options.max_connections_addr)
- return false;
+ if (this.connections >= this.maxtotal)
+ return false;
- if (addrcnt == undefined)
- addrcnt = 1;
- else
- addrcnt++;
- counters_addresses[addr] = addrcnt;
+ addr = fd.client_addr;
+ if ((addrcnt = this.addresses[addr]) != undefined &&
+ addrcnt >= this.maxaddr)
+ return false;
- return true;
-}
+ if (addrcnt == undefined)
+ addrcnt = 1;
+ else
+ addrcnt++;
+ this.addresses[addr] = addrcnt;
+ this.connections++;
-function counters_dec(fd)
-{
- var addr = fd.client_addr;
- if ((--counters_addresses[addr]) == 0)
- delete counters_addresses[addr];
+ return true;
+ },
- counters_connections--;
-}
+ remove: function(fd)
+ {
+ var addr;
+
+ addr = fd.client_addr;
+ if ((--this.addresses[addr]) == 0)
+ delete this.addresses[addr];
+ this.connections--;
+ }
+};
+var climits = new CLimits();
-var fdidx_count = 0;
-var fdidx_min = 0;
-var poll_set = {};
-function poll_set_add(fd)
-{
+/*
+ * Descriptor polling set management
+ */
- if (fdidx_count > 9999999)
- fdidx_count = fdidx_min + 1;
- fd.fdidx = fdidx_count++;
- poll_set[fd.fdidx] = fd;
+function PollSet()
+{
+ this.count = 0;
+ this.min = 0;
+ this.set = {};
}
-function poll_set_remove(fd)
-{
+PollSet.prototype = {
+ add: function(fd)
+ {
- delete poll_set[fd.fdidx];
-}
+ if (this.count > 9999999)
+ this.count = this.min + 1;
+ fd.fdidx = this.count++;
+ this.set[fd.fdidx] = fd;
+ },
+
+ remove: function(fd)
+ {
+
+ delete this.set[fd.fdidx];
+ }
+};
+
+var pollset = new PollSet();
*/
fd.events = FD.POLLIN;
fd.type = STYPE_LISTEN;
- poll_set_add(fd);
+ pollset.add(fd);
} catch (x) {
err.put(x + " preparing listening socket\n");
}
}
- if (fdidx_count == 0)
+ if (pollset.count == 0)
exit();
- fdidx_min = fdidx_count;
+ pollset.min = pollset.count;
/*
* Main loop
var exp = cur + 3600;
var old;
- for (i in poll_set) {
- if ((fd = poll_set[i]) == undefined ||
+ for (i in pollset.set) {
+ if ((fd = pollset.set[i]) == undefined ||
fd.type != STYPE_HTTP)
continue;
if (fd.expires <= cur) {
* descriptor, we must close it.
*/
fd.close();
- counters_dec(fd);
- poll_set_remove(fd);
+ climits.remove(fd);
+ pollset.remove(fd);
continue;
}
if (fd.expires < exp)
exp -= cur;
/*
- * Poll our set of descriptors for events
+ * Poll our set of descriptors for events.
+ * XXX We definitely should use libevent here.
+ * The polling set gets regenerated by the C code at every
+ * call, which is suboptimal. I guess that we still could use
+ * poll while providing C primitives to add/remove descriptors
+ * from the set a-la select(2). But libevent(3) is always
+ * superior while being able to run on various systems unlike
+ * BSD kqueue(2).
*/
try {
- e = FD.poll(poll_set, exp * 1000);
+ e = FD.poll(pollset.set, exp * 1000);
} catch (x) {
err.put(x + " for poll(2)\n");
continue;
/*
* Verify if we should call the session gc, and if so, do so.
+ * XXX We probably shouldn't do this anymore
*/
sess_gc_secs += cur - old;
if (sess_gc_secs >= options.sess_gc_interval) {
(efd.revents & FD.POLLIN) != 0) {
try {
fd = efd.accept();
- if (!counters_inc(fd)) {
+ if (!climits.add(fd)) {
http_error(fd, 403.9,
'Too Many Connections',
'Your browser has exceeded its maximum ' +
* add FD to polling set
*/
fd.state_http_init(cur);
- poll_set_add(fd);
+ pollset.add(fd);
} catch (x) {
err.put(x + " at accept(2)\n");
fd.close();
* them to return a 500 error
*/
}
- counters_dec(efd);
- poll_set_remove(efd);
+ climits.remove(efd);
+ pollset.remove(efd);
}
}
}