summaryrefslogtreecommitdiff
path: root/src/utils.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/utils.c264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/utils.c b/src/utils.c
new file mode 100644
index 0000000..1a91d7a
--- /dev/null
+++ b/src/utils.c
@@ -0,0 +1,264 @@
+/* $Id: utils.c,v 1.1.1.1 2000-02-16 17:32:24 sdyoung Exp $
+ *
+ * Misc. routines which are used by the various functions to handle strings
+ * and memory allocation and pretty much anything else we can think of. Also,
+ * the load cutoff routine is in here, along with the HTML show stats
+ * function. Could not think of a better place for it, so it's in here.
+ *
+ * Copyright (C) 1998 Steven Young
+ * Copyright (C) 1999 Robert James Kaes (rjkaes@flarenet.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <defines.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <ctype.h>
+#include <sysexits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <assert.h>
+
+#include "config.h"
+#include "tinyproxy.h"
+#include "utils.h"
+#include "log.h"
+#include "conns.h"
+#include "buffer.h"
+
+char *xstrdup(char *st)
+{
+ char *p;
+
+ assert(st);
+
+ if (!(p = strdup(st))) {
+ log("ERROR xstrdup: out of memory (%s)", strerror(errno));
+ return NULL;
+ } else {
+ return p;
+ }
+}
+
+/*
+ * Find the start of the needle in the haystack. Limits the search to less
+ * than "length" characters. Returns NULL if the needle is not found.
+ */
+char *xstrstr(char *haystack, char *needle, unsigned int length,
+ int case_sensitive)
+{
+ unsigned int i;
+ /* Used to specify which function to use... need the decl. */
+ int (*fn) (const char *s1, const char *s2, unsigned int n);
+
+ assert(haystack);
+ assert(needle);
+ assert(length > 0);
+ assert(case_sensitive == FALSE || case_sensitive == TRUE);
+
+ if (case_sensitive)
+ fn = strncmp;
+ else
+ fn = strncasecmp;
+
+ if (strlen(needle) > length)
+ return NULL;
+
+ for (i = 0; i <= length - strlen(needle); i++) {
+ if ((*fn) (haystack + i, needle, strlen(needle)) == 0)
+ return haystack + i;
+
+ }
+
+ return NULL;
+}
+
+/*
+ * for-sure malloc
+ */
+void *xmalloc(unsigned long int sz)
+{
+ void *p;
+
+ assert(sz > 0);
+
+ if (!(p = malloc((size_t) sz))) {
+ log("ERROR xmalloc: out of memory (%s)", strerror(errno));
+ return NULL;
+ }
+ return p;
+}
+
+#ifdef USE_PROC
+int calcload(void)
+{
+ char buf[BUFFER], *p;
+ FILE *f;
+
+ if (!config.cutoffload) {
+ return -1;
+ }
+
+ if (!(f = fopen("/proc/loadavg", "rt"))) {
+ log("unable to read /proc/loadavg");
+ config.cutoffload = 0.0;
+ return -1;
+ }
+ fgets(buf, BUFFER, f);
+ p = strchr(buf, ' ');
+ *p = '\0';
+ load = atof(buf);
+ fclose(f);
+ return 0;
+}
+
+#else
+int calcload(void)
+{
+ FILE *f;
+ char buf[BUFFER];
+ char *p, *y;
+
+ if (!config.cutoffload) {
+ return -1;
+ }
+
+ if (!(f = popen(UPTIME_PATH, "r"))) {
+ log("calcload: unable to exec uptime");
+ config.cutoffload = 0.0;
+ return -1;
+ }
+ fgets(buf, BUFFER, f);
+ p = strrchr(buf, ':');
+ p += 2;
+ y = strchr(p, ',');
+ *y = '\0';
+ load = atof(p);
+ pclose(f);
+ return 0;
+}
+
+#endif
+
+/*
+ * Delete the server's buffer and replace it with a premade message which will
+ * be sent to the client.
+ */
+static void update_output_buffer(struct conn_s *connptr, char *outbuf)
+{
+ assert(connptr);
+ assert(outbuf);
+
+ delete_buffer(connptr->sbuffer);
+ connptr->sbuffer = new_buffer();
+
+ push_buffer(connptr->sbuffer, outbuf, strlen(outbuf));
+ shutdown(connptr->server_fd, 2);
+ connptr->type = CLOSINGCONN;
+}
+
+/*
+ * Display the statics of the tinyproxy server.
+ */
+int showstats(struct conn_s *connptr)
+{
+ char *outbuf;
+ static char *msg = "HTTP/1.0 200 OK\r\n" \
+ "Content-type: text/html\r\n\r\n" \
+ "<html><head><title>%s stats</title></head>\r\n" \
+ "<body>\r\n" \
+ "<center><h2>%s run-time statistics</h2></center><hr>\r\n" \
+ "<blockquote>\r\n" \
+ "Number of requests: %lu<br>\r\n" \
+ "Number of connections: %lu<br>\r\n" \
+ "Number of bad connections: %lu<br>\r\n" \
+ "Number of opens: %lu<br>\r\n" \
+ "Number of listens: %lu<br>\r\n" \
+ "Number of bytes (tx): %lu<br>\r\n" \
+ "Number of bytes (rx): %lu<br>\r\n" \
+ "Number of garbage collects:%lu<br>\r\n" \
+ "Number of idle connection kills:%lu<br>\r\n" \
+ "Number of refused connections due to high load:%lu<br>\r\n" \
+ "Current system load average:%.2f" \
+ "(recalculated every % lu seconds)<br>\r\n" \
+ "</blockquote>\r\n</body></html>\r\n";
+
+ assert(connptr);
+
+ outbuf = xmalloc(BUFFER);
+
+ sprintf(outbuf, msg, VERSION, VERSION, stats.num_reqs,
+ stats.num_cons, stats.num_badcons, stats.num_opens,
+ stats.num_listens, stats.num_tx, stats.num_rx,
+ stats.num_garbage, stats.num_idles, stats.num_refused, load,
+ LOAD_RECALCTIMER);
+
+ update_output_buffer(connptr, outbuf);
+
+ return 0;
+}
+
+/*
+ * Display an error to the client.
+ */
+int httperr(struct conn_s *connptr, int err, char *msg)
+{
+ char *outbuf;
+ static char *premsg = "HTTP/1.0 %d %s\r\n" \
+ "Content-type: text/html\r\n\r\n" \
+ "<html><head><title>%s</title></head>\r\n" \
+ "<body>\r\n" \
+ "<font size=\"+2\">Cache Error!</font><br>\r\n" \
+ "An error of type %d occurred: %s\r\n" \
+ "<hr>\r\n" \
+ "<font size=\"-1\"><em>Generated by %s</em></font>\r\n" \
+ "</body></html>\r\n";
+
+ assert(connptr);
+ assert(err > 0);
+ assert(msg);
+
+ outbuf = xmalloc(BUFFER);
+ sprintf(outbuf, premsg, err, msg, msg, err, msg, VERSION);
+
+ update_output_buffer(connptr, outbuf);
+
+ return 0;
+}
+
+void makedaemon(void)
+{
+ if (fork() != 0)
+ exit(0);
+
+ setsid();
+ signal(SIGHUP, SIG_IGN);
+
+ if (fork() != 0)
+ exit(0);
+
+ chdir("/");
+ umask(0);
+
+ close(0);
+ close(1);
+ close(2);
+}