tinyproxy/src/utils.c

265 lines
5.7 KiB
C
Raw Normal View History

/* $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);
}