diff options
Diffstat (limited to '')
-rw-r--r-- | src/utils.c | 264 |
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); +} |