* [Indent] Ran Source Through indent
I re-indented the source code using indent with the following options: indent -kr -bad -bap -nut -i8 -l80 -psl -sob -ss -ncs There are now _no_ tabs in the source files, and all indentation is eight spaces. Lines are 80 characters long, and the procedure type is on it's own line. Read the indent manual for more information about what each option means.
This commit is contained in:
parent
38f0b3a103
commit
c0299e1868
211
src/acl.c
211
src/acl.c
@ -1,4 +1,4 @@
|
||||
/* $Id: acl.c,v 1.21 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: acl.c,v 1.22 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* This system handles Access Control for use of this daemon. A list of
|
||||
* domains, or IP addresses (including IP blocks) are stored in a list
|
||||
@ -37,15 +37,15 @@ enum acl_type { ACL_STRING, ACL_NUMERIC };
|
||||
* entry (like a domain name) or an IP entry.
|
||||
*/
|
||||
struct acl_s {
|
||||
acl_access_t access;
|
||||
enum acl_type type;
|
||||
union {
|
||||
char* string;
|
||||
acl_access_t access;
|
||||
enum acl_type type;
|
||||
union {
|
||||
char *string;
|
||||
struct {
|
||||
unsigned char octet[IPV6_LEN];
|
||||
unsigned char mask[IPV6_LEN];
|
||||
} ip;
|
||||
} address;
|
||||
} address;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -65,11 +65,11 @@ static vector_t access_list = NULL;
|
||||
int
|
||||
insert_acl(char *location, acl_access_t access_type)
|
||||
{
|
||||
struct acl_s acl;
|
||||
int i, ret, mask;
|
||||
char *p, ip_dst[IPV6_LEN];
|
||||
struct acl_s acl;
|
||||
int i, ret, mask;
|
||||
char *p, ip_dst[IPV6_LEN];
|
||||
|
||||
assert(location != NULL);
|
||||
assert(location != NULL);
|
||||
|
||||
/*
|
||||
* If the access list has not been set up, create it.
|
||||
@ -110,7 +110,7 @@ insert_acl(char *location, acl_access_t access_type)
|
||||
*p = '\0';
|
||||
if (full_inet_pton(location, ip_dst) <= 0)
|
||||
return -1;
|
||||
|
||||
|
||||
acl.type = ACL_NUMERIC;
|
||||
memcpy(acl.address.ip.octet, ip_dst, IPV6_LEN);
|
||||
|
||||
@ -119,7 +119,8 @@ insert_acl(char *location, acl_access_t access_type)
|
||||
if (mask >= ((i + 1) * 8))
|
||||
acl.address.ip.mask[i] = 0xff;
|
||||
else
|
||||
acl.address.ip.mask[i] = 0xff << (8 - (mask - i * 8));
|
||||
acl.address.ip.mask[i] =
|
||||
0xff << (8 - (mask - i * 8));
|
||||
}
|
||||
} else {
|
||||
/* In all likelihood a string */
|
||||
@ -138,7 +139,6 @@ insert_acl(char *location, acl_access_t access_type)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called whenever a "string" access control is found in
|
||||
* the ACL. From here we do both a text based string comparison, along with
|
||||
@ -149,72 +149,73 @@ insert_acl(char *location, acl_access_t access_type)
|
||||
* -1 if no tests match, so skip
|
||||
*/
|
||||
static int
|
||||
acl_string_processing(struct acl_s* acl,
|
||||
const char* ip_address,
|
||||
const char* string_address)
|
||||
acl_string_processing(struct acl_s *acl,
|
||||
const char *ip_address, const char *string_address)
|
||||
{
|
||||
int match;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
size_t test_length, match_length;
|
||||
char ipbuf[512];
|
||||
int match;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
size_t test_length, match_length;
|
||||
char ipbuf[512];
|
||||
|
||||
assert(acl && acl->type == ACL_STRING);
|
||||
assert(ip_address && strlen(ip_address) > 0);
|
||||
assert(string_address && strlen(string_address) > 0);
|
||||
|
||||
/*
|
||||
* If the first character of the ACL string is a period, we need to
|
||||
* do a string based test only; otherwise, we can do a reverse
|
||||
* lookup test as well.
|
||||
*/
|
||||
if (acl->address.string[0] != '.') {
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (getaddrinfo(acl->address.string, NULL, &hints, &res) != 0)
|
||||
goto STRING_TEST;
|
||||
/*
|
||||
* If the first character of the ACL string is a period, we need to
|
||||
* do a string based test only; otherwise, we can do a reverse
|
||||
* lookup test as well.
|
||||
*/
|
||||
if (acl->address.string[0] != '.') {
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (getaddrinfo(acl->address.string, NULL, &hints, &res) != 0)
|
||||
goto STRING_TEST;
|
||||
|
||||
ressave = res;
|
||||
ressave = res;
|
||||
|
||||
match = FALSE;
|
||||
do {
|
||||
get_ip_string(res->ai_addr, ipbuf, sizeof(ipbuf));
|
||||
if (strcmp(ip_address, ipbuf) == 0) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
match = FALSE;
|
||||
do {
|
||||
get_ip_string(res->ai_addr, ipbuf, sizeof(ipbuf));
|
||||
if (strcmp(ip_address, ipbuf) == 0) {
|
||||
match = TRUE;
|
||||
break;
|
||||
}
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
freeaddrinfo(ressave);
|
||||
|
||||
if (match) {
|
||||
if (acl->access == ACL_DENY)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
if (acl->access == ACL_DENY)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
STRING_TEST:
|
||||
test_length = strlen(string_address);
|
||||
match_length = strlen(acl->address.string);
|
||||
STRING_TEST:
|
||||
test_length = strlen(string_address);
|
||||
match_length = strlen(acl->address.string);
|
||||
|
||||
/*
|
||||
* If the string length is shorter than AC string, return a -1 so
|
||||
* that the "driver" will skip onto the next control in the list.
|
||||
*/
|
||||
if (test_length < match_length)
|
||||
return -1;
|
||||
/*
|
||||
* If the string length is shorter than AC string, return a -1 so
|
||||
* that the "driver" will skip onto the next control in the list.
|
||||
*/
|
||||
if (test_length < match_length)
|
||||
return -1;
|
||||
|
||||
if (strcasecmp(string_address + (test_length - match_length), acl->address.string) == 0) {
|
||||
if (acl->access == ACL_DENY)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
if (strcasecmp
|
||||
(string_address + (test_length - match_length),
|
||||
acl->address.string) == 0) {
|
||||
if (acl->access == ACL_DENY)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Indicate that no tests succeeded, so skip to next control. */
|
||||
return -1;
|
||||
/* Indicate that no tests succeeded, so skip to next control. */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -226,30 +227,30 @@ STRING_TEST:
|
||||
* -1 neither allowed nor denied.
|
||||
*/
|
||||
static int
|
||||
check_numeric_acl(const struct acl_s* acl, const char* ip)
|
||||
check_numeric_acl(const struct acl_s *acl, const char *ip)
|
||||
{
|
||||
uint8_t addr[IPV6_LEN], x, y;
|
||||
int i;
|
||||
uint8_t addr[IPV6_LEN], x, y;
|
||||
int i;
|
||||
|
||||
assert(acl && acl->type == ACL_NUMERIC);
|
||||
assert(ip && strlen(ip) > 0);
|
||||
|
||||
if (full_inet_pton(ip, &addr) <= 0) return -1;
|
||||
if (full_inet_pton(ip, &addr) <= 0)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i != IPV6_LEN; ++i) {
|
||||
for (i = 0; i != IPV6_LEN; ++i) {
|
||||
x = addr[i] & acl->address.ip.mask[i];
|
||||
y = acl->address.ip.octet[i] & acl->address.ip.mask[i];
|
||||
|
||||
/* If x and y don't match, the IP addresses don't match */
|
||||
if (x != y)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The addresses match, return the permission */
|
||||
return (acl->access == ACL_ALLOW);
|
||||
/* The addresses match, return the permission */
|
||||
return (acl->access == ACL_ALLOW);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Checks whether file descriptor is allowed.
|
||||
*
|
||||
@ -258,48 +259,50 @@ check_numeric_acl(const struct acl_s* acl, const char* ip)
|
||||
* 0 if denied
|
||||
*/
|
||||
int
|
||||
check_acl(int fd, const char* ip, const char* host)
|
||||
check_acl(int fd, const char *ip, const char *host)
|
||||
{
|
||||
struct acl_s* acl;
|
||||
int perm;
|
||||
struct acl_s *acl;
|
||||
int perm;
|
||||
int i;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ip != NULL);
|
||||
assert(host != NULL);
|
||||
assert(fd >= 0);
|
||||
assert(ip != NULL);
|
||||
assert(host != NULL);
|
||||
|
||||
/*
|
||||
* If there is no access list allow everything.
|
||||
*/
|
||||
if (!access_list) return 1;
|
||||
/*
|
||||
* If there is no access list allow everything.
|
||||
*/
|
||||
if (!access_list)
|
||||
return 1;
|
||||
|
||||
for (i = 0; i != vector_length(access_list); ++i) {
|
||||
acl = vector_getentry(access_list, i, NULL);
|
||||
switch (acl->type) {
|
||||
case ACL_STRING:
|
||||
perm = acl_string_processing(acl, ip, host);
|
||||
break;
|
||||
case ACL_STRING:
|
||||
perm = acl_string_processing(acl, ip, host);
|
||||
break;
|
||||
|
||||
case ACL_NUMERIC:
|
||||
if (ip[0] == '\0') continue;
|
||||
perm = check_numeric_acl(acl, ip);
|
||||
break;
|
||||
}
|
||||
case ACL_NUMERIC:
|
||||
if (ip[0] == '\0')
|
||||
continue;
|
||||
perm = check_numeric_acl(acl, ip);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the return value too see if the IP address is
|
||||
* allowed or denied.
|
||||
*/
|
||||
if (perm == 0)
|
||||
break;
|
||||
else if (perm == 1)
|
||||
return perm;
|
||||
* allowed or denied.
|
||||
*/
|
||||
if (perm == 0)
|
||||
break;
|
||||
else if (perm == 1)
|
||||
return perm;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deny all connections by default.
|
||||
*/
|
||||
log_message(LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].",
|
||||
host, ip);
|
||||
return 0;
|
||||
/*
|
||||
* Deny all connections by default.
|
||||
*/
|
||||
log_message(LOG_NOTICE, "Unauthorized connection from \"%s\" [%s].",
|
||||
host, ip);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: acl.h,v 1.4 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: acl.h,v 1.5 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'acl.c' for detailed information.
|
||||
*
|
||||
@ -21,6 +21,7 @@
|
||||
typedef enum { ACL_ALLOW, ACL_DENY } acl_access_t;
|
||||
|
||||
extern int insert_acl(char *location, acl_access_t access_type);
|
||||
extern int check_acl(int fd, const char* ip_address, const char* string_address);
|
||||
extern int check_acl(int fd, const char *ip_address,
|
||||
const char *string_address);
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: anonymous.c,v 1.15 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: anonymous.c,v 1.16 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Handles insertion and searches for headers which should be let through when
|
||||
* the anonymous feature is turned on.
|
||||
@ -28,7 +28,7 @@ static hashmap_t anonymous_map = NULL;
|
||||
short int
|
||||
is_anonymous_enabled(void)
|
||||
{
|
||||
return (anonymous_map != NULL) ? 1 : 0;
|
||||
return (anonymous_map != NULL) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -38,10 +38,10 @@ is_anonymous_enabled(void)
|
||||
int
|
||||
anonymous_search(char *s)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(anonymous_map != NULL);
|
||||
assert(s != NULL);
|
||||
assert(anonymous_map != NULL);
|
||||
|
||||
return hashmap_search(anonymous_map, s);
|
||||
return hashmap_search(anonymous_map, s);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -53,21 +53,21 @@ anonymous_search(char *s)
|
||||
int
|
||||
anonymous_insert(char *s)
|
||||
{
|
||||
char data = 1;
|
||||
char data = 1;
|
||||
|
||||
assert(s != NULL);
|
||||
assert(s != NULL);
|
||||
|
||||
if (!anonymous_map) {
|
||||
anonymous_map = hashmap_create(32);
|
||||
if (!anonymous_map)
|
||||
return -1;
|
||||
}
|
||||
if (!anonymous_map) {
|
||||
anonymous_map = hashmap_create(32);
|
||||
if (!anonymous_map)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hashmap_search(anonymous_map, s) > 0) {
|
||||
/* The key was already found, so return a positive number. */
|
||||
return 0;
|
||||
}
|
||||
if (hashmap_search(anonymous_map, s) > 0) {
|
||||
/* The key was already found, so return a positive number. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Insert the new key */
|
||||
return hashmap_insert(anonymous_map, s, &data, sizeof(data));
|
||||
/* Insert the new key */
|
||||
return hashmap_insert(anonymous_map, s, &data, sizeof(data));
|
||||
}
|
||||
|
308
src/buffer.c
308
src/buffer.c
@ -1,4 +1,4 @@
|
||||
/* $Id: buffer.c,v 1.24 2004-02-13 21:27:42 rjkaes Exp $
|
||||
/* $Id: buffer.c,v 1.25 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* The buffer used in each connection is a linked list of lines. As the lines
|
||||
* are read in and written out the buffer expands and contracts. Basically,
|
||||
@ -31,10 +31,10 @@
|
||||
#define BUFFER_TAIL(x) (x)->tail
|
||||
|
||||
struct bufline_s {
|
||||
unsigned char *string; /* the actual string of data */
|
||||
struct bufline_s *next; /* pointer to next in linked list */
|
||||
size_t length; /* length of the string of data */
|
||||
size_t pos; /* start sending from this offset */
|
||||
unsigned char *string; /* the actual string of data */
|
||||
struct bufline_s *next; /* pointer to next in linked list */
|
||||
size_t length; /* length of the string of data */
|
||||
size_t pos; /* start sending from this offset */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -42,9 +42,9 @@ struct bufline_s {
|
||||
* (and includes the total size)
|
||||
*/
|
||||
struct buffer_s {
|
||||
struct bufline_s *head; /* top of the buffer */
|
||||
struct bufline_s *tail; /* bottom of the buffer */
|
||||
size_t size; /* total size of the buffer */
|
||||
struct bufline_s *head; /* top of the buffer */
|
||||
struct bufline_s *tail; /* bottom of the buffer */
|
||||
size_t size; /* total size of the buffer */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -55,28 +55,28 @@ struct buffer_s {
|
||||
static struct bufline_s *
|
||||
makenewline(unsigned char *data, size_t length)
|
||||
{
|
||||
struct bufline_s *newline;
|
||||
struct bufline_s *newline;
|
||||
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
if (!(newline = safemalloc(sizeof(struct bufline_s))))
|
||||
return NULL;
|
||||
if (!(newline = safemalloc(sizeof(struct bufline_s))))
|
||||
return NULL;
|
||||
|
||||
if (!(newline->string = safemalloc(length))) {
|
||||
safefree(newline);
|
||||
return NULL;
|
||||
}
|
||||
if (!(newline->string = safemalloc(length))) {
|
||||
safefree(newline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(newline->string, data, length);
|
||||
memcpy(newline->string, data, length);
|
||||
|
||||
newline->next = NULL;
|
||||
newline->length = length;
|
||||
newline->next = NULL;
|
||||
newline->length = length;
|
||||
|
||||
/* Position our "read" pointer at the beginning of the data */
|
||||
newline->pos = 0;
|
||||
/* Position our "read" pointer at the beginning of the data */
|
||||
newline->pos = 0;
|
||||
|
||||
return newline;
|
||||
return newline;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -85,15 +85,15 @@ makenewline(unsigned char *data, size_t length)
|
||||
static void
|
||||
free_line(struct bufline_s *line)
|
||||
{
|
||||
assert(line != NULL);
|
||||
assert(line != NULL);
|
||||
|
||||
if (!line)
|
||||
return;
|
||||
if (!line)
|
||||
return;
|
||||
|
||||
if (line->string)
|
||||
safefree(line->string);
|
||||
if (line->string)
|
||||
safefree(line->string);
|
||||
|
||||
safefree(line);
|
||||
safefree(line);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -102,20 +102,20 @@ free_line(struct bufline_s *line)
|
||||
struct buffer_s *
|
||||
new_buffer(void)
|
||||
{
|
||||
struct buffer_s *buffptr;
|
||||
struct buffer_s *buffptr;
|
||||
|
||||
if (!(buffptr = safemalloc(sizeof(struct buffer_s))))
|
||||
return NULL;
|
||||
if (!(buffptr = safemalloc(sizeof(struct buffer_s))))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Since the buffer is initially empty, set the HEAD and TAIL
|
||||
* pointers to NULL since they can't possibly point anywhere at the
|
||||
* moment.
|
||||
*/
|
||||
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = NULL;
|
||||
buffptr->size = 0;
|
||||
/*
|
||||
* Since the buffer is initially empty, set the HEAD and TAIL
|
||||
* pointers to NULL since they can't possibly point anywhere at the
|
||||
* moment.
|
||||
*/
|
||||
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = NULL;
|
||||
buffptr->size = 0;
|
||||
|
||||
return buffptr;
|
||||
return buffptr;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -124,25 +124,26 @@ new_buffer(void)
|
||||
void
|
||||
delete_buffer(struct buffer_s *buffptr)
|
||||
{
|
||||
struct bufline_s *next;
|
||||
struct bufline_s *next;
|
||||
|
||||
assert(buffptr != NULL);
|
||||
assert(buffptr != NULL);
|
||||
|
||||
while (BUFFER_HEAD(buffptr)) {
|
||||
next = BUFFER_HEAD(buffptr)->next;
|
||||
free_line(BUFFER_HEAD(buffptr));
|
||||
BUFFER_HEAD(buffptr) = next;
|
||||
}
|
||||
while (BUFFER_HEAD(buffptr)) {
|
||||
next = BUFFER_HEAD(buffptr)->next;
|
||||
free_line(BUFFER_HEAD(buffptr));
|
||||
BUFFER_HEAD(buffptr) = next;
|
||||
}
|
||||
|
||||
safefree(buffptr);
|
||||
safefree(buffptr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the current size of the buffer.
|
||||
*/
|
||||
size_t buffer_size(struct buffer_s *buffptr)
|
||||
size_t
|
||||
buffer_size(struct buffer_s *buffptr)
|
||||
{
|
||||
return buffptr->size;
|
||||
return buffptr->size;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -151,37 +152,37 @@ size_t buffer_size(struct buffer_s *buffptr)
|
||||
int
|
||||
add_to_buffer(struct buffer_s *buffptr, unsigned char *data, size_t length)
|
||||
{
|
||||
struct bufline_s *newline;
|
||||
struct bufline_s *newline;
|
||||
|
||||
assert(buffptr != NULL);
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
assert(buffptr != NULL);
|
||||
assert(data != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
/*
|
||||
* Sanity check here. A buffer with a non-NULL head pointer must
|
||||
* have a size greater than zero, and vice-versa.
|
||||
*/
|
||||
if (BUFFER_HEAD(buffptr) == NULL)
|
||||
assert(buffptr->size == 0);
|
||||
else
|
||||
assert(buffptr->size > 0);
|
||||
/*
|
||||
* Sanity check here. A buffer with a non-NULL head pointer must
|
||||
* have a size greater than zero, and vice-versa.
|
||||
*/
|
||||
if (BUFFER_HEAD(buffptr) == NULL)
|
||||
assert(buffptr->size == 0);
|
||||
else
|
||||
assert(buffptr->size > 0);
|
||||
|
||||
/*
|
||||
* Make a new line so we can add it to the buffer.
|
||||
*/
|
||||
if (!(newline = makenewline(data, length)))
|
||||
return -1;
|
||||
/*
|
||||
* Make a new line so we can add it to the buffer.
|
||||
*/
|
||||
if (!(newline = makenewline(data, length)))
|
||||
return -1;
|
||||
|
||||
if (buffptr->size == 0)
|
||||
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = newline;
|
||||
else {
|
||||
BUFFER_TAIL(buffptr)->next = newline;
|
||||
BUFFER_TAIL(buffptr) = newline;
|
||||
}
|
||||
if (buffptr->size == 0)
|
||||
BUFFER_HEAD(buffptr) = BUFFER_TAIL(buffptr) = newline;
|
||||
else {
|
||||
BUFFER_TAIL(buffptr)->next = newline;
|
||||
BUFFER_TAIL(buffptr) = newline;
|
||||
}
|
||||
|
||||
buffptr->size += length;
|
||||
buffptr->size += length;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -190,17 +191,17 @@ add_to_buffer(struct buffer_s *buffptr, unsigned char *data, size_t length)
|
||||
static struct bufline_s *
|
||||
remove_from_buffer(struct buffer_s *buffptr)
|
||||
{
|
||||
struct bufline_s *line;
|
||||
struct bufline_s *line;
|
||||
|
||||
assert(buffptr != NULL);
|
||||
assert(BUFFER_HEAD(buffptr) != NULL);
|
||||
assert(buffptr != NULL);
|
||||
assert(BUFFER_HEAD(buffptr) != NULL);
|
||||
|
||||
line = BUFFER_HEAD(buffptr);
|
||||
BUFFER_HEAD(buffptr) = line->next;
|
||||
line = BUFFER_HEAD(buffptr);
|
||||
BUFFER_HEAD(buffptr) = line->next;
|
||||
|
||||
buffptr->size -= line->length;
|
||||
buffptr->size -= line->length;
|
||||
|
||||
return line;
|
||||
return line;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -211,51 +212,51 @@ remove_from_buffer(struct buffer_s *buffptr)
|
||||
ssize_t
|
||||
read_buffer(int fd, struct buffer_s * buffptr)
|
||||
{
|
||||
ssize_t bytesin;
|
||||
unsigned char buffer[READ_BUFFER_SIZE];
|
||||
ssize_t bytesin;
|
||||
unsigned char buffer[READ_BUFFER_SIZE];
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(buffptr != NULL);
|
||||
assert(fd >= 0);
|
||||
assert(buffptr != NULL);
|
||||
|
||||
/*
|
||||
* Don't allow the buffer to grow larger than MAXBUFFSIZE
|
||||
*/
|
||||
if (buffptr->size >= MAXBUFFSIZE)
|
||||
return 0;
|
||||
/*
|
||||
* Don't allow the buffer to grow larger than MAXBUFFSIZE
|
||||
*/
|
||||
if (buffptr->size >= MAXBUFFSIZE)
|
||||
return 0;
|
||||
|
||||
bytesin = read(fd, buffer, READ_BUFFER_SIZE);
|
||||
bytesin = read(fd, buffer, READ_BUFFER_SIZE);
|
||||
|
||||
if (bytesin > 0) {
|
||||
if (add_to_buffer(buffptr, buffer, bytesin) < 0) {
|
||||
log_message(LOG_ERR,
|
||||
"readbuff: add_to_buffer() error.");
|
||||
return -1;
|
||||
}
|
||||
if (bytesin > 0) {
|
||||
if (add_to_buffer(buffptr, buffer, bytesin) < 0) {
|
||||
log_message(LOG_ERR,
|
||||
"readbuff: add_to_buffer() error.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return bytesin;
|
||||
} else {
|
||||
if (bytesin == 0) {
|
||||
/* connection was closed by client */
|
||||
return -1;
|
||||
} else {
|
||||
switch (errno) {
|
||||
return bytesin;
|
||||
} else {
|
||||
if (bytesin == 0) {
|
||||
/* connection was closed by client */
|
||||
return -1;
|
||||
} else {
|
||||
switch (errno) {
|
||||
#ifdef EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
case EWOULDBLOCK:
|
||||
#else
|
||||
# ifdef EAGAIN
|
||||
case EAGAIN:
|
||||
case EAGAIN:
|
||||
# endif
|
||||
#endif
|
||||
case EINTR:
|
||||
return 0;
|
||||
default:
|
||||
log_message(LOG_ERR,
|
||||
"readbuff: recv() error \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
case EINTR:
|
||||
return 0;
|
||||
default:
|
||||
log_message(LOG_ERR,
|
||||
"readbuff: recv() error \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -265,50 +266,51 @@ read_buffer(int fd, struct buffer_s * buffptr)
|
||||
ssize_t
|
||||
write_buffer(int fd, struct buffer_s * buffptr)
|
||||
{
|
||||
ssize_t bytessent;
|
||||
struct bufline_s *line;
|
||||
ssize_t bytessent;
|
||||
struct bufline_s *line;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(buffptr != NULL);
|
||||
assert(fd >= 0);
|
||||
assert(buffptr != NULL);
|
||||
|
||||
if (buffptr->size == 0)
|
||||
return 0;
|
||||
if (buffptr->size == 0)
|
||||
return 0;
|
||||
|
||||
/* Sanity check. It would be bad to be using a NULL pointer! */
|
||||
assert(BUFFER_HEAD(buffptr) != NULL);
|
||||
line = BUFFER_HEAD(buffptr);
|
||||
/* Sanity check. It would be bad to be using a NULL pointer! */
|
||||
assert(BUFFER_HEAD(buffptr) != NULL);
|
||||
line = BUFFER_HEAD(buffptr);
|
||||
|
||||
bytessent =
|
||||
send(fd, line->string + line->pos, line->length - line->pos, MSG_NOSIGNAL);
|
||||
bytessent =
|
||||
send(fd, line->string + line->pos, line->length - line->pos,
|
||||
MSG_NOSIGNAL);
|
||||
|
||||
if (bytessent >= 0) {
|
||||
/* bytes sent, adjust buffer */
|
||||
line->pos += bytessent;
|
||||
if (line->pos == line->length)
|
||||
free_line(remove_from_buffer(buffptr));
|
||||
return bytessent;
|
||||
} else {
|
||||
switch (errno) {
|
||||
if (bytessent >= 0) {
|
||||
/* bytes sent, adjust buffer */
|
||||
line->pos += bytessent;
|
||||
if (line->pos == line->length)
|
||||
free_line(remove_from_buffer(buffptr));
|
||||
return bytessent;
|
||||
} else {
|
||||
switch (errno) {
|
||||
#ifdef EWOULDBLOCK
|
||||
case EWOULDBLOCK:
|
||||
case EWOULDBLOCK:
|
||||
#else
|
||||
# ifdef EAGAIN
|
||||
case EAGAIN:
|
||||
case EAGAIN:
|
||||
# endif
|
||||
#endif
|
||||
case EINTR:
|
||||
return 0;
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
log_message(LOG_ERR,
|
||||
"writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return 0;
|
||||
default:
|
||||
log_message(LOG_ERR,
|
||||
"writebuff: write() error \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
case EINTR:
|
||||
return 0;
|
||||
case ENOBUFS:
|
||||
case ENOMEM:
|
||||
log_message(LOG_ERR,
|
||||
"writebuff: write() error [NOBUFS/NOMEM] \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return 0;
|
||||
default:
|
||||
log_message(LOG_ERR,
|
||||
"writebuff: write() error \"%s\" on file descriptor %d",
|
||||
strerror(errno), fd);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: buffer.h,v 1.9 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: buffer.h,v 1.10 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'buffer.c' for a detailed description.
|
||||
*
|
||||
@ -29,9 +29,9 @@ extern size_t buffer_size(struct buffer_s *buffptr);
|
||||
* Add a new line to the given buffer. The data IS copied into the structure.
|
||||
*/
|
||||
extern int add_to_buffer(struct buffer_s *buffptr, unsigned char *data,
|
||||
size_t length);
|
||||
size_t length);
|
||||
|
||||
extern ssize_t read_buffer(int fd, struct buffer_s *buffptr);
|
||||
extern ssize_t write_buffer(int fd, struct buffer_s *buffptr);
|
||||
|
||||
#endif /* __BUFFER_H_ */
|
||||
#endif /* __BUFFER_H_ */
|
||||
|
483
src/child.c
483
src/child.c
@ -1,4 +1,4 @@
|
||||
/* $Id: child.c,v 1.17 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: child.c,v 1.18 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Handles the creation/destruction of the various children required for
|
||||
* processing incoming connections.
|
||||
@ -35,9 +35,9 @@ static socklen_t addrlen;
|
||||
*/
|
||||
enum child_status_t { T_EMPTY, T_WAITING, T_CONNECTED };
|
||||
struct child_s {
|
||||
pid_t tid;
|
||||
unsigned int connects;
|
||||
enum child_status_t status;
|
||||
pid_t tid;
|
||||
unsigned int connects;
|
||||
enum child_status_t status;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -47,11 +47,11 @@ struct child_s {
|
||||
static struct child_s *child_ptr;
|
||||
|
||||
static struct child_config_s {
|
||||
int maxclients, maxrequestsperchild;
|
||||
int maxspareservers, minspareservers, startservers;
|
||||
int maxclients, maxrequestsperchild;
|
||||
int maxspareservers, minspareservers, startservers;
|
||||
} child_config;
|
||||
|
||||
static unsigned int* servers_waiting; /* servers waiting for a connection */
|
||||
static unsigned int *servers_waiting; /* servers waiting for a connection */
|
||||
|
||||
/*
|
||||
* Lock/Unlock the "servers_waiting" variable so that two children cannot
|
||||
@ -72,40 +72,40 @@ static int lock_fd = -1;
|
||||
static void
|
||||
_child_lock_init(void)
|
||||
{
|
||||
char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX";
|
||||
char lock_file[] = "/tmp/tinyproxy.servers.lock.XXXXXX";
|
||||
|
||||
lock_fd = mkstemp(lock_file);
|
||||
unlink(lock_file);
|
||||
lock_fd = mkstemp(lock_file);
|
||||
unlink(lock_file);
|
||||
|
||||
lock_it.l_type = F_WRLCK;
|
||||
lock_it.l_whence = SEEK_SET;
|
||||
lock_it.l_start = 0;
|
||||
lock_it.l_len = 0;
|
||||
lock_it.l_type = F_WRLCK;
|
||||
lock_it.l_whence = SEEK_SET;
|
||||
lock_it.l_start = 0;
|
||||
lock_it.l_len = 0;
|
||||
|
||||
unlock_it.l_type = F_UNLCK;
|
||||
unlock_it.l_whence = SEEK_SET;
|
||||
unlock_it.l_start = 0;
|
||||
unlock_it.l_len = 0;
|
||||
unlock_it.l_type = F_UNLCK;
|
||||
unlock_it.l_whence = SEEK_SET;
|
||||
unlock_it.l_start = 0;
|
||||
unlock_it.l_len = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_child_lock_wait(void)
|
||||
{
|
||||
int rc;
|
||||
int rc;
|
||||
|
||||
while ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return;
|
||||
}
|
||||
while ((rc = fcntl(lock_fd, F_SETLKW, &lock_it)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_child_lock_release(void)
|
||||
{
|
||||
if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
|
||||
return;
|
||||
if (fcntl(lock_fd, F_SETLKW, &unlock_it) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
/* END OF LOCKING SECTION */
|
||||
@ -131,119 +131,124 @@ _child_lock_release(void)
|
||||
short int
|
||||
child_configure(child_config_t type, int val)
|
||||
{
|
||||
switch (type) {
|
||||
case CHILD_MAXCLIENTS:
|
||||
child_config.maxclients = val;
|
||||
break;
|
||||
case CHILD_MAXSPARESERVERS:
|
||||
child_config.maxspareservers = val;
|
||||
break;
|
||||
case CHILD_MINSPARESERVERS:
|
||||
child_config.minspareservers = val;
|
||||
break;
|
||||
case CHILD_STARTSERVERS:
|
||||
child_config.startservers = val;
|
||||
break;
|
||||
case CHILD_MAXREQUESTSPERCHILD:
|
||||
child_config.maxrequestsperchild = val;
|
||||
break;
|
||||
default:
|
||||
DEBUG2("Invalid type (%d)", type);
|
||||
return -1;
|
||||
}
|
||||
switch (type) {
|
||||
case CHILD_MAXCLIENTS:
|
||||
child_config.maxclients = val;
|
||||
break;
|
||||
case CHILD_MAXSPARESERVERS:
|
||||
child_config.maxspareservers = val;
|
||||
break;
|
||||
case CHILD_MINSPARESERVERS:
|
||||
child_config.minspareservers = val;
|
||||
break;
|
||||
case CHILD_STARTSERVERS:
|
||||
child_config.startservers = val;
|
||||
break;
|
||||
case CHILD_MAXREQUESTSPERCHILD:
|
||||
child_config.maxrequestsperchild = val;
|
||||
break;
|
||||
default:
|
||||
DEBUG2("Invalid type (%d)", type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main (per child) loop.
|
||||
*/
|
||||
static void
|
||||
child_main(struct child_s* ptr)
|
||||
child_main(struct child_s *ptr)
|
||||
{
|
||||
int connfd;
|
||||
struct sockaddr *cliaddr;
|
||||
socklen_t clilen;
|
||||
int connfd;
|
||||
struct sockaddr *cliaddr;
|
||||
socklen_t clilen;
|
||||
|
||||
cliaddr = safemalloc(addrlen);
|
||||
if (!cliaddr) {
|
||||
log_message(LOG_CRIT,
|
||||
"Could not allocate memory for child address.");
|
||||
exit(0);
|
||||
}
|
||||
cliaddr = safemalloc(addrlen);
|
||||
if (!cliaddr) {
|
||||
log_message(LOG_CRIT,
|
||||
"Could not allocate memory for child address.");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ptr->connects = 0;
|
||||
ptr->connects = 0;
|
||||
|
||||
while (!config.quit) {
|
||||
ptr->status = T_WAITING;
|
||||
while (!config.quit) {
|
||||
ptr->status = T_WAITING;
|
||||
|
||||
clilen = addrlen;
|
||||
clilen = addrlen;
|
||||
|
||||
connfd = accept(listenfd, cliaddr, &clilen);
|
||||
connfd = accept(listenfd, cliaddr, &clilen);
|
||||
|
||||
#ifndef NDEBUG
|
||||
/*
|
||||
* Enable the TINYPROXY_DEBUG environment variable if you
|
||||
* want to use the GDB debugger.
|
||||
*/
|
||||
if (getenv("TINYPROXY_DEBUG")) {
|
||||
/* Pause for 10 seconds to allow us to connect debugger */
|
||||
fprintf(stderr,
|
||||
"Process has accepted connection: %ld\n", (long int)ptr->tid);
|
||||
sleep(10);
|
||||
fprintf(stderr, "Continuing process: %ld\n", (long int)ptr->tid);
|
||||
}
|
||||
/*
|
||||
* Enable the TINYPROXY_DEBUG environment variable if you
|
||||
* want to use the GDB debugger.
|
||||
*/
|
||||
if (getenv("TINYPROXY_DEBUG")) {
|
||||
/* Pause for 10 seconds to allow us to connect debugger */
|
||||
fprintf(stderr,
|
||||
"Process has accepted connection: %ld\n",
|
||||
(long int)ptr->tid);
|
||||
sleep(10);
|
||||
fprintf(stderr, "Continuing process: %ld\n",
|
||||
(long int)ptr->tid);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Make sure no error occurred...
|
||||
*/
|
||||
if (connfd < 0) {
|
||||
log_message(LOG_ERR, "Accept returned an error (%s) ... retrying.", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Make sure no error occurred...
|
||||
*/
|
||||
if (connfd < 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Accept returned an error (%s) ... retrying.",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr->status = T_CONNECTED;
|
||||
ptr->status = T_CONNECTED;
|
||||
|
||||
SERVER_DEC();
|
||||
SERVER_DEC();
|
||||
|
||||
handle_connection(connfd);
|
||||
ptr->connects++;
|
||||
handle_connection(connfd);
|
||||
ptr->connects++;
|
||||
|
||||
if (child_config.maxrequestsperchild != 0) {
|
||||
DEBUG2("%u connections so far...", ptr->connects);
|
||||
if (child_config.maxrequestsperchild != 0) {
|
||||
DEBUG2("%u connections so far...", ptr->connects);
|
||||
|
||||
if (ptr->connects == child_config.maxrequestsperchild) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Child has reached MaxRequestsPerChild (%u). Killing child.",
|
||||
ptr->connects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ptr->connects == child_config.maxrequestsperchild) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Child has reached MaxRequestsPerChild (%u). Killing child.",
|
||||
ptr->connects);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SERVER_COUNT_LOCK();
|
||||
if (*servers_waiting > child_config.maxspareservers) {
|
||||
/*
|
||||
* There are too many spare children, kill ourself
|
||||
* off.
|
||||
*/
|
||||
log_message(LOG_NOTICE,
|
||||
"Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.",
|
||||
*servers_waiting, child_config.maxspareservers);
|
||||
SERVER_COUNT_UNLOCK();
|
||||
SERVER_COUNT_LOCK();
|
||||
if (*servers_waiting > child_config.maxspareservers) {
|
||||
/*
|
||||
* There are too many spare children, kill ourself
|
||||
* off.
|
||||
*/
|
||||
log_message(LOG_NOTICE,
|
||||
"Waiting servers (%d) exceeds MaxSpareServers (%d). Killing child.",
|
||||
*servers_waiting,
|
||||
child_config.maxspareservers);
|
||||
SERVER_COUNT_UNLOCK();
|
||||
|
||||
break;
|
||||
} else {
|
||||
SERVER_COUNT_UNLOCK();
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
SERVER_COUNT_UNLOCK();
|
||||
}
|
||||
|
||||
SERVER_INC();
|
||||
}
|
||||
SERVER_INC();
|
||||
}
|
||||
|
||||
ptr->status = T_EMPTY;
|
||||
ptr->status = T_EMPTY;
|
||||
|
||||
safefree(cliaddr);
|
||||
exit(0);
|
||||
safefree(cliaddr);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -251,22 +256,22 @@ child_main(struct child_s* ptr)
|
||||
* child_main() function.
|
||||
*/
|
||||
static pid_t
|
||||
child_make(struct child_s* ptr)
|
||||
child_make(struct child_s *ptr)
|
||||
{
|
||||
pid_t pid;
|
||||
|
||||
if ((pid = fork()) > 0)
|
||||
return pid; /* parent */
|
||||
pid_t pid;
|
||||
|
||||
/*
|
||||
* Reset the SIGNALS so that the child can be reaped.
|
||||
*/
|
||||
set_signal_handler(SIGCHLD, SIG_DFL);
|
||||
set_signal_handler(SIGTERM, SIG_DFL);
|
||||
set_signal_handler(SIGHUP, SIG_DFL);
|
||||
if ((pid = fork()) > 0)
|
||||
return pid; /* parent */
|
||||
|
||||
child_main(ptr); /* never returns */
|
||||
return -1;
|
||||
/*
|
||||
* Reset the SIGNALS so that the child can be reaped.
|
||||
*/
|
||||
set_signal_handler(SIGCHLD, SIG_DFL);
|
||||
set_signal_handler(SIGTERM, SIG_DFL);
|
||||
set_signal_handler(SIGHUP, SIG_DFL);
|
||||
|
||||
child_main(ptr); /* never returns */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -275,78 +280,80 @@ child_make(struct child_s* ptr)
|
||||
short int
|
||||
child_pool_create(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Make sure the number of MaxClients is not zero, since this
|
||||
* variable determines the size of the array created for children
|
||||
* later on.
|
||||
*/
|
||||
if (child_config.maxclients == 0) {
|
||||
log_message(LOG_ERR,
|
||||
"child_pool_create: \"MaxClients\" must be greater than zero.");
|
||||
return -1;
|
||||
}
|
||||
if (child_config.startservers == 0) {
|
||||
log_message(LOG_ERR,
|
||||
"child_pool_create: \"StartServers\" must be greater than zero.");
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Make sure the number of MaxClients is not zero, since this
|
||||
* variable determines the size of the array created for children
|
||||
* later on.
|
||||
*/
|
||||
if (child_config.maxclients == 0) {
|
||||
log_message(LOG_ERR,
|
||||
"child_pool_create: \"MaxClients\" must be greater than zero.");
|
||||
return -1;
|
||||
}
|
||||
if (child_config.startservers == 0) {
|
||||
log_message(LOG_ERR,
|
||||
"child_pool_create: \"StartServers\" must be greater than zero.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
child_ptr = calloc_shared_memory(child_config.maxclients,
|
||||
sizeof(struct child_s));
|
||||
if (!child_ptr) {
|
||||
log_message(LOG_ERR, "Could not allocate memory for children.");
|
||||
return -1;
|
||||
}
|
||||
child_ptr = calloc_shared_memory(child_config.maxclients,
|
||||
sizeof(struct child_s));
|
||||
if (!child_ptr) {
|
||||
log_message(LOG_ERR, "Could not allocate memory for children.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
servers_waiting = malloc_shared_memory(sizeof(unsigned int));
|
||||
if (servers_waiting == MAP_FAILED) {
|
||||
log_message(LOG_ERR, "Could not allocate memory for child counting.");
|
||||
return -1;
|
||||
}
|
||||
*servers_waiting = 0;
|
||||
servers_waiting = malloc_shared_memory(sizeof(unsigned int));
|
||||
if (servers_waiting == MAP_FAILED) {
|
||||
log_message(LOG_ERR,
|
||||
"Could not allocate memory for child counting.");
|
||||
return -1;
|
||||
}
|
||||
*servers_waiting = 0;
|
||||
|
||||
/*
|
||||
* Create a "locking" file for use around the servers_waiting
|
||||
* variable.
|
||||
*/
|
||||
_child_lock_init();
|
||||
/*
|
||||
* Create a "locking" file for use around the servers_waiting
|
||||
* variable.
|
||||
*/
|
||||
_child_lock_init();
|
||||
|
||||
if (child_config.startservers > child_config.maxclients) {
|
||||
log_message(LOG_WARNING,
|
||||
"Can not start more than \"MaxClients\" servers. Starting %u servers instead.",
|
||||
child_config.maxclients);
|
||||
child_config.startservers = child_config.maxclients;
|
||||
}
|
||||
if (child_config.startservers > child_config.maxclients) {
|
||||
log_message(LOG_WARNING,
|
||||
"Can not start more than \"MaxClients\" servers. Starting %u servers instead.",
|
||||
child_config.maxclients);
|
||||
child_config.startservers = child_config.maxclients;
|
||||
}
|
||||
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
child_ptr[i].status = T_EMPTY;
|
||||
child_ptr[i].connects = 0;
|
||||
}
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
child_ptr[i].status = T_EMPTY;
|
||||
child_ptr[i].connects = 0;
|
||||
}
|
||||
|
||||
for (i = 0; i != child_config.startservers; i++) {
|
||||
DEBUG2("Trying to create child %d of %d", i + 1, child_config.startservers);
|
||||
child_ptr[i].status = T_WAITING;
|
||||
child_ptr[i].tid = child_make(&child_ptr[i]);
|
||||
for (i = 0; i != child_config.startservers; i++) {
|
||||
DEBUG2("Trying to create child %d of %d", i + 1,
|
||||
child_config.startservers);
|
||||
child_ptr[i].status = T_WAITING;
|
||||
child_ptr[i].tid = child_make(&child_ptr[i]);
|
||||
|
||||
if (child_ptr[i].tid < 0) {
|
||||
log_message(LOG_WARNING,
|
||||
"Could not create child number %d of %d",
|
||||
i, child_config.startservers);
|
||||
return -1;
|
||||
} else {
|
||||
log_message(LOG_INFO,
|
||||
"Creating child number %d of %d ...",
|
||||
i + 1, child_config.startservers);
|
||||
if (child_ptr[i].tid < 0) {
|
||||
log_message(LOG_WARNING,
|
||||
"Could not create child number %d of %d",
|
||||
i, child_config.startservers);
|
||||
return -1;
|
||||
} else {
|
||||
log_message(LOG_INFO,
|
||||
"Creating child number %d of %d ...",
|
||||
i + 1, child_config.startservers);
|
||||
|
||||
SERVER_INC();
|
||||
}
|
||||
}
|
||||
SERVER_INC();
|
||||
}
|
||||
}
|
||||
|
||||
log_message(LOG_INFO, "Finished creating all children.");
|
||||
log_message(LOG_INFO, "Finished creating all children.");
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -356,59 +363,61 @@ child_pool_create(void)
|
||||
void
|
||||
child_main_loop(void)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int i;
|
||||
|
||||
while (1) {
|
||||
if (config.quit)
|
||||
return;
|
||||
while (1) {
|
||||
if (config.quit)
|
||||
return;
|
||||
|
||||
/* If there are not enough spare servers, create more */
|
||||
SERVER_COUNT_LOCK();
|
||||
if (*servers_waiting < child_config.minspareservers) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.",
|
||||
*servers_waiting, child_config.minspareservers);
|
||||
/* If there are not enough spare servers, create more */
|
||||
SERVER_COUNT_LOCK();
|
||||
if (*servers_waiting < child_config.minspareservers) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Waiting servers (%d) is less than MinSpareServers (%d). Creating new child.",
|
||||
*servers_waiting,
|
||||
child_config.minspareservers);
|
||||
|
||||
SERVER_COUNT_UNLOCK();
|
||||
SERVER_COUNT_UNLOCK();
|
||||
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
if (child_ptr[i].status == T_EMPTY) {
|
||||
child_ptr[i].status = T_WAITING;
|
||||
child_ptr[i].tid = child_make(&child_ptr[i]);
|
||||
if (child_ptr[i].tid < 0) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Could not create child");
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
if (child_ptr[i].status == T_EMPTY) {
|
||||
child_ptr[i].status = T_WAITING;
|
||||
child_ptr[i].tid =
|
||||
child_make(&child_ptr[i]);
|
||||
if (child_ptr[i].tid < 0) {
|
||||
log_message(LOG_NOTICE,
|
||||
"Could not create child");
|
||||
|
||||
child_ptr[i].status = T_EMPTY;
|
||||
break;
|
||||
}
|
||||
child_ptr[i].status = T_EMPTY;
|
||||
break;
|
||||
}
|
||||
|
||||
SERVER_INC();
|
||||
SERVER_INC();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SERVER_COUNT_UNLOCK();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SERVER_COUNT_UNLOCK();
|
||||
}
|
||||
|
||||
sleep(5);
|
||||
sleep(5);
|
||||
|
||||
/* Handle log rotation if it was requested */
|
||||
if (received_sighup) {
|
||||
truncate_log_file();
|
||||
/* Handle log rotation if it was requested */
|
||||
if (received_sighup) {
|
||||
truncate_log_file();
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
if (config.filter) {
|
||||
filter_destroy();
|
||||
filter_init();
|
||||
}
|
||||
log_message(LOG_NOTICE, "Re-reading filter file.");
|
||||
#endif /* FILTER_ENABLE */
|
||||
if (config.filter) {
|
||||
filter_destroy();
|
||||
filter_init();
|
||||
}
|
||||
log_message(LOG_NOTICE, "Re-reading filter file.");
|
||||
#endif /* FILTER_ENABLE */
|
||||
|
||||
received_sighup = FALSE;
|
||||
}
|
||||
}
|
||||
received_sighup = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -417,23 +426,23 @@ child_main_loop(void)
|
||||
void
|
||||
child_kill_children(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
if (child_ptr[i].status != T_EMPTY)
|
||||
kill(child_ptr[i].tid, SIGTERM);
|
||||
}
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i != child_config.maxclients; i++) {
|
||||
if (child_ptr[i].status != T_EMPTY)
|
||||
kill(child_ptr[i].tid, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
child_listening_sock(uint16_t port)
|
||||
{
|
||||
listenfd = listen_sock(port, &addrlen);
|
||||
return listenfd;
|
||||
listenfd = listen_sock(port, &addrlen);
|
||||
return listenfd;
|
||||
}
|
||||
|
||||
void
|
||||
child_close_sock(void)
|
||||
{
|
||||
close(listenfd);
|
||||
close(listenfd);
|
||||
}
|
||||
|
12
src/child.h
12
src/child.h
@ -1,4 +1,4 @@
|
||||
/* $Id: child.h,v 1.3 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: child.h,v 1.4 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'child.c' for more information.
|
||||
*
|
||||
@ -19,11 +19,11 @@
|
||||
#define TINYPROXY_CHILD_H
|
||||
|
||||
typedef enum {
|
||||
CHILD_MAXCLIENTS,
|
||||
CHILD_MAXSPARESERVERS,
|
||||
CHILD_MINSPARESERVERS,
|
||||
CHILD_STARTSERVERS,
|
||||
CHILD_MAXREQUESTSPERCHILD
|
||||
CHILD_MAXCLIENTS,
|
||||
CHILD_MAXSPARESERVERS,
|
||||
CHILD_MINSPARESERVERS,
|
||||
CHILD_STARTSERVERS,
|
||||
CHILD_MAXREQUESTSPERCHILD
|
||||
} child_config_t;
|
||||
|
||||
extern short int child_pool_create(void);
|
||||
|
12
src/common.h
12
src/common.h
@ -1,4 +1,4 @@
|
||||
/* $Id: common.h,v 1.8 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: common.h,v 1.9 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* This file groups all the headers required throughout the tinyproxy
|
||||
* system. All this information use to be in the "tinyproxy.h" header,
|
||||
@ -166,13 +166,13 @@
|
||||
# define MSG_NOSIGNAL (0)
|
||||
#endif
|
||||
|
||||
#ifndef SHUT_RD /* these three Posix.1g names are quite new */
|
||||
# define SHUT_RD 0 /* shutdown for reading */
|
||||
# define SHUT_WR 1 /* shutdown for writing */
|
||||
# define SHUT_RDWR 2 /* shutdown for reading and writing */
|
||||
#ifndef SHUT_RD /* these three Posix.1g names are quite new */
|
||||
# define SHUT_RD 0 /* shutdown for reading */
|
||||
# define SHUT_WR 1 /* shutdown for writing */
|
||||
# define SHUT_RDWR 2 /* shutdown for reading and writing */
|
||||
#endif
|
||||
|
||||
#define MAXLISTEN 1024 /* Max number of connections */
|
||||
#define MAXLISTEN 1024 /* Max number of connections */
|
||||
|
||||
/*
|
||||
* SunOS doesn't have INADDR_NONE defined.
|
||||
|
449
src/conffile.c
449
src/conffile.c
@ -1,4 +1,4 @@
|
||||
/* $Id: conffile.c,v 1.4 2004-08-24 16:34:22 rjkaes Exp $
|
||||
/* $Id: conffile.c,v 1.5 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Parses the configuration file and sets up the config_s structure for
|
||||
* use by the application. This file replaces the old grammar.y and
|
||||
@ -57,12 +57,11 @@
|
||||
*/
|
||||
#define RE_MAX_MATCHES 16
|
||||
|
||||
|
||||
/*
|
||||
* All configuration handling functions are REQUIRED to be defined
|
||||
* with the same function template as below.
|
||||
*/
|
||||
typedef int (*CONFFILE_HANDLER)(struct config_s*, const char*, regmatch_t[]);
|
||||
typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, regmatch_t[]);
|
||||
|
||||
/*
|
||||
* Define the pattern used by any directive handling function. The
|
||||
@ -77,12 +76,16 @@ typedef int (*CONFFILE_HANDLER)(struct config_s*, const char*, regmatch_t[]);
|
||||
*/
|
||||
#define HANDLE_FUNC(func) int func(struct config_s* conf, const char* line, regmatch_t match[])
|
||||
|
||||
|
||||
/*
|
||||
* List all the handling functions. These are defined later, but they need
|
||||
* to be in-scope before the big structure below.
|
||||
*/
|
||||
static HANDLE_FUNC(handle_nop) { return 0; } /* do nothing function */
|
||||
static
|
||||
HANDLE_FUNC(handle_nop)
|
||||
{
|
||||
return 0;
|
||||
} /* do nothing function */
|
||||
|
||||
static HANDLE_FUNC(handle_allow);
|
||||
static HANDLE_FUNC(handle_anonymous);
|
||||
static HANDLE_FUNC(handle_bind);
|
||||
@ -115,12 +118,12 @@ static HANDLE_FUNC(handle_statfile);
|
||||
static HANDLE_FUNC(handle_stathost);
|
||||
static HANDLE_FUNC(handle_syslog);
|
||||
static HANDLE_FUNC(handle_timeout);
|
||||
|
||||
//static HANDLE_FUNC(handle_upstream);
|
||||
static HANDLE_FUNC(handle_user);
|
||||
static HANDLE_FUNC(handle_viaproxyname);
|
||||
static HANDLE_FUNC(handle_xtinyproxy);
|
||||
|
||||
|
||||
/*
|
||||
* This macro can be used to make standard directives in the form:
|
||||
* directive arguments [arguments ...]
|
||||
@ -134,7 +137,6 @@ static HANDLE_FUNC(handle_xtinyproxy);
|
||||
*/
|
||||
#define STDCONF(d, re, func) { BEGIN "(" d ")" WS re END, func, NULL }
|
||||
|
||||
|
||||
/*
|
||||
* Holds the regular expression used to match the configuration directive,
|
||||
* the function pointer to the routine to handle the directive, and
|
||||
@ -142,74 +144,66 @@ static HANDLE_FUNC(handle_xtinyproxy);
|
||||
* to be compiled one.
|
||||
*/
|
||||
struct {
|
||||
const char* re;
|
||||
const char *re;
|
||||
CONFFILE_HANDLER handler;
|
||||
regex_t* cre;
|
||||
regex_t *cre;
|
||||
} directives[] = {
|
||||
/* comments */
|
||||
{ BEGIN "#", handle_nop },
|
||||
|
||||
/* blank lines */
|
||||
{ "^[[:space:]]+$", handle_nop },
|
||||
|
||||
/* string arguments */
|
||||
STDCONF("logfile", STR, handle_logfile),
|
||||
STDCONF("pidfile", STR, handle_pidfile),
|
||||
STDCONF("anonymous", STR, handle_anonymous),
|
||||
STDCONF("viaproxyname", STR, handle_viaproxyname),
|
||||
STDCONF("defaulterrorfile", STR, handle_defaulterrorfile),
|
||||
STDCONF("statfile", STR, handle_statfile),
|
||||
STDCONF("stathost", STR, handle_stathost),
|
||||
STDCONF("xtinyproxy", STR, handle_xtinyproxy),
|
||||
|
||||
/* boolean arguments */
|
||||
STDCONF("syslog", BOOL, handle_syslog),
|
||||
STDCONF("bindsame", BOOL, handle_bindsame),
|
||||
|
||||
/* integer arguments */
|
||||
STDCONF("port", INT, handle_port),
|
||||
STDCONF("maxclients", INT, handle_maxclients),
|
||||
STDCONF("maxspareservers", INT, handle_maxspareservers),
|
||||
STDCONF("minspareservers", INT, handle_minspareservers),
|
||||
STDCONF("startservers", INT, handle_startservers),
|
||||
STDCONF("maxrequestsperchild", INT, handle_maxrequestsperchild),
|
||||
STDCONF("timeout", INT, handle_timeout),
|
||||
STDCONF("connectport", INT, handle_connectport),
|
||||
|
||||
/* alphanumeric arguments */
|
||||
STDCONF("user", ALNUM, handle_user),
|
||||
STDCONF("group", ALNUM, handle_group),
|
||||
|
||||
/* ip arguments */
|
||||
STDCONF("listen", IP, handle_listen),
|
||||
STDCONF("allow", "(" IPMASK "|" ALNUM ")", handle_allow),
|
||||
STDCONF("deny", "(" IPMASK "|" ALNUM ")", handle_deny),
|
||||
STDCONF("bind", IP, handle_bind),
|
||||
|
||||
/* error files */
|
||||
STDCONF("errorfile", INT WS STR, handle_errorfile),
|
||||
|
||||
/* filtering */
|
||||
STDCONF("filter", STR, handle_filter),
|
||||
STDCONF("filterurls", BOOL, handle_filterurls),
|
||||
STDCONF("filterextended", BOOL, handle_filterextended),
|
||||
STDCONF("filterdefaultdeny", BOOL, handle_filterdefaultdeny),
|
||||
STDCONF("filtercasesensitive", BOOL, handle_filtercasesensitive),
|
||||
|
||||
/* Reverse proxy arguments */
|
||||
STDCONF("reversebaseurl", STR, handle_reversebaseurl),
|
||||
STDCONF("reverseonly", BOOL, handle_reverseonly),
|
||||
STDCONF("reversemagic", BOOL, handle_reversemagic),
|
||||
STDCONF("reversepath", STR WS "(" STR ")?", handle_reversepath),
|
||||
|
||||
/* upstream is rather complicated */
|
||||
{
|
||||
BEGIN "#", handle_nop},
|
||||
/* blank lines */
|
||||
{
|
||||
"^[[:space:]]+$", handle_nop},
|
||||
/* string arguments */
|
||||
STDCONF("logfile", STR, handle_logfile),
|
||||
STDCONF("pidfile", STR, handle_pidfile),
|
||||
STDCONF("anonymous", STR, handle_anonymous),
|
||||
STDCONF("viaproxyname", STR, handle_viaproxyname),
|
||||
STDCONF("defaulterrorfile", STR, handle_defaulterrorfile),
|
||||
STDCONF("statfile", STR, handle_statfile),
|
||||
STDCONF("stathost", STR, handle_stathost),
|
||||
STDCONF("xtinyproxy", STR, handle_xtinyproxy),
|
||||
/* boolean arguments */
|
||||
STDCONF("syslog", BOOL, handle_syslog),
|
||||
STDCONF("bindsame", BOOL, handle_bindsame),
|
||||
/* integer arguments */
|
||||
STDCONF("port", INT, handle_port),
|
||||
STDCONF("maxclients", INT, handle_maxclients),
|
||||
STDCONF("maxspareservers", INT, handle_maxspareservers),
|
||||
STDCONF("minspareservers", INT, handle_minspareservers),
|
||||
STDCONF("startservers", INT, handle_startservers),
|
||||
STDCONF("maxrequestsperchild", INT, handle_maxrequestsperchild),
|
||||
STDCONF("timeout", INT, handle_timeout),
|
||||
STDCONF("connectport", INT, handle_connectport),
|
||||
/* alphanumeric arguments */
|
||||
STDCONF("user", ALNUM, handle_user),
|
||||
STDCONF("group", ALNUM, handle_group),
|
||||
/* ip arguments */
|
||||
STDCONF("listen", IP, handle_listen),
|
||||
STDCONF("allow", "(" IPMASK "|" ALNUM ")", handle_allow),
|
||||
STDCONF("deny", "(" IPMASK "|" ALNUM ")", handle_deny),
|
||||
STDCONF("bind", IP, handle_bind),
|
||||
/* error files */
|
||||
STDCONF("errorfile", INT WS STR, handle_errorfile),
|
||||
/* filtering */
|
||||
STDCONF("filter", STR, handle_filter),
|
||||
STDCONF("filterurls", BOOL, handle_filterurls),
|
||||
STDCONF("filterextended", BOOL, handle_filterextended),
|
||||
STDCONF("filterdefaultdeny", BOOL, handle_filterdefaultdeny),
|
||||
STDCONF("filtercasesensitive", BOOL, handle_filtercasesensitive),
|
||||
/* Reverse proxy arguments */
|
||||
STDCONF("reversebaseurl", STR, handle_reversebaseurl),
|
||||
STDCONF("reverseonly", BOOL, handle_reverseonly),
|
||||
STDCONF("reversemagic", BOOL, handle_reversemagic),
|
||||
STDCONF("reversepath", STR WS "(" STR ")?", handle_reversepath),
|
||||
/* upstream is rather complicated */
|
||||
// { BEGIN "no" WS "upstream" WS STR END, handle_no_upstream },
|
||||
// { BEGIN "upstream" WS IP ":" INT "(" WS STR ")" END, handle_upstream },
|
||||
|
||||
/* loglevel */
|
||||
STDCONF("loglevel", "(critical|error|warning|notice|connect|info)", handle_loglevel)
|
||||
/* loglevel */
|
||||
STDCONF("loglevel", "(critical|error|warning|notice|connect|info)",
|
||||
handle_loglevel)
|
||||
};
|
||||
const unsigned int ndirectives = sizeof(directives)/sizeof(directives[0]);
|
||||
const unsigned int ndirectives = sizeof(directives) / sizeof(directives[0]);
|
||||
|
||||
/*
|
||||
* Compiles the regular expressions used by the configuration file. This
|
||||
@ -225,7 +219,7 @@ config_compile(void)
|
||||
for (i = 0; i != ndirectives; ++i) {
|
||||
assert(directives[i].handler);
|
||||
assert(!directives[i].cre);
|
||||
|
||||
|
||||
directives[i].cre = safemalloc(sizeof(regex_t));
|
||||
if (!directives[i].cre)
|
||||
return -1;
|
||||
@ -233,12 +227,12 @@ config_compile(void)
|
||||
r = regcomp(directives[i].cre,
|
||||
directives[i].re,
|
||||
REG_EXTENDED | REG_ICASE | REG_NEWLINE);
|
||||
if (r) return r;
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Attempt to match the supplied line with any of the configuration
|
||||
* regexes defined above. If a match is found, call the handler
|
||||
@ -248,7 +242,7 @@ config_compile(void)
|
||||
* a negative number is returned.
|
||||
*/
|
||||
static int
|
||||
check_match(struct config_s* conf, const char* line)
|
||||
check_match(struct config_s *conf, const char *line)
|
||||
{
|
||||
regmatch_t match[RE_MAX_MATCHES];
|
||||
unsigned int i;
|
||||
@ -258,7 +252,7 @@ check_match(struct config_s* conf, const char* line)
|
||||
for (i = 0; i != ndirectives; ++i) {
|
||||
assert(directives[i].cre);
|
||||
if (!regexec(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
|
||||
return (*directives[i].handler)(conf, line, match);
|
||||
return (*directives[i].handler) (conf, line, match);
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -268,9 +262,9 @@ check_match(struct config_s* conf, const char* line)
|
||||
* Parse the previously opened configuration stream.
|
||||
*/
|
||||
int
|
||||
config_parse(struct config_s* conf, FILE* f)
|
||||
config_parse(struct config_s *conf, FILE * f)
|
||||
{
|
||||
char buffer[1024]; /* 1KB lines should be plenty */
|
||||
char buffer[1024]; /* 1KB lines should be plenty */
|
||||
unsigned long lineno = 1;
|
||||
|
||||
while (fgets(buffer, sizeof(buffer), f)) {
|
||||
@ -283,7 +277,6 @@ config_parse(struct config_s* conf, FILE* f)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* The following are basic data extraction building blocks that can
|
||||
@ -291,15 +284,15 @@ config_parse(struct config_s* conf, FILE* f)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
static char*
|
||||
get_string_arg(const char* line, regmatch_t* match)
|
||||
static char *
|
||||
get_string_arg(const char *line, regmatch_t * match)
|
||||
{
|
||||
char *p;
|
||||
const unsigned int len = match->rm_eo - match->rm_so;
|
||||
|
||||
assert(line);
|
||||
assert(len > 0);
|
||||
|
||||
|
||||
p = safemalloc(len + 1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
@ -310,9 +303,10 @@ get_string_arg(const char* line, regmatch_t* match)
|
||||
}
|
||||
|
||||
static int
|
||||
set_string_arg(char** var, const char* line, regmatch_t* match)
|
||||
set_string_arg(char **var, const char *line, regmatch_t * match)
|
||||
{
|
||||
char* arg = get_string_arg(line, match);
|
||||
char *arg = get_string_arg(line, match);
|
||||
|
||||
if (!arg)
|
||||
return -1;
|
||||
*var = safestrdup(arg);
|
||||
@ -321,9 +315,9 @@ set_string_arg(char** var, const char* line, regmatch_t* match)
|
||||
}
|
||||
|
||||
static int
|
||||
get_bool_arg(const char* line, regmatch_t* match)
|
||||
get_bool_arg(const char *line, regmatch_t * match)
|
||||
{
|
||||
const char* p = line + match->rm_so;
|
||||
const char *p = line + match->rm_so;
|
||||
|
||||
assert(line);
|
||||
assert(match && match->rm_so != -1);
|
||||
@ -336,36 +330,35 @@ get_bool_arg(const char* line, regmatch_t* match)
|
||||
}
|
||||
|
||||
static int
|
||||
set_bool_arg(unsigned int* var, const char* line, regmatch_t* match)
|
||||
set_bool_arg(unsigned int *var, const char *line, regmatch_t * match)
|
||||
{
|
||||
assert(var);
|
||||
assert(line);
|
||||
assert(match && match->rm_so != -1);
|
||||
|
||||
|
||||
*var = get_bool_arg(line, match);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline long int
|
||||
get_int_arg(const char* line, regmatch_t* match)
|
||||
get_int_arg(const char *line, regmatch_t * match)
|
||||
{
|
||||
assert(line);
|
||||
assert(match && match->rm_so != -1);
|
||||
|
||||
|
||||
return strtol(line + match->rm_so, NULL, 0);
|
||||
}
|
||||
static int
|
||||
set_int_arg(int long* var, const char* line, regmatch_t* match)
|
||||
set_int_arg(int long *var, const char *line, regmatch_t * match)
|
||||
{
|
||||
assert(var);
|
||||
assert(line);
|
||||
assert(match);
|
||||
|
||||
|
||||
*var = get_int_arg(line, match);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
*
|
||||
* Below are all the directive handling functions. You will notice
|
||||
@ -384,17 +377,23 @@ set_int_arg(int long* var, const char* line, regmatch_t* match)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
static HANDLE_FUNC(handle_logfile)
|
||||
static
|
||||
HANDLE_FUNC(handle_logfile)
|
||||
{
|
||||
return set_string_arg(&conf->logf_name, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_pidfile)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_pidfile)
|
||||
{
|
||||
return set_string_arg(&conf->pidpath, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_anonymous)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_anonymous)
|
||||
{
|
||||
char *arg = get_string_arg(line, &match[2]);
|
||||
|
||||
if (!arg)
|
||||
return -1;
|
||||
|
||||
@ -402,35 +401,46 @@ static HANDLE_FUNC(handle_anonymous)
|
||||
safefree(arg);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_viaproxyname)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_viaproxyname)
|
||||
{
|
||||
int r = set_string_arg(&conf->via_proxy_name, line, &match[2]);
|
||||
if (r) return r;
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message(LOG_INFO,
|
||||
"Setting \"Via\" header proxy to %s",
|
||||
conf->via_proxy_name);
|
||||
"Setting \"Via\" header proxy to %s", conf->via_proxy_name);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_defaulterrorfile)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_defaulterrorfile)
|
||||
{
|
||||
return set_string_arg(&conf->errorpage_undef, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_statfile)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_statfile)
|
||||
{
|
||||
return set_string_arg(&conf->statpage, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_stathost)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_stathost)
|
||||
{
|
||||
int r = set_string_arg(&conf->stathost, line, &match[2]);
|
||||
if (r) return r;
|
||||
log_message(LOG_INFO,
|
||||
"Stathost set to \"%s\"",
|
||||
conf->stathost);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message(LOG_INFO, "Stathost set to \"%s\"", conf->stathost);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_xtinyproxy)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_xtinyproxy)
|
||||
{
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
return set_string_arg(&conf->my_domain, line, &match[2]);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
@ -438,91 +448,126 @@ static HANDLE_FUNC(handle_xtinyproxy)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
static HANDLE_FUNC(handle_syslog)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_syslog)
|
||||
{
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
return set_bool_arg(&conf->syslog, line, &match[2]);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"Syslog support not compiled in executable.\n");
|
||||
fprintf(stderr, "Syslog support not compiled in executable.\n");
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
static HANDLE_FUNC(handle_bindsame)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_bindsame)
|
||||
{
|
||||
int r = set_bool_arg(&conf->bindsame, line, &match[2]);
|
||||
if (r) return r;
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message(LOG_INFO, "Binding outgoing connection to incoming IP");
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_port)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_port)
|
||||
{
|
||||
return set_int_arg((long int*)&conf->port, line, &match[2]);
|
||||
return set_int_arg((long int *)&conf->port, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_maxclients)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_maxclients)
|
||||
{
|
||||
child_configure(CHILD_MAXCLIENTS, get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_maxspareservers)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_maxspareservers)
|
||||
{
|
||||
child_configure(CHILD_MAXSPARESERVERS, get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_minspareservers)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_minspareservers)
|
||||
{
|
||||
child_configure(CHILD_MINSPARESERVERS, get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_startservers)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_startservers)
|
||||
{
|
||||
child_configure(CHILD_STARTSERVERS, get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_maxrequestsperchild)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_maxrequestsperchild)
|
||||
{
|
||||
child_configure(CHILD_MAXREQUESTSPERCHILD, get_int_arg(line, &match[2]));
|
||||
child_configure(CHILD_MAXREQUESTSPERCHILD,
|
||||
get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_timeout)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_timeout)
|
||||
{
|
||||
return set_int_arg((long int*)&conf->idletimeout, line, &match[2]);
|
||||
return set_int_arg((long int *)&conf->idletimeout, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_connectport)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_connectport)
|
||||
{
|
||||
add_connect_port_allowed(get_int_arg(line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_user)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_user)
|
||||
{
|
||||
return set_string_arg(&conf->username, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_group)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_group)
|
||||
{
|
||||
return set_string_arg(&conf->group, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_allow)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_allow)
|
||||
{
|
||||
char* arg = get_string_arg(line, &match[2]);
|
||||
char *arg = get_string_arg(line, &match[2]);
|
||||
|
||||
insert_acl(arg, ACL_ALLOW);
|
||||
safefree(arg);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_deny)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_deny)
|
||||
{
|
||||
char *arg = get_string_arg(line, &match[2]);
|
||||
|
||||
insert_acl(arg, ACL_DENY);
|
||||
safefree(arg);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_bind)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_bind)
|
||||
{
|
||||
#ifndef TRANSPARENT_PROXY
|
||||
int r = set_string_arg(&conf->bind_address, line, &match[2]);
|
||||
if (r) return r;
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message(LOG_INFO,
|
||||
"Outgoing connections bound to IP %s",
|
||||
conf->bind_address);
|
||||
"Outgoing connections bound to IP %s", conf->bind_address);
|
||||
return 0;
|
||||
#else
|
||||
fprintf(stderr,
|
||||
@ -530,14 +575,20 @@ static HANDLE_FUNC(handle_bind)
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
static HANDLE_FUNC(handle_listen)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_listen)
|
||||
{
|
||||
int r = set_string_arg(&conf->ipAddr, line, &match[2]);
|
||||
if (r) return r;
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message(LOG_INFO, "Listing on IP %s", conf->ipAddr);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_errorfile)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_errorfile)
|
||||
{
|
||||
/*
|
||||
* Because an integer is defined as ((0x)?[[:digit:]]+) _two_
|
||||
@ -548,6 +599,7 @@ static HANDLE_FUNC(handle_errorfile)
|
||||
*/
|
||||
long int err = get_int_arg(line, &match[2]);
|
||||
char *page = get_string_arg(line, &match[4]);
|
||||
|
||||
add_new_errorpage(page, err);
|
||||
safefree(page);
|
||||
return 0;
|
||||
@ -557,24 +609,27 @@ static HANDLE_FUNC(handle_errorfile)
|
||||
* Log level's strings.
|
||||
*/
|
||||
struct log_levels_s {
|
||||
const char* string;
|
||||
const char *string;
|
||||
int level;
|
||||
};
|
||||
static struct log_levels_s log_levels[] = {
|
||||
{ "critical", LOG_CRIT },
|
||||
{ "error", LOG_ERR },
|
||||
{ "warning", LOG_WARNING },
|
||||
{ "notice", LOG_NOTICE },
|
||||
{ "connect", LOG_CONN },
|
||||
{ "info", LOG_INFO }
|
||||
{"critical", LOG_CRIT},
|
||||
{"error", LOG_ERR},
|
||||
{"warning", LOG_WARNING},
|
||||
{"notice", LOG_NOTICE},
|
||||
{"connect", LOG_CONN},
|
||||
{"info", LOG_INFO}
|
||||
};
|
||||
|
||||
static HANDLE_FUNC(handle_loglevel)
|
||||
static
|
||||
HANDLE_FUNC(handle_loglevel)
|
||||
{
|
||||
static const unsigned int nlevels = sizeof(log_levels)/sizeof(log_levels[0]);
|
||||
static const unsigned int nlevels =
|
||||
sizeof(log_levels) / sizeof(log_levels[0]);
|
||||
unsigned int i;
|
||||
|
||||
|
||||
char *arg = get_string_arg(line, &match[2]);
|
||||
|
||||
for (i = 0; i != nlevels; ++i) {
|
||||
if (!strcasecmp(arg, log_levels[i].string)) {
|
||||
set_log_level(log_levels[i].level);
|
||||
@ -584,29 +639,37 @@ static HANDLE_FUNC(handle_loglevel)
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
static HANDLE_FUNC(handle_filter)
|
||||
static
|
||||
HANDLE_FUNC(handle_filter)
|
||||
{
|
||||
return set_string_arg(&conf->filter, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_filterurls)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterurls)
|
||||
{
|
||||
return set_bool_arg(&conf->filter_url, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_filterextended)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterextended)
|
||||
{
|
||||
return set_bool_arg(&conf->filter_extended, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_filterdefaultdeny)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterdefaultdeny)
|
||||
{
|
||||
assert(match[2].rm_so != -1);
|
||||
|
||||
|
||||
if (get_bool_arg(line, &match[2]))
|
||||
filter_set_default_policy(FILTER_DEFAULT_DENY);
|
||||
return 0;
|
||||
}
|
||||
static HANDLE_FUNC(handle_filtercasesensitive)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filtercasesensitive)
|
||||
{
|
||||
return set_bool_arg(&conf->filter_casesensitive, line, &match[2]);
|
||||
}
|
||||
@ -618,29 +681,59 @@ no_filter_support(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC(handle_filter) { return no_filter_support(); }
|
||||
static HANDLE_FUNC(handle_filtercasesensitive) { return no_filter_support(); }
|
||||
static HANDLE_FUNC(handle_filterdefaultdeny) { return no_filter_support(); }
|
||||
static HANDLE_FUNC(handle_filterextended) { return no_filter_support(); }
|
||||
static HANDLE_FUNC(handle_filterurls) { return no_filter_support(); }
|
||||
static
|
||||
HANDLE_FUNC(handle_filter)
|
||||
{
|
||||
return no_filter_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filtercasesensitive)
|
||||
{
|
||||
return no_filter_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterdefaultdeny)
|
||||
{
|
||||
return no_filter_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterextended)
|
||||
{
|
||||
return no_filter_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_filterurls)
|
||||
{
|
||||
return no_filter_support();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
static HANDLE_FUNC(handle_reverseonly)
|
||||
static
|
||||
HANDLE_FUNC(handle_reverseonly)
|
||||
{
|
||||
return set_bool_arg(&conf->reverseonly, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_reversemagic)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reversemagic)
|
||||
{
|
||||
return set_bool_arg(&conf->reversemagic, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_reversebaseurl)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reversebaseurl)
|
||||
{
|
||||
return set_string_arg(&conf->reversebaseurl, line, &match[2]);
|
||||
}
|
||||
static HANDLE_FUNC(handle_reversepath)
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reversepath)
|
||||
{
|
||||
/*
|
||||
* The second string argument is optional.
|
||||
@ -648,7 +741,8 @@ static HANDLE_FUNC(handle_reversepath)
|
||||
char *arg1, *arg2;
|
||||
|
||||
arg1 = get_string_arg(line, &match[2]);
|
||||
if (!arg1) return -1;
|
||||
if (!arg1)
|
||||
return -1;
|
||||
|
||||
if (match[3].rm_so != -1) {
|
||||
arg2 = get_string_arg(line, &match[3]);
|
||||
@ -674,9 +768,28 @@ no_reverse_support(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC(handle_reversebaseurl) { return no_reverse_support(); }
|
||||
static HANDLE_FUNC(handle_reversemagic) { return no_reverse_support(); }
|
||||
static HANDLE_FUNC(handle_reverseonly) { return no_reverse_support(); }
|
||||
static HANDLE_FUNC(handle_reversepath) { return no_reverse_support(); }
|
||||
static
|
||||
HANDLE_FUNC(handle_reversebaseurl)
|
||||
{
|
||||
return no_reverse_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reversemagic)
|
||||
{
|
||||
return no_reverse_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reverseonly)
|
||||
{
|
||||
return no_reverse_support();
|
||||
}
|
||||
|
||||
static
|
||||
HANDLE_FUNC(handle_reversepath)
|
||||
{
|
||||
return no_reverse_support();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: conffile.h,v 1.1 2004-08-13 20:19:50 rjkaes Exp $
|
||||
/* $Id: conffile.h,v 1.2 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'conffile.c' for more details.
|
||||
*
|
||||
@ -19,6 +19,6 @@
|
||||
#define TINYPROXY_CONFFILE_H
|
||||
|
||||
extern int config_compile(void);
|
||||
extern int config_parse(struct config_s* conf, FILE* f);
|
||||
extern int config_parse(struct config_s *conf, FILE * f);
|
||||
|
||||
#endif
|
||||
|
156
src/conns.c
156
src/conns.c
@ -1,4 +1,4 @@
|
||||
/* $Id: conns.c,v 1.24 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: conns.c,v 1.25 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Create and free the connection structure. One day there could be
|
||||
* other connection related tasks put here, but for now the header
|
||||
@ -27,118 +27,118 @@
|
||||
#include "stats.h"
|
||||
|
||||
struct conn_s *
|
||||
initialize_conn(int client_fd, const char* ipaddr, const char* string_addr,
|
||||
const char* sock_ipaddr)
|
||||
initialize_conn(int client_fd, const char *ipaddr, const char *string_addr,
|
||||
const char *sock_ipaddr)
|
||||
{
|
||||
struct conn_s *connptr;
|
||||
struct buffer_s *cbuffer, *sbuffer;
|
||||
struct conn_s *connptr;
|
||||
struct buffer_s *cbuffer, *sbuffer;
|
||||
|
||||
assert(client_fd >= 0);
|
||||
assert(client_fd >= 0);
|
||||
|
||||
/*
|
||||
* Allocate the memory for all the internal components
|
||||
*/
|
||||
cbuffer = new_buffer();
|
||||
sbuffer = new_buffer();
|
||||
/*
|
||||
* Allocate the memory for all the internal components
|
||||
*/
|
||||
cbuffer = new_buffer();
|
||||
sbuffer = new_buffer();
|
||||
|
||||
if (!cbuffer || !sbuffer)
|
||||
goto error_exit;
|
||||
if (!cbuffer || !sbuffer)
|
||||
goto error_exit;
|
||||
|
||||
/*
|
||||
* Allocate the space for the conn_s structure itself.
|
||||
*/
|
||||
connptr = safemalloc(sizeof(struct conn_s));
|
||||
if (!connptr)
|
||||
goto error_exit;
|
||||
/*
|
||||
* Allocate the space for the conn_s structure itself.
|
||||
*/
|
||||
connptr = safemalloc(sizeof(struct conn_s));
|
||||
if (!connptr)
|
||||
goto error_exit;
|
||||
|
||||
connptr->client_fd = client_fd;
|
||||
connptr->server_fd = -1;
|
||||
connptr->client_fd = client_fd;
|
||||
connptr->server_fd = -1;
|
||||
|
||||
connptr->cbuffer = cbuffer;
|
||||
connptr->sbuffer = sbuffer;
|
||||
connptr->cbuffer = cbuffer;
|
||||
connptr->sbuffer = sbuffer;
|
||||
|
||||
connptr->request_line = NULL;
|
||||
connptr->request_line = NULL;
|
||||
|
||||
/* These store any error strings */
|
||||
connptr->error_variables = NULL;
|
||||
connptr->error_string = NULL;
|
||||
connptr->error_number = -1;
|
||||
/* These store any error strings */
|
||||
connptr->error_variables = NULL;
|
||||
connptr->error_string = NULL;
|
||||
connptr->error_number = -1;
|
||||
|
||||
connptr->connect_method = FALSE;
|
||||
connptr->show_stats = FALSE;
|
||||
connptr->connect_method = FALSE;
|
||||
connptr->show_stats = FALSE;
|
||||
|
||||
connptr->protocol.major = connptr->protocol.minor = 0;
|
||||
connptr->protocol.major = connptr->protocol.minor = 0;
|
||||
|
||||
/* There is _no_ content length initially */
|
||||
connptr->content_length.server = connptr->content_length.client = -1;
|
||||
/* There is _no_ content length initially */
|
||||
connptr->content_length.server = connptr->content_length.client = -1;
|
||||
|
||||
connptr->server_ip_addr = sock_ipaddr ? safestrdup(sock_ipaddr) : 0;
|
||||
connptr->client_ip_addr = safestrdup(ipaddr);
|
||||
connptr->client_string_addr = safestrdup(string_addr);
|
||||
connptr->server_ip_addr = sock_ipaddr ? safestrdup(sock_ipaddr) : 0;
|
||||
connptr->client_ip_addr = safestrdup(ipaddr);
|
||||
connptr->client_string_addr = safestrdup(string_addr);
|
||||
|
||||
connptr->upstream_proxy = NULL;
|
||||
connptr->upstream_proxy = NULL;
|
||||
|
||||
update_stats(STAT_OPEN);
|
||||
update_stats(STAT_OPEN);
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
connptr->reversepath = NULL;
|
||||
connptr->reversepath = NULL;
|
||||
#endif
|
||||
|
||||
return connptr;
|
||||
return connptr;
|
||||
|
||||
error_exit:
|
||||
/*
|
||||
* If we got here, there was a problem allocating memory
|
||||
*/
|
||||
if (cbuffer)
|
||||
delete_buffer(cbuffer);
|
||||
if (sbuffer)
|
||||
delete_buffer(sbuffer);
|
||||
error_exit:
|
||||
/*
|
||||
* If we got here, there was a problem allocating memory
|
||||
*/
|
||||
if (cbuffer)
|
||||
delete_buffer(cbuffer);
|
||||
if (sbuffer)
|
||||
delete_buffer(sbuffer);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
destroy_conn(struct conn_s *connptr)
|
||||
{
|
||||
assert(connptr != NULL);
|
||||
assert(connptr != NULL);
|
||||
|
||||
if (connptr->client_fd != -1)
|
||||
if (close(connptr->client_fd) < 0)
|
||||
log_message(LOG_INFO, "Client (%d) close message: %s",
|
||||
connptr->client_fd, strerror(errno));
|
||||
if (connptr->server_fd != -1)
|
||||
if (close(connptr->server_fd) < 0)
|
||||
log_message(LOG_INFO, "Server (%d) close message: %s",
|
||||
connptr->server_fd, strerror(errno));
|
||||
if (connptr->client_fd != -1)
|
||||
if (close(connptr->client_fd) < 0)
|
||||
log_message(LOG_INFO, "Client (%d) close message: %s",
|
||||
connptr->client_fd, strerror(errno));
|
||||
if (connptr->server_fd != -1)
|
||||
if (close(connptr->server_fd) < 0)
|
||||
log_message(LOG_INFO, "Server (%d) close message: %s",
|
||||
connptr->server_fd, strerror(errno));
|
||||
|
||||
if (connptr->cbuffer)
|
||||
delete_buffer(connptr->cbuffer);
|
||||
if (connptr->sbuffer)
|
||||
delete_buffer(connptr->sbuffer);
|
||||
if (connptr->cbuffer)
|
||||
delete_buffer(connptr->cbuffer);
|
||||
if (connptr->sbuffer)
|
||||
delete_buffer(connptr->sbuffer);
|
||||
|
||||
if (connptr->request_line)
|
||||
safefree(connptr->request_line);
|
||||
if (connptr->request_line)
|
||||
safefree(connptr->request_line);
|
||||
|
||||
if (connptr->error_variables)
|
||||
hashmap_delete(connptr->error_variables);
|
||||
if (connptr->error_variables)
|
||||
hashmap_delete(connptr->error_variables);
|
||||
|
||||
if (connptr->error_string)
|
||||
safefree(connptr->error_string);
|
||||
if (connptr->error_string)
|
||||
safefree(connptr->error_string);
|
||||
|
||||
if (connptr->server_ip_addr)
|
||||
safefree(connptr->server_ip_addr);
|
||||
if (connptr->client_ip_addr)
|
||||
safefree(connptr->client_ip_addr);
|
||||
if (connptr->client_string_addr)
|
||||
safefree(connptr->client_string_addr);
|
||||
if (connptr->server_ip_addr)
|
||||
safefree(connptr->server_ip_addr);
|
||||
if (connptr->client_ip_addr)
|
||||
safefree(connptr->client_ip_addr);
|
||||
if (connptr->client_string_addr)
|
||||
safefree(connptr->client_string_addr);
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
if (connptr->reversepath)
|
||||
safefree(connptr->reversepath);
|
||||
if (connptr->reversepath)
|
||||
safefree(connptr->reversepath);
|
||||
#endif
|
||||
|
||||
safefree(connptr);
|
||||
safefree(connptr);
|
||||
|
||||
update_stats(STAT_CLOSE);
|
||||
update_stats(STAT_CLOSE);
|
||||
}
|
||||
|
88
src/conns.h
88
src/conns.h
@ -1,4 +1,4 @@
|
||||
/* $Id: conns.h,v 1.19 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: conns.h,v 1.20 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'conns.c' for a detailed description.
|
||||
*
|
||||
@ -25,58 +25,58 @@
|
||||
* Connection Definition
|
||||
*/
|
||||
struct conn_s {
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
int client_fd;
|
||||
int server_fd;
|
||||
|
||||
struct buffer_s *cbuffer;
|
||||
struct buffer_s *sbuffer;
|
||||
struct buffer_s *cbuffer;
|
||||
struct buffer_s *sbuffer;
|
||||
|
||||
/* The request line (first line) from the client */
|
||||
char *request_line;
|
||||
/* The request line (first line) from the client */
|
||||
char *request_line;
|
||||
|
||||
/* Booleans */
|
||||
unsigned int connect_method;
|
||||
unsigned int show_stats;
|
||||
/* Booleans */
|
||||
unsigned int connect_method;
|
||||
unsigned int show_stats;
|
||||
|
||||
/*
|
||||
* This structure stores key -> value mappings for substitution
|
||||
* in the error HTML files.
|
||||
*/
|
||||
hashmap_t error_variables;
|
||||
* This structure stores key -> value mappings for substitution
|
||||
* in the error HTML files.
|
||||
*/
|
||||
hashmap_t error_variables;
|
||||
|
||||
int error_number;
|
||||
char *error_string;
|
||||
int error_number;
|
||||
char *error_string;
|
||||
|
||||
/* A Content-Length value from the remote server */
|
||||
struct {
|
||||
long int server;
|
||||
long int client;
|
||||
} content_length;
|
||||
/* A Content-Length value from the remote server */
|
||||
struct {
|
||||
long int server;
|
||||
long int client;
|
||||
} content_length;
|
||||
|
||||
/*
|
||||
* Store the server's IP (for BindSame)
|
||||
*/
|
||||
char* server_ip_addr;
|
||||
/*
|
||||
* Store the server's IP (for BindSame)
|
||||
*/
|
||||
char *server_ip_addr;
|
||||
|
||||
/*
|
||||
* Store the client's IP and hostname information
|
||||
*/
|
||||
char* client_ip_addr;
|
||||
char* client_string_addr;
|
||||
/*
|
||||
* Store the client's IP and hostname information
|
||||
*/
|
||||
char *client_ip_addr;
|
||||
char *client_string_addr;
|
||||
|
||||
/*
|
||||
* Store the incoming request's HTTP protocol.
|
||||
*/
|
||||
struct {
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
} protocol;
|
||||
/*
|
||||
* Store the incoming request's HTTP protocol.
|
||||
*/
|
||||
struct {
|
||||
unsigned int major;
|
||||
unsigned int minor;
|
||||
} protocol;
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
/*
|
||||
* Place to store the current per-connection reverse proxy path
|
||||
*/
|
||||
char* reversepath;
|
||||
/*
|
||||
* Place to store the current per-connection reverse proxy path
|
||||
*/
|
||||
char *reversepath;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -88,9 +88,9 @@ struct conn_s {
|
||||
/*
|
||||
* Functions for the creation and destruction of a connection structure.
|
||||
*/
|
||||
extern struct conn_s* initialize_conn(int client_fd, const char* ipaddr,
|
||||
const char* string_addr,
|
||||
const char* sock_ipaddr);
|
||||
extern struct conn_s *initialize_conn(int client_fd, const char *ipaddr,
|
||||
const char *string_addr,
|
||||
const char *sock_ipaddr);
|
||||
extern void destroy_conn(struct conn_s *connptr);
|
||||
|
||||
#endif
|
||||
|
50
src/daemon.c
50
src/daemon.c
@ -1,4 +1,4 @@
|
||||
/* $Id: daemon.c,v 1.4 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: daemon.c,v 1.5 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* This file contains functions which are useful when writing a
|
||||
* daemon process. The functions include a "makedaemon" function and
|
||||
@ -28,26 +28,26 @@
|
||||
void
|
||||
makedaemon(void)
|
||||
{
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
|
||||
setsid();
|
||||
set_signal_handler(SIGHUP, SIG_IGN);
|
||||
setsid();
|
||||
set_signal_handler(SIGHUP, SIG_IGN);
|
||||
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
if (fork() != 0)
|
||||
exit(0);
|
||||
|
||||
chdir("/");
|
||||
umask(077);
|
||||
chdir("/");
|
||||
umask(077);
|
||||
|
||||
#if NDEBUG
|
||||
/*
|
||||
* When not in debugging mode, close the standard file
|
||||
* descriptors.
|
||||
*/
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
close(0);
|
||||
close(1);
|
||||
close(2);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -56,25 +56,25 @@ makedaemon(void)
|
||||
* to handle signals sent to the process.
|
||||
*/
|
||||
signal_func *
|
||||
set_signal_handler(int signo, signal_func *func)
|
||||
set_signal_handler(int signo, signal_func * func)
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
struct sigaction act, oact;
|
||||
|
||||
act.sa_handler = func;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
if (signo == SIGALRM) {
|
||||
act.sa_handler = func;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
if (signo == SIGALRM) {
|
||||
#ifdef SA_INTERRUPT
|
||||
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
|
||||
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
|
||||
#endif
|
||||
} else {
|
||||
} else {
|
||||
#ifdef SA_RESTART
|
||||
act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */
|
||||
act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (sigaction(signo, &act, &oact) < 0)
|
||||
return SIG_ERR;
|
||||
if (sigaction(signo, &act, &oact) < 0)
|
||||
return SIG_ERR;
|
||||
|
||||
return oact.sa_handler;
|
||||
return oact.sa_handler;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: daemon.h,v 1.2 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: daemon.h,v 1.3 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'daemon.c' for a detailed description.
|
||||
*
|
||||
@ -23,7 +23,7 @@ typedef void signal_func(int);
|
||||
/*
|
||||
* Pass a singal integer and a function to handle the signal.
|
||||
*/
|
||||
extern signal_func *set_signal_handler(int signo, signal_func *func);
|
||||
extern signal_func *set_signal_handler(int signo, signal_func * func);
|
||||
|
||||
/*
|
||||
* Make a program a daemon process
|
||||
|
248
src/filter.c
248
src/filter.c
@ -1,4 +1,4 @@
|
||||
/* $Id: filter.c,v 1.21 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: filter.c,v 1.22 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Copyright (c) 1999 George Talusan (gstalusan@uwaterloo.ca)
|
||||
* Copyright (c) 2002 James E. Flemer (jflemer@acm.jhu.edu)
|
||||
@ -30,9 +30,9 @@
|
||||
static int err;
|
||||
|
||||
struct filter_list {
|
||||
struct filter_list *next;
|
||||
char *pat;
|
||||
regex_t *cpat;
|
||||
struct filter_list *next;
|
||||
char *pat;
|
||||
regex_t *cpat;
|
||||
};
|
||||
|
||||
static struct filter_list *fl = NULL;
|
||||
@ -45,158 +45,162 @@ static filter_policy_t default_policy = FILTER_DEFAULT_ALLOW;
|
||||
void
|
||||
filter_init(void)
|
||||
{
|
||||
FILE *fd;
|
||||
struct filter_list *p;
|
||||
char buf[FILTER_BUFFER_LEN];
|
||||
char *s;
|
||||
int cflags;
|
||||
FILE *fd;
|
||||
struct filter_list *p;
|
||||
char buf[FILTER_BUFFER_LEN];
|
||||
char *s;
|
||||
int cflags;
|
||||
|
||||
if (!fl && !already_init) {
|
||||
fd = fopen(config.filter, "r");
|
||||
if (fd) {
|
||||
p = NULL;
|
||||
if (!fl && !already_init) {
|
||||
fd = fopen(config.filter, "r");
|
||||
if (fd) {
|
||||
p = NULL;
|
||||
|
||||
cflags = REG_NEWLINE | REG_NOSUB;
|
||||
if (config.filter_extended)
|
||||
cflags |= REG_EXTENDED;
|
||||
if (!config.filter_casesensitive)
|
||||
cflags |= REG_ICASE;
|
||||
cflags = REG_NEWLINE | REG_NOSUB;
|
||||
if (config.filter_extended)
|
||||
cflags |= REG_EXTENDED;
|
||||
if (!config.filter_casesensitive)
|
||||
cflags |= REG_ICASE;
|
||||
|
||||
while (fgets(buf, FILTER_BUFFER_LEN, fd)) {
|
||||
/*
|
||||
* Remove any trailing white space and
|
||||
* comments.
|
||||
*/
|
||||
s = buf;
|
||||
while (*s) {
|
||||
if (isspace((unsigned char)*s)) break;
|
||||
if (*s == '#') {
|
||||
/*
|
||||
* If the '#' char is preceeded by
|
||||
* an escape, it's not a comment
|
||||
* string.
|
||||
*/
|
||||
if (s == buf || *(s - 1) != '\\')
|
||||
break;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
*s = '\0';
|
||||
while (fgets(buf, FILTER_BUFFER_LEN, fd)) {
|
||||
/*
|
||||
* Remove any trailing white space and
|
||||
* comments.
|
||||
*/
|
||||
s = buf;
|
||||
while (*s) {
|
||||
if (isspace((unsigned char)*s))
|
||||
break;
|
||||
if (*s == '#') {
|
||||
/*
|
||||
* If the '#' char is preceeded by
|
||||
* an escape, it's not a comment
|
||||
* string.
|
||||
*/
|
||||
if (s == buf
|
||||
|| *(s - 1) != '\\')
|
||||
break;
|
||||
}
|
||||
++s;
|
||||
}
|
||||
*s = '\0';
|
||||
|
||||
/* skip leading whitespace */
|
||||
s = buf;
|
||||
while (*s && isspace((unsigned char)*s))
|
||||
s++;
|
||||
/* skip leading whitespace */
|
||||
s = buf;
|
||||
while (*s && isspace((unsigned char)*s))
|
||||
s++;
|
||||
|
||||
/* skip blank lines and comments */
|
||||
if (*s == '\0')
|
||||
continue;
|
||||
/* skip blank lines and comments */
|
||||
if (*s == '\0')
|
||||
continue;
|
||||
|
||||
if (!p) /* head of list */
|
||||
fl = p =
|
||||
safecalloc(1,
|
||||
sizeof(struct
|
||||
filter_list));
|
||||
else { /* next entry */
|
||||
p->next =
|
||||
safecalloc(1,
|
||||
sizeof(struct
|
||||
filter_list));
|
||||
p = p->next;
|
||||
}
|
||||
if (!p) /* head of list */
|
||||
fl = p =
|
||||
safecalloc(1,
|
||||
sizeof(struct
|
||||
filter_list));
|
||||
else { /* next entry */
|
||||
p->next =
|
||||
safecalloc(1,
|
||||
sizeof(struct
|
||||
filter_list));
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
p->pat = safestrdup(s);
|
||||
p->cpat = safemalloc(sizeof(regex_t));
|
||||
if ((err = regcomp(p->cpat, p->pat, cflags)) != 0) {
|
||||
fprintf(stderr, "Bad regex in %s: %s\n",
|
||||
config.filter, p->pat);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
}
|
||||
if (ferror(fd)) {
|
||||
perror("fgets");
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
fclose(fd);
|
||||
p->pat = safestrdup(s);
|
||||
p->cpat = safemalloc(sizeof(regex_t));
|
||||
if ((err =
|
||||
regcomp(p->cpat, p->pat, cflags)) != 0) {
|
||||
fprintf(stderr, "Bad regex in %s: %s\n",
|
||||
config.filter, p->pat);
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
}
|
||||
if (ferror(fd)) {
|
||||
perror("fgets");
|
||||
exit(EX_DATAERR);
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
already_init = 1;
|
||||
}
|
||||
}
|
||||
already_init = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* unlink the list */
|
||||
void
|
||||
filter_destroy(void)
|
||||
{
|
||||
struct filter_list *p, *q;
|
||||
struct filter_list *p, *q;
|
||||
|
||||
if (already_init) {
|
||||
for (p = q = fl; p; p = q) {
|
||||
regfree(p->cpat);
|
||||
safefree(p->cpat);
|
||||
safefree(p->pat);
|
||||
q = p->next;
|
||||
safefree(p);
|
||||
}
|
||||
fl = NULL;
|
||||
already_init = 0;
|
||||
}
|
||||
if (already_init) {
|
||||
for (p = q = fl; p; p = q) {
|
||||
regfree(p->cpat);
|
||||
safefree(p->cpat);
|
||||
safefree(p->pat);
|
||||
q = p->next;
|
||||
safefree(p);
|
||||
}
|
||||
fl = NULL;
|
||||
already_init = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return 0 to allow, non-zero to block */
|
||||
int
|
||||
filter_domain(const char *host)
|
||||
{
|
||||
struct filter_list *p;
|
||||
int result;
|
||||
struct filter_list *p;
|
||||
int result;
|
||||
|
||||
if (!fl || !already_init)
|
||||
goto COMMON_EXIT;
|
||||
if (!fl || !already_init)
|
||||
goto COMMON_EXIT;
|
||||
|
||||
for (p = fl; p; p = p->next) {
|
||||
result = regexec(p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
for (p = fl; p; p = p->next) {
|
||||
result =
|
||||
regexec(p->cpat, host, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
|
||||
if (result == 0) {
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
COMMON_EXIT:
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
COMMON_EXIT:
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns 0 to allow, non-zero to block */
|
||||
int
|
||||
filter_url(const char *url)
|
||||
{
|
||||
struct filter_list *p;
|
||||
int result;
|
||||
struct filter_list *p;
|
||||
int result;
|
||||
|
||||
if (!fl || !already_init)
|
||||
goto COMMON_EXIT;
|
||||
if (!fl || !already_init)
|
||||
goto COMMON_EXIT;
|
||||
|
||||
for (p = fl; p; p = p->next) {
|
||||
result = regexec(p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
for (p = fl; p; p = p->next) {
|
||||
result = regexec(p->cpat, url, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
|
||||
if (result == 0) {
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (result == 0) {
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
COMMON_EXIT:
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
COMMON_EXIT:
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -205,5 +209,5 @@ filter_url(const char *url)
|
||||
void
|
||||
filter_set_default_policy(filter_policy_t policy)
|
||||
{
|
||||
default_policy = policy;
|
||||
default_policy = policy;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: filter.h,v 1.5 2002-06-07 18:36:21 rjkaes Exp $
|
||||
/* $Id: filter.h,v 1.6 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'filter.c' for a detailed description.
|
||||
*
|
||||
@ -19,8 +19,8 @@
|
||||
#define _TINYPROXY_FILTER_H_
|
||||
|
||||
typedef enum {
|
||||
FILTER_DEFAULT_ALLOW,
|
||||
FILTER_DEFAULT_DENY,
|
||||
FILTER_DEFAULT_ALLOW,
|
||||
FILTER_DEFAULT_DENY,
|
||||
} filter_policy_t;
|
||||
|
||||
extern void filter_init(void);
|
||||
|
478
src/hashmap.c
478
src/hashmap.c
@ -1,4 +1,4 @@
|
||||
/* $Id: hashmap.c,v 1.16 2005-07-12 17:39:43 rjkaes Exp $
|
||||
/* $Id: hashmap.c,v 1.17 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* A hashmap implementation. The keys are case-insensitive NULL terminated
|
||||
* strings, and the data is arbitrary lumps of data. Copies of both the
|
||||
@ -38,11 +38,11 @@
|
||||
* with.
|
||||
*/
|
||||
struct hashentry_s {
|
||||
char *key;
|
||||
void *data;
|
||||
size_t len;
|
||||
char *key;
|
||||
void *data;
|
||||
size_t len;
|
||||
|
||||
struct hashentry_s *prev, *next;
|
||||
struct hashentry_s *prev, *next;
|
||||
};
|
||||
|
||||
struct hashbucket_s {
|
||||
@ -50,10 +50,10 @@ struct hashbucket_s {
|
||||
};
|
||||
|
||||
struct hashmap_s {
|
||||
unsigned int size;
|
||||
hashmap_iter end_iterator;
|
||||
unsigned int size;
|
||||
hashmap_iter end_iterator;
|
||||
|
||||
struct hashbucket_s *buckets;
|
||||
struct hashbucket_s *buckets;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -68,23 +68,23 @@ struct hashmap_s {
|
||||
static int
|
||||
hashfunc(const char *key, unsigned int size)
|
||||
{
|
||||
uint32_t hash;
|
||||
uint32_t hash;
|
||||
|
||||
if (key == NULL)
|
||||
return -EINVAL;
|
||||
if (size == 0)
|
||||
return -ERANGE;
|
||||
|
||||
for (hash = tolower(*key++); *key != '\0'; key++) {
|
||||
uint32_t bit =
|
||||
(hash & 1) ? (1 << (sizeof(uint32_t) - 1)) : 0;
|
||||
hash >>= 1;
|
||||
if (key == NULL)
|
||||
return -EINVAL;
|
||||
if (size == 0)
|
||||
return -ERANGE;
|
||||
|
||||
hash += tolower(*key) + bit;
|
||||
}
|
||||
for (hash = tolower(*key++); *key != '\0'; key++) {
|
||||
uint32_t bit = (hash & 1) ? (1 << (sizeof(uint32_t) - 1)) : 0;
|
||||
|
||||
/* Keep the hash within the table limits */
|
||||
return hash % size;
|
||||
hash >>= 1;
|
||||
|
||||
hash += tolower(*key) + bit;
|
||||
}
|
||||
|
||||
/* Keep the hash within the table limits */
|
||||
return hash % size;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -97,26 +97,26 @@ hashfunc(const char *key, unsigned int size)
|
||||
hashmap_t
|
||||
hashmap_create(unsigned int nbuckets)
|
||||
{
|
||||
struct hashmap_s* ptr;
|
||||
struct hashmap_s *ptr;
|
||||
|
||||
if (nbuckets == 0)
|
||||
return NULL;
|
||||
if (nbuckets == 0)
|
||||
return NULL;
|
||||
|
||||
ptr = safecalloc(1, sizeof(struct hashmap_s));
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
ptr = safecalloc(1, sizeof(struct hashmap_s));
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
ptr->size = nbuckets;
|
||||
ptr->buckets = safecalloc(nbuckets, sizeof(struct hashbucket_s));
|
||||
if (!ptr->buckets) {
|
||||
safefree(ptr);
|
||||
return NULL;
|
||||
}
|
||||
ptr->size = nbuckets;
|
||||
ptr->buckets = safecalloc(nbuckets, sizeof(struct hashbucket_s));
|
||||
if (!ptr->buckets) {
|
||||
safefree(ptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This points to "one" past the end of the hashmap. */
|
||||
ptr->end_iterator = 0;
|
||||
/* This points to "one" past the end of the hashmap. */
|
||||
ptr->end_iterator = 0;
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -127,26 +127,26 @@ hashmap_create(unsigned int nbuckets)
|
||||
* negative number is returned if "entry" was NULL
|
||||
*/
|
||||
static inline int
|
||||
delete_hashbucket(struct hashbucket_s* bucket)
|
||||
delete_hashbucket(struct hashbucket_s *bucket)
|
||||
{
|
||||
struct hashentry_s *nextptr;
|
||||
struct hashentry_s *ptr;
|
||||
struct hashentry_s *nextptr;
|
||||
struct hashentry_s *ptr;
|
||||
|
||||
if (bucket == NULL || bucket->head == NULL)
|
||||
return -EINVAL;
|
||||
if (bucket == NULL || bucket->head == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = bucket->head;
|
||||
while (ptr) {
|
||||
nextptr = ptr->next;
|
||||
|
||||
safefree(ptr->key);
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
ptr = bucket->head;
|
||||
while (ptr) {
|
||||
nextptr = ptr->next;
|
||||
|
||||
ptr = nextptr;
|
||||
}
|
||||
safefree(ptr->key);
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
|
||||
return 0;
|
||||
ptr = nextptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -158,21 +158,21 @@ delete_hashbucket(struct hashbucket_s* bucket)
|
||||
int
|
||||
hashmap_delete(hashmap_t map)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if (map == NULL)
|
||||
return -EINVAL;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i != map->size; i++) {
|
||||
if (map->buckets[i].head != NULL) {
|
||||
delete_hashbucket(&map->buckets[i]);
|
||||
}
|
||||
}
|
||||
if (map == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
safefree(map->buckets);
|
||||
safefree(map);
|
||||
for (i = 0; i != map->size; i++) {
|
||||
if (map->buckets[i].head != NULL) {
|
||||
delete_hashbucket(&map->buckets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
safefree(map->buckets);
|
||||
safefree(map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -186,57 +186,56 @@ hashmap_delete(hashmap_t map)
|
||||
* negative number if there are errors
|
||||
*/
|
||||
int
|
||||
hashmap_insert(hashmap_t map, const char *key,
|
||||
const void *data, size_t len)
|
||||
hashmap_insert(hashmap_t map, const char *key, const void *data, size_t len)
|
||||
{
|
||||
struct hashentry_s *ptr;
|
||||
int hash;
|
||||
char *key_copy;
|
||||
void *data_copy;
|
||||
struct hashentry_s *ptr;
|
||||
int hash;
|
||||
char *key_copy;
|
||||
void *data_copy;
|
||||
|
||||
assert(map != NULL);
|
||||
assert(key != NULL);
|
||||
assert(data != NULL);
|
||||
assert(len > 0);
|
||||
assert(map != NULL);
|
||||
assert(key != NULL);
|
||||
assert(data != NULL);
|
||||
assert(len > 0);
|
||||
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
if (!data || len < 1)
|
||||
return -ERANGE;
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
if (!data || len < 1)
|
||||
return -ERANGE;
|
||||
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
/*
|
||||
* First make copies of the key and data in case there is a memory
|
||||
* problem later.
|
||||
*/
|
||||
key_copy = safestrdup(key);
|
||||
if (!key_copy)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* First make copies of the key and data in case there is a memory
|
||||
* problem later.
|
||||
*/
|
||||
key_copy = safestrdup(key);
|
||||
if (!key_copy)
|
||||
return -ENOMEM;
|
||||
|
||||
if (data) {
|
||||
data_copy = safemalloc(len);
|
||||
if (!data_copy) {
|
||||
safefree(key_copy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(data_copy, data, len);
|
||||
} else {
|
||||
data_copy = NULL;
|
||||
}
|
||||
if (data) {
|
||||
data_copy = safemalloc(len);
|
||||
if (!data_copy) {
|
||||
safefree(key_copy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(data_copy, data, len);
|
||||
} else {
|
||||
data_copy = NULL;
|
||||
}
|
||||
|
||||
ptr = safemalloc(sizeof(struct hashentry_s));
|
||||
if (!ptr) {
|
||||
safefree(key_copy);
|
||||
safefree(data_copy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ptr = safemalloc(sizeof(struct hashentry_s));
|
||||
if (!ptr) {
|
||||
safefree(key_copy);
|
||||
safefree(data_copy);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ptr->key = key_copy;
|
||||
ptr->data = data_copy;
|
||||
ptr->len = len;
|
||||
ptr->key = key_copy;
|
||||
ptr->data = data_copy;
|
||||
ptr->len = len;
|
||||
|
||||
/*
|
||||
* Now add the entry to the end of the bucket chain.
|
||||
@ -245,13 +244,13 @@ hashmap_insert(hashmap_t map, const char *key,
|
||||
ptr->prev = map->buckets[hash].tail;
|
||||
if (map->buckets[hash].tail)
|
||||
map->buckets[hash].tail->next = ptr;
|
||||
|
||||
|
||||
map->buckets[hash].tail = ptr;
|
||||
if (!map->buckets[hash].head)
|
||||
map->buckets[hash].head = ptr;
|
||||
|
||||
map->end_iterator++;
|
||||
return 0;
|
||||
map->end_iterator++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -262,15 +261,15 @@ hashmap_insert(hashmap_t map, const char *key,
|
||||
hashmap_iter
|
||||
hashmap_first(hashmap_t map)
|
||||
{
|
||||
assert(map != NULL);
|
||||
assert(map != NULL);
|
||||
|
||||
if (!map)
|
||||
return -EINVAL;
|
||||
if (!map)
|
||||
return -EINVAL;
|
||||
|
||||
if (map->end_iterator == 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
if (map->end_iterator == 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -282,16 +281,16 @@ hashmap_first(hashmap_t map)
|
||||
int
|
||||
hashmap_is_end(hashmap_t map, hashmap_iter iter)
|
||||
{
|
||||
assert(map != NULL);
|
||||
assert(iter >= 0);
|
||||
assert(map != NULL);
|
||||
assert(iter >= 0);
|
||||
|
||||
if (!map || iter < 0)
|
||||
return -EINVAL;
|
||||
if (!map || iter < 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (iter == map->end_iterator)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
if (iter == map->end_iterator)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -303,37 +302,37 @@ hashmap_is_end(hashmap_t map, hashmap_iter iter)
|
||||
* an "end-iterator" if the key wasn't found
|
||||
*/
|
||||
hashmap_iter
|
||||
hashmap_find(hashmap_t map, const char* key)
|
||||
hashmap_find(hashmap_t map, const char *key)
|
||||
{
|
||||
unsigned int i;
|
||||
hashmap_iter iter = 0;
|
||||
struct hashentry_s* ptr;
|
||||
unsigned int i;
|
||||
hashmap_iter iter = 0;
|
||||
struct hashentry_s *ptr;
|
||||
|
||||
assert(map != NULL);
|
||||
assert(key != NULL);
|
||||
assert(map != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
if (!map || !key)
|
||||
return -EINVAL;
|
||||
if (!map || !key)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Loop through all the keys and look for the first occurrence
|
||||
* of a particular key.
|
||||
*/
|
||||
for (i = 0; i != map->size; i++) {
|
||||
ptr = map->buckets[i].head;
|
||||
/*
|
||||
* Loop through all the keys and look for the first occurrence
|
||||
* of a particular key.
|
||||
*/
|
||||
for (i = 0; i != map->size; i++) {
|
||||
ptr = map->buckets[i].head;
|
||||
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
/* Found it, so return the current count */
|
||||
return iter;
|
||||
}
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
/* Found it, so return the current count */
|
||||
return iter;
|
||||
}
|
||||
|
||||
iter++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
}
|
||||
|
||||
return iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -343,38 +342,37 @@ hashmap_find(hashmap_t map, const char* key)
|
||||
* negative upon error
|
||||
*/
|
||||
ssize_t
|
||||
hashmap_return_entry(hashmap_t map, hashmap_iter iter,
|
||||
char** key, void** data)
|
||||
hashmap_return_entry(hashmap_t map, hashmap_iter iter, char **key, void **data)
|
||||
{
|
||||
unsigned int i;
|
||||
struct hashentry_s* ptr;
|
||||
hashmap_iter count = 0;
|
||||
unsigned int i;
|
||||
struct hashentry_s *ptr;
|
||||
hashmap_iter count = 0;
|
||||
|
||||
assert(map != NULL);
|
||||
assert(iter >= 0);
|
||||
assert(iter != map->end_iterator);
|
||||
assert(key != NULL);
|
||||
assert(data != NULL);
|
||||
assert(map != NULL);
|
||||
assert(iter >= 0);
|
||||
assert(iter != map->end_iterator);
|
||||
assert(key != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
if (!map || iter < 0 || !key || !data)
|
||||
return -EINVAL;
|
||||
if (!map || iter < 0 || !key || !data)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i != map->size; i++) {
|
||||
ptr = map->buckets[i].head;
|
||||
while (ptr) {
|
||||
if (count == iter) {
|
||||
/* This is the data so return it */
|
||||
*key = ptr->key;
|
||||
*data = ptr->data;
|
||||
return ptr->len;
|
||||
}
|
||||
for (i = 0; i != map->size; i++) {
|
||||
ptr = map->buckets[i].head;
|
||||
while (ptr) {
|
||||
if (count == iter) {
|
||||
/* This is the data so return it */
|
||||
*key = ptr->key;
|
||||
*data = ptr->data;
|
||||
return ptr->len;
|
||||
}
|
||||
|
||||
ptr = ptr->next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
ptr = ptr->next;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return -EFAULT;
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -387,29 +385,29 @@ hashmap_return_entry(hashmap_t map, hashmap_iter iter,
|
||||
ssize_t
|
||||
hashmap_search(hashmap_t map, const char *key)
|
||||
{
|
||||
int hash;
|
||||
struct hashentry_s* ptr;
|
||||
ssize_t count = 0;
|
||||
int hash;
|
||||
struct hashentry_s *ptr;
|
||||
ssize_t count = 0;
|
||||
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
ptr = map->buckets[hash].head;
|
||||
ptr = map->buckets[hash].head;
|
||||
|
||||
/* All right, there is an entry here, now see if it's the one we want */
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0)
|
||||
++count;
|
||||
/* All right, there is an entry here, now see if it's the one we want */
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0)
|
||||
++count;
|
||||
|
||||
/* This entry didn't contain the key; move to the next one */
|
||||
ptr = ptr->next;
|
||||
}
|
||||
/* This entry didn't contain the key; move to the next one */
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -421,30 +419,30 @@ hashmap_search(hashmap_t map, const char *key)
|
||||
* length of data for the entry
|
||||
*/
|
||||
ssize_t
|
||||
hashmap_entry_by_key(hashmap_t map, const char* key, void** data)
|
||||
hashmap_entry_by_key(hashmap_t map, const char *key, void **data)
|
||||
{
|
||||
int hash;
|
||||
struct hashentry_s* ptr;
|
||||
int hash;
|
||||
struct hashentry_s *ptr;
|
||||
|
||||
if (!map || !key || !data)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
if (!map || !key || !data)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = map->buckets[hash].head;
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
*data = ptr->data;
|
||||
return ptr->len;
|
||||
}
|
||||
ptr = map->buckets[hash].head;
|
||||
|
||||
ptr = ptr->next;
|
||||
}
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
*data = ptr->data;
|
||||
return ptr->len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -458,26 +456,26 @@ hashmap_entry_by_key(hashmap_t map, const char* key, void** data)
|
||||
ssize_t
|
||||
hashmap_remove(hashmap_t map, const char *key)
|
||||
{
|
||||
int hash;
|
||||
struct hashentry_s *ptr, *next;
|
||||
short int deleted = 0;
|
||||
int hash;
|
||||
struct hashentry_s *ptr, *next;
|
||||
short int deleted = 0;
|
||||
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
hash = hashfunc(key, map->size);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
ptr = map->buckets[hash].head;
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
/*
|
||||
* Found the data, now need to remove everything
|
||||
* and update the hashmap.
|
||||
*/
|
||||
ptr = map->buckets[hash].head;
|
||||
while (ptr) {
|
||||
if (strcasecmp(ptr->key, key) == 0) {
|
||||
/*
|
||||
* Found the data, now need to remove everything
|
||||
* and update the hashmap.
|
||||
*/
|
||||
next = ptr->next;
|
||||
|
||||
|
||||
if (ptr->prev)
|
||||
ptr->prev->next = ptr->next;
|
||||
if (ptr->next)
|
||||
@ -487,22 +485,22 @@ hashmap_remove(hashmap_t map, const char *key)
|
||||
map->buckets[hash].head = ptr->next;
|
||||
if (map->buckets[hash].tail == ptr)
|
||||
map->buckets[hash].tail = ptr->prev;
|
||||
|
||||
safefree(ptr->key);
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
|
||||
++deleted;
|
||||
--map->end_iterator;
|
||||
|
||||
safefree(ptr->key);
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
|
||||
++deleted;
|
||||
--map->end_iterator;
|
||||
|
||||
ptr = next;
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This entry didn't contain the key; move to the next one */
|
||||
ptr = ptr->next;
|
||||
}
|
||||
/* This entry didn't contain the key; move to the next one */
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
/* The key was not found, so return 0 */
|
||||
return deleted;
|
||||
/* The key was not found, so return 0 */
|
||||
return deleted;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: hashmap.h,v 1.3 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: hashmap.h,v 1.4 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* A hashmap implementation. The keys are case-insensitive NULL terminated
|
||||
* strings, and the data is arbitrary lumps of data. Copies of both the
|
||||
@ -38,15 +38,15 @@ extern "C" {
|
||||
* hash map. Sure, it's a pointer, but the struct is hidden in the C file.
|
||||
* So, just use the hashmap_t like it's a cookie. :)
|
||||
*/
|
||||
typedef struct hashmap_s* hashmap_t;
|
||||
typedef int hashmap_iter;
|
||||
typedef struct hashmap_s *hashmap_t;
|
||||
typedef int hashmap_iter;
|
||||
|
||||
/*
|
||||
* hashmap_create() takes one argument, which is the number of buckets to
|
||||
* use internally. hashmap_delete() is self explanatory.
|
||||
*/
|
||||
extern hashmap_t hashmap_create(unsigned int nbuckets);
|
||||
extern int hashmap_delete(hashmap_t map);
|
||||
extern hashmap_t hashmap_create(unsigned int nbuckets);
|
||||
extern int hashmap_delete(hashmap_t map);
|
||||
|
||||
/*
|
||||
* When the you insert a key/data pair into the hashmap it will the key
|
||||
@ -57,15 +57,15 @@ extern int hashmap_delete(hashmap_t map);
|
||||
* Returns: negative on error
|
||||
* 0 upon successful insert
|
||||
*/
|
||||
extern int hashmap_insert(hashmap_t map, const char *key,
|
||||
const void *data, size_t len);
|
||||
extern int hashmap_insert(hashmap_t map, const char *key,
|
||||
const void *data, size_t len);
|
||||
|
||||
/*
|
||||
* Get an iterator to the first entry.
|
||||
*
|
||||
* Returns: an negative value upon error.
|
||||
*/
|
||||
extern hashmap_iter hashmap_first(hashmap_t map);
|
||||
extern hashmap_iter hashmap_first(hashmap_t map);
|
||||
|
||||
/*
|
||||
* Checks to see if the iterator is pointing at the "end" of the entries.
|
||||
@ -73,7 +73,7 @@ extern hashmap_iter hashmap_first(hashmap_t map);
|
||||
* Returns: 1 if it is the end
|
||||
* 0 otherwise
|
||||
*/
|
||||
extern int hashmap_is_end(hashmap_t map, hashmap_iter iter);
|
||||
extern int hashmap_is_end(hashmap_t map, hashmap_iter iter);
|
||||
|
||||
/*
|
||||
* Return a "pointer" to the first instance of the particular key. It can
|
||||
@ -83,7 +83,7 @@ extern int hashmap_is_end(hashmap_t map, hashmap_iter iter);
|
||||
* an "iterator" pointing at the first key
|
||||
* an "end-iterator" if the key wasn't found
|
||||
*/
|
||||
extern hashmap_iter hashmap_find(hashmap_t map, const char* key);
|
||||
extern hashmap_iter hashmap_find(hashmap_t map, const char *key);
|
||||
|
||||
/*
|
||||
* Retrieve the key/data associated with a particular iterator.
|
||||
@ -93,8 +93,8 @@ extern hashmap_iter hashmap_find(hashmap_t map, const char* key);
|
||||
* Returns: the length of the data block upon success
|
||||
* negative upon error
|
||||
*/
|
||||
extern ssize_t hashmap_return_entry(hashmap_t map, hashmap_iter iter,
|
||||
char** key, void** data);
|
||||
extern ssize_t hashmap_return_entry(hashmap_t map, hashmap_iter iter,
|
||||
char **key, void **data);
|
||||
|
||||
/*
|
||||
* Get the first entry (assuming there is more than one) for a particular
|
||||
@ -104,7 +104,8 @@ extern ssize_t hashmap_return_entry(hashmap_t map, hashmap_iter iter,
|
||||
* zero if no entry is found
|
||||
* length of data for the entry
|
||||
*/
|
||||
extern ssize_t hashmap_entry_by_key(hashmap_t map, const char* key, void** data);
|
||||
extern ssize_t hashmap_entry_by_key(hashmap_t map, const char *key,
|
||||
void **data);
|
||||
|
||||
/*
|
||||
* Searches for _any_ occurrances of "key" within the hashmap and returns the
|
||||
@ -114,7 +115,7 @@ extern ssize_t hashmap_entry_by_key(hashmap_t map, const char* key, void** data)
|
||||
* zero if no key is found
|
||||
* count found (positive value)
|
||||
*/
|
||||
extern ssize_t hashmap_search(hashmap_t map, const char *key);
|
||||
extern ssize_t hashmap_search(hashmap_t map, const char *key);
|
||||
|
||||
/*
|
||||
* Go through the hashmap and remove the particular key.
|
||||
@ -124,10 +125,9 @@ extern ssize_t hashmap_search(hashmap_t map, const char *key);
|
||||
* 0 if the key was not found
|
||||
* positive count of entries deleted
|
||||
*/
|
||||
extern ssize_t hashmap_remove(hashmap_t map, const char *key);
|
||||
extern ssize_t hashmap_remove(hashmap_t map, const char *key);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* C++ */
|
||||
|
||||
#endif /* _HASHMAP_H */
|
||||
#endif /* C++ */
|
||||
#endif /* _HASHMAP_H */
|
||||
|
127
src/heap.c
127
src/heap.c
@ -1,4 +1,4 @@
|
||||
/* $Id: heap.c,v 1.9 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: heap.c,v 1.10 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Debugging versions of various heap related functions are combined
|
||||
* here. The debugging versions include assertions and also print
|
||||
@ -25,70 +25,70 @@
|
||||
|
||||
void *
|
||||
debugging_calloc(size_t nmemb, size_t size, const char *file,
|
||||
unsigned long line)
|
||||
unsigned long line)
|
||||
{
|
||||
void *ptr;
|
||||
void *ptr;
|
||||
|
||||
assert(nmemb > 0);
|
||||
assert(size > 0);
|
||||
assert(nmemb > 0);
|
||||
assert(size > 0);
|
||||
|
||||
ptr = calloc(nmemb, size);
|
||||
fprintf(stderr, "{calloc: %p:%u x %u} %s:%lu\n", ptr, nmemb, size, file,
|
||||
line);
|
||||
return ptr;
|
||||
ptr = calloc(nmemb, size);
|
||||
fprintf(stderr, "{calloc: %p:%u x %u} %s:%lu\n", ptr, nmemb, size, file,
|
||||
line);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
debugging_malloc(size_t size, const char *file, unsigned long line)
|
||||
{
|
||||
void *ptr;
|
||||
void *ptr;
|
||||
|
||||
assert(size > 0);
|
||||
assert(size > 0);
|
||||
|
||||
ptr = malloc(size);
|
||||
fprintf(stderr, "{malloc: %p:%u} %s:%lu\n", ptr, size, file, line);
|
||||
return ptr;
|
||||
ptr = malloc(size);
|
||||
fprintf(stderr, "{malloc: %p:%u} %s:%lu\n", ptr, size, file, line);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *
|
||||
debugging_realloc(void *ptr, size_t size, const char *file, unsigned long line)
|
||||
{
|
||||
void *newptr;
|
||||
|
||||
assert(size > 0);
|
||||
|
||||
newptr = realloc(ptr, size);
|
||||
fprintf(stderr, "{realloc: %p -> %p:%u} %s:%lu\n", ptr, newptr, size,
|
||||
file, line);
|
||||
return newptr;
|
||||
void *newptr;
|
||||
|
||||
assert(size > 0);
|
||||
|
||||
newptr = realloc(ptr, size);
|
||||
fprintf(stderr, "{realloc: %p -> %p:%u} %s:%lu\n", ptr, newptr, size,
|
||||
file, line);
|
||||
return newptr;
|
||||
}
|
||||
|
||||
void
|
||||
debugging_free(void *ptr, const char *file, unsigned long line)
|
||||
{
|
||||
fprintf(stderr, "{free: %p} %s:%lu\n", ptr, file, line);
|
||||
fprintf(stderr, "{free: %p} %s:%lu\n", ptr, file, line);
|
||||
|
||||
if (ptr != NULL)
|
||||
free(ptr);
|
||||
return;
|
||||
if (ptr != NULL)
|
||||
free(ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
char*
|
||||
debugging_strdup(const char* s, const char* file, unsigned long line)
|
||||
char *
|
||||
debugging_strdup(const char *s, const char *file, unsigned long line)
|
||||
{
|
||||
char* ptr;
|
||||
size_t len;
|
||||
char *ptr;
|
||||
size_t len;
|
||||
|
||||
assert(s != NULL);
|
||||
assert(s != NULL);
|
||||
|
||||
len = strlen(s) + 1;
|
||||
ptr = malloc(len);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
memcpy(ptr, s, len);
|
||||
len = strlen(s) + 1;
|
||||
ptr = malloc(len);
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
memcpy(ptr, s, len);
|
||||
|
||||
fprintf(stderr, "{strdup: %p:%u} %s:%lu\n", ptr, len, file, line);
|
||||
return ptr;
|
||||
fprintf(stderr, "{strdup: %p:%u} %s:%lu\n", ptr, len, file, line);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -99,51 +99,50 @@ debugging_strdup(const char* s, const char* file, unsigned long line)
|
||||
* want to look into something like MM (Shared Memory Library) for a better
|
||||
* solution.
|
||||
*/
|
||||
void*
|
||||
void *
|
||||
malloc_shared_memory(size_t size)
|
||||
{
|
||||
int fd;
|
||||
void* ptr;
|
||||
char buffer[32];
|
||||
int fd;
|
||||
void *ptr;
|
||||
char buffer[32];
|
||||
|
||||
static char* shared_file = "/tmp/tinyproxy.shared.XXXXXX";
|
||||
static char *shared_file = "/tmp/tinyproxy.shared.XXXXXX";
|
||||
|
||||
assert(size > 0);
|
||||
assert(size > 0);
|
||||
|
||||
strlcpy(buffer, shared_file, sizeof(buffer));
|
||||
strlcpy(buffer, shared_file, sizeof(buffer));
|
||||
|
||||
if ((fd = mkstemp(buffer)) == -1)
|
||||
return MAP_FAILED;
|
||||
unlink(buffer);
|
||||
if ((fd = mkstemp(buffer)) == -1)
|
||||
return MAP_FAILED;
|
||||
unlink(buffer);
|
||||
|
||||
if (ftruncate(fd, size) == -1)
|
||||
return MAP_FAILED;
|
||||
ptr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
if (ftruncate(fd, size) == -1)
|
||||
return MAP_FAILED;
|
||||
ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a block of memory from the "shared" region an initialize it to
|
||||
* zero.
|
||||
*/
|
||||
void*
|
||||
void *
|
||||
calloc_shared_memory(size_t nmemb, size_t size)
|
||||
{
|
||||
void* ptr;
|
||||
long length;
|
||||
void *ptr;
|
||||
long length;
|
||||
|
||||
assert(nmemb > 0);
|
||||
assert(size > 0);
|
||||
assert(nmemb > 0);
|
||||
assert(size > 0);
|
||||
|
||||
length = nmemb * size;
|
||||
length = nmemb * size;
|
||||
|
||||
ptr = malloc_shared_memory(length);
|
||||
if (ptr == MAP_FAILED)
|
||||
return ptr;
|
||||
ptr = malloc_shared_memory(length);
|
||||
if (ptr == MAP_FAILED)
|
||||
return ptr;
|
||||
|
||||
memset(ptr, 0, length);
|
||||
memset(ptr, 0, length);
|
||||
|
||||
return ptr;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
16
src/heap.h
16
src/heap.h
@ -1,4 +1,4 @@
|
||||
/* $Id: heap.h,v 1.5 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: heap.h,v 1.6 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'heap.c' for a detailed description.
|
||||
*
|
||||
@ -24,14 +24,14 @@
|
||||
#ifndef NDEBUG
|
||||
|
||||
extern void *debugging_calloc(size_t nmemb, size_t size, const char *file,
|
||||
unsigned long line);
|
||||
unsigned long line);
|
||||
extern void *debugging_malloc(size_t size, const char *file,
|
||||
unsigned long line);
|
||||
unsigned long line);
|
||||
extern void debugging_free(void *ptr, const char *file, unsigned long line);
|
||||
extern void *debugging_realloc(void *ptr, size_t size, const char *file,
|
||||
unsigned long line);
|
||||
extern char *debugging_strdup(const char* s, const char* file,
|
||||
unsigned long line);
|
||||
unsigned long line);
|
||||
extern char *debugging_strdup(const char *s, const char *file,
|
||||
unsigned long line);
|
||||
|
||||
# define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__)
|
||||
# define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__)
|
||||
@ -57,7 +57,7 @@ free(*__safefree_tmp); \
|
||||
/*
|
||||
* Allocate memory from the "shared" region of memory.
|
||||
*/
|
||||
extern void* malloc_shared_memory(size_t size);
|
||||
extern void* calloc_shared_memory(size_t nmemb, size_t size);
|
||||
extern void *malloc_shared_memory(size_t size);
|
||||
extern void *calloc_shared_memory(size_t nmemb, size_t size);
|
||||
|
||||
#endif
|
||||
|
328
src/htmlerror.c
328
src/htmlerror.c
@ -1,4 +1,4 @@
|
||||
/* $Id: htmlerror.c,v 1.7 2003-08-01 00:14:34 rjkaes Exp $
|
||||
/* $Id: htmlerror.c,v 1.8 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* This file contains source code for the handling and display of
|
||||
* HTML error pages with variable substitution.
|
||||
@ -29,73 +29,77 @@
|
||||
/*
|
||||
* Add an error number -> filename mapping to the errorpages list.
|
||||
*/
|
||||
#define ERRORNUM_BUFSIZE 8 /* this is more than required */
|
||||
#define ERRORNUM_BUFSIZE 8 /* this is more than required */
|
||||
#define ERRPAGES_BUCKETCOUNT 16
|
||||
|
||||
int
|
||||
add_new_errorpage(char *filepath, unsigned int errornum) {
|
||||
char errornbuf[ERRORNUM_BUFSIZE];
|
||||
add_new_errorpage(char *filepath, unsigned int errornum)
|
||||
{
|
||||
char errornbuf[ERRORNUM_BUFSIZE];
|
||||
|
||||
config.errorpages = hashmap_create(ERRPAGES_BUCKETCOUNT);
|
||||
if (!config.errorpages)
|
||||
return(-1);
|
||||
config.errorpages = hashmap_create(ERRPAGES_BUCKETCOUNT);
|
||||
if (!config.errorpages)
|
||||
return (-1);
|
||||
|
||||
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
|
||||
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
|
||||
|
||||
if (hashmap_insert(config.errorpages, errornbuf,
|
||||
filepath, strlen(filepath) + 1) < 0)
|
||||
return(-1);
|
||||
if (hashmap_insert(config.errorpages, errornbuf,
|
||||
filepath, strlen(filepath) + 1) < 0)
|
||||
return (-1);
|
||||
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the file appropriate for a given error.
|
||||
*/
|
||||
static char*
|
||||
get_html_file(unsigned int errornum) {
|
||||
hashmap_iter result_iter;
|
||||
char errornbuf[ERRORNUM_BUFSIZE];
|
||||
char *key;
|
||||
static char *val;
|
||||
static char *
|
||||
get_html_file(unsigned int errornum)
|
||||
{
|
||||
hashmap_iter result_iter;
|
||||
char errornbuf[ERRORNUM_BUFSIZE];
|
||||
char *key;
|
||||
static char *val;
|
||||
|
||||
assert(errornum >= 100 && errornum < 1000);
|
||||
assert(errornum >= 100 && errornum < 1000);
|
||||
|
||||
if (!config.errorpages) return(config.errorpage_undef);
|
||||
if (!config.errorpages)
|
||||
return (config.errorpage_undef);
|
||||
|
||||
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
|
||||
snprintf(errornbuf, ERRORNUM_BUFSIZE, "%u", errornum);
|
||||
|
||||
result_iter = hashmap_find(config.errorpages, errornbuf);
|
||||
result_iter = hashmap_find(config.errorpages, errornbuf);
|
||||
|
||||
if (hashmap_is_end(config.errorpages, result_iter))
|
||||
return(config.errorpage_undef);
|
||||
if (hashmap_is_end(config.errorpages, result_iter))
|
||||
return (config.errorpage_undef);
|
||||
|
||||
if (hashmap_return_entry(config.errorpages, result_iter,
|
||||
&key, (void **)&val) < 0)
|
||||
return(config.errorpage_undef);
|
||||
if (hashmap_return_entry(config.errorpages, result_iter,
|
||||
&key, (void **)&val) < 0)
|
||||
return (config.errorpage_undef);
|
||||
|
||||
return(val);
|
||||
return (val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up the value for a variable.
|
||||
*/
|
||||
static char*
|
||||
lookup_variable(struct conn_s *connptr, char *varname) {
|
||||
hashmap_iter result_iter;
|
||||
char *key;
|
||||
static char *data;
|
||||
static char *
|
||||
lookup_variable(struct conn_s *connptr, char *varname)
|
||||
{
|
||||
hashmap_iter result_iter;
|
||||
char *key;
|
||||
static char *data;
|
||||
|
||||
result_iter = hashmap_find(connptr->error_variables, varname);
|
||||
result_iter = hashmap_find(connptr->error_variables, varname);
|
||||
|
||||
if (hashmap_is_end(connptr->error_variables, result_iter))
|
||||
return(NULL);
|
||||
if (hashmap_is_end(connptr->error_variables, result_iter))
|
||||
return (NULL);
|
||||
|
||||
if (hashmap_return_entry(connptr->error_variables, result_iter,
|
||||
&key, (void **)&data) < 0)
|
||||
return(NULL);
|
||||
if (hashmap_return_entry(connptr->error_variables, result_iter,
|
||||
&key, (void **)&data) < 0)
|
||||
return (NULL);
|
||||
|
||||
return(data);
|
||||
return (data);
|
||||
}
|
||||
|
||||
#define HTML_BUFSIZE 4096
|
||||
@ -104,66 +108,75 @@ lookup_variable(struct conn_s *connptr, char *varname) {
|
||||
* Send an already-opened file to the client with variable substitution.
|
||||
*/
|
||||
int
|
||||
send_html_file(FILE *infile, struct conn_s *connptr) {
|
||||
char inbuf[HTML_BUFSIZE], *varstart = NULL, *p;
|
||||
char *varval;
|
||||
int in_variable = 0, writeret;
|
||||
send_html_file(FILE * infile, struct conn_s *connptr)
|
||||
{
|
||||
char inbuf[HTML_BUFSIZE], *varstart = NULL, *p;
|
||||
char *varval;
|
||||
int in_variable = 0, writeret;
|
||||
|
||||
while(fgets(inbuf, HTML_BUFSIZE, infile) != NULL) {
|
||||
for (p = inbuf; *p; p++) {
|
||||
switch(*p) {
|
||||
case '}':
|
||||
if(in_variable) {
|
||||
*p = '\0';
|
||||
if(!(varval = lookup_variable(connptr, varstart)))
|
||||
varval = "(unknown)";
|
||||
writeret = write_message(connptr->client_fd, "%s",
|
||||
varval);
|
||||
if(writeret) return(writeret);
|
||||
in_variable = 0;
|
||||
} else {
|
||||
writeret = write_message(connptr->client_fd, "%c", *p);
|
||||
if (writeret) return(writeret);
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
/* a {{ will print a single {. If we are NOT
|
||||
* already in a { variable, then proceed with
|
||||
* setup. If we ARE already in a { variable,
|
||||
* this code will fallthrough to the code that
|
||||
* just dumps a character to the client fd.
|
||||
*/
|
||||
if(!in_variable) {
|
||||
varstart = p+1;
|
||||
in_variable++;
|
||||
} else
|
||||
in_variable = 0;
|
||||
default:
|
||||
if(!in_variable) {
|
||||
writeret = write_message(connptr->client_fd, "%c",
|
||||
*p);
|
||||
if(writeret) return(writeret);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
in_variable = 0;
|
||||
}
|
||||
return(0);
|
||||
while (fgets(inbuf, HTML_BUFSIZE, infile) != NULL) {
|
||||
for (p = inbuf; *p; p++) {
|
||||
switch (*p) {
|
||||
case '}':
|
||||
if (in_variable) {
|
||||
*p = '\0';
|
||||
if (!
|
||||
(varval =
|
||||
lookup_variable(connptr,
|
||||
varstart)))
|
||||
varval = "(unknown)";
|
||||
writeret =
|
||||
write_message(connptr->client_fd,
|
||||
"%s", varval);
|
||||
if (writeret)
|
||||
return (writeret);
|
||||
in_variable = 0;
|
||||
} else {
|
||||
writeret =
|
||||
write_message(connptr->client_fd,
|
||||
"%c", *p);
|
||||
if (writeret)
|
||||
return (writeret);
|
||||
}
|
||||
break;
|
||||
case '{':
|
||||
/* a {{ will print a single {. If we are NOT
|
||||
* already in a { variable, then proceed with
|
||||
* setup. If we ARE already in a { variable,
|
||||
* this code will fallthrough to the code that
|
||||
* just dumps a character to the client fd.
|
||||
*/
|
||||
if (!in_variable) {
|
||||
varstart = p + 1;
|
||||
in_variable++;
|
||||
} else
|
||||
in_variable = 0;
|
||||
default:
|
||||
if (!in_variable) {
|
||||
writeret =
|
||||
write_message(connptr->client_fd,
|
||||
"%c", *p);
|
||||
if (writeret)
|
||||
return (writeret);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
in_variable = 0;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
send_http_headers(struct conn_s *connptr, int code, char *message) {
|
||||
char *headers = \
|
||||
"HTTP/1.0 %d %s\r\n" \
|
||||
"Server: %s/%s\r\n" \
|
||||
"Content-Type: text/html\r\n" \
|
||||
"Connection: close\r\n" \
|
||||
"\r\n";
|
||||
send_http_headers(struct conn_s *connptr, int code, char *message)
|
||||
{
|
||||
char *headers =
|
||||
"HTTP/1.0 %d %s\r\n"
|
||||
"Server: %s/%s\r\n"
|
||||
"Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n";
|
||||
|
||||
return(write_message(connptr->client_fd, headers,
|
||||
code, message,
|
||||
PACKAGE, VERSION));
|
||||
return (write_message(connptr->client_fd, headers,
|
||||
code, message, PACKAGE, VERSION));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -172,33 +185,32 @@ send_http_headers(struct conn_s *connptr, int code, char *message) {
|
||||
int
|
||||
send_http_error_message(struct conn_s *connptr)
|
||||
{
|
||||
char *error_file;
|
||||
FILE *infile;
|
||||
int ret;
|
||||
char *fallback_error = \
|
||||
"<html><head><title>%s</title></head>" \
|
||||
"<body><blockquote><i>%s %s</i><br>" \
|
||||
"The page you requested was unavailable. The error code is listed " \
|
||||
"below. In addition, the HTML file which has been configured as the " \
|
||||
"page to be displayed when an error of this type was unavailable, " \
|
||||
"with the error code %d (%s). Please contact your administrator." \
|
||||
"<center>%s</center>" \
|
||||
"</body></html>" \
|
||||
"\r\n";
|
||||
char *error_file;
|
||||
FILE *infile;
|
||||
int ret;
|
||||
char *fallback_error =
|
||||
"<html><head><title>%s</title></head>"
|
||||
"<body><blockquote><i>%s %s</i><br>"
|
||||
"The page you requested was unavailable. The error code is listed "
|
||||
"below. In addition, the HTML file which has been configured as the "
|
||||
"page to be displayed when an error of this type was unavailable, "
|
||||
"with the error code %d (%s). Please contact your administrator."
|
||||
"<center>%s</center>" "</body></html>" "\r\n";
|
||||
|
||||
send_http_headers(connptr, connptr->error_number, connptr->error_string);
|
||||
send_http_headers(connptr, connptr->error_number,
|
||||
connptr->error_string);
|
||||
|
||||
error_file = get_html_file(connptr->error_number);
|
||||
if(!(infile = fopen(error_file, "r")))
|
||||
return(write_message(connptr->client_fd, fallback_error,
|
||||
connptr->error_string,
|
||||
PACKAGE, VERSION,
|
||||
errno, strerror(errno),
|
||||
connptr->error_string));
|
||||
error_file = get_html_file(connptr->error_number);
|
||||
if (!(infile = fopen(error_file, "r")))
|
||||
return (write_message(connptr->client_fd, fallback_error,
|
||||
connptr->error_string,
|
||||
PACKAGE, VERSION,
|
||||
errno, strerror(errno),
|
||||
connptr->error_string));
|
||||
|
||||
ret = send_html_file(infile, connptr);
|
||||
fclose(infile);
|
||||
return(ret);
|
||||
ret = send_html_file(infile, connptr);
|
||||
fclose(infile);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -207,18 +219,20 @@ send_http_error_message(struct conn_s *connptr)
|
||||
|
||||
#define ERRVAR_BUCKETCOUNT 16
|
||||
|
||||
int
|
||||
add_error_variable(struct conn_s *connptr, char *key, char *val)
|
||||
int
|
||||
add_error_variable(struct conn_s *connptr, char *key, char *val)
|
||||
{
|
||||
if(!connptr->error_variables)
|
||||
if (!(connptr->error_variables = hashmap_create(ERRVAR_BUCKETCOUNT)))
|
||||
return(-1);
|
||||
if (!connptr->error_variables)
|
||||
if (!
|
||||
(connptr->error_variables =
|
||||
hashmap_create(ERRVAR_BUCKETCOUNT)))
|
||||
return (-1);
|
||||
|
||||
if (hashmap_insert(connptr->error_variables, key, val,
|
||||
strlen(val) + 1) < 0)
|
||||
return(-1);
|
||||
if (hashmap_insert(connptr->error_variables, key, val,
|
||||
strlen(val) + 1) < 0)
|
||||
return (-1);
|
||||
|
||||
return(0);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#define ADD_VAR_RET(x, y) if(y) { if(add_error_variable(connptr, x, y) == -1) return(-1); }
|
||||
@ -227,46 +241,48 @@ add_error_variable(struct conn_s *connptr, char *key, char *val)
|
||||
* Set some standard variables used by all HTML pages
|
||||
*/
|
||||
int
|
||||
add_standard_vars(struct conn_s *connptr) {
|
||||
char timebuf[30];
|
||||
time_t global_time = time(NULL);
|
||||
add_standard_vars(struct conn_s *connptr)
|
||||
{
|
||||
char timebuf[30];
|
||||
time_t global_time = time(NULL);
|
||||
|
||||
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime(&global_time));
|
||||
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime(&global_time));
|
||||
|
||||
ADD_VAR_RET("request", connptr->request_line);
|
||||
ADD_VAR_RET("cause", connptr->error_string);
|
||||
ADD_VAR_RET("clientip", connptr->client_ip_addr);
|
||||
ADD_VAR_RET("clienthost", connptr->client_string_addr);
|
||||
ADD_VAR_RET("version", VERSION);
|
||||
ADD_VAR_RET("package", PACKAGE);
|
||||
ADD_VAR_RET("date", timebuf);
|
||||
return(0);
|
||||
ADD_VAR_RET("request", connptr->request_line);
|
||||
ADD_VAR_RET("cause", connptr->error_string);
|
||||
ADD_VAR_RET("clientip", connptr->client_ip_addr);
|
||||
ADD_VAR_RET("clienthost", connptr->client_string_addr);
|
||||
ADD_VAR_RET("version", VERSION);
|
||||
ADD_VAR_RET("package", PACKAGE);
|
||||
ADD_VAR_RET("date", timebuf);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the error information to the conn structure.
|
||||
*/
|
||||
int
|
||||
indicate_http_error(struct conn_s* connptr, int number, char *message, ...)
|
||||
indicate_http_error(struct conn_s *connptr, int number, char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char *key, *val;
|
||||
va_list ap;
|
||||
char *key, *val;
|
||||
|
||||
va_start(ap, message);
|
||||
va_start(ap, message);
|
||||
|
||||
while((key = va_arg(ap, char *))) {
|
||||
val = va_arg(ap, char *);
|
||||
if(add_error_variable(connptr, key, val) == -1) {
|
||||
va_end(ap);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
while ((key = va_arg(ap, char *))) {
|
||||
val = va_arg(ap, char *);
|
||||
|
||||
connptr->error_number = number;
|
||||
connptr->error_string = safestrdup(message);
|
||||
if (add_error_variable(connptr, key, val) == -1) {
|
||||
va_end(ap);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
connptr->error_number = number;
|
||||
connptr->error_string = safestrdup(message);
|
||||
|
||||
return(add_standard_vars(connptr));
|
||||
va_end(ap);
|
||||
|
||||
return (add_standard_vars(connptr));
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: htmlerror.h,v 1.2 2003-03-14 22:45:59 rjkaes Exp $
|
||||
/* $Id: htmlerror.h,v 1.3 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Contains header declarations for the HTML error functions in
|
||||
* htmlerror.c
|
||||
@ -24,10 +24,11 @@ struct conn_s;
|
||||
|
||||
extern int add_new_errorpage(char *filepath, unsigned int errornum);
|
||||
extern int send_http_error_message(struct conn_s *connptr);
|
||||
extern int indicate_http_error(struct conn_s *connptr, int number, char *message, ...);
|
||||
extern int indicate_http_error(struct conn_s *connptr, int number,
|
||||
char *message, ...);
|
||||
extern int add_error_variable(struct conn_s *connptr, char *key, char *val);
|
||||
extern int send_html_file(FILE *infile, struct conn_s *connptr);
|
||||
extern int send_html_file(FILE * infile, struct conn_s *connptr);
|
||||
extern int send_http_headers(struct conn_s *connptr, int code, char *message);
|
||||
extern int add_standard_vars(struct conn_s *connptr);
|
||||
|
||||
#endif /* !TINYPROXY_HTMLERROR_H */
|
||||
#endif /* !TINYPROXY_HTMLERROR_H */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: http_message.c,v 1.5 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: http_message.c,v 1.6 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'http_message.h' for a detailed description.
|
||||
*
|
||||
@ -28,28 +28,28 @@
|
||||
* still in use---bad things would happen.
|
||||
*/
|
||||
struct http_message_s {
|
||||
/* Response string and code supplied on the HTTP status line */
|
||||
struct {
|
||||
const char* string;
|
||||
int code;
|
||||
} response;
|
||||
|
||||
/*
|
||||
* A group of headers to be sent with this message. Right now
|
||||
* the strings are referenced through pointers in an array.
|
||||
* I might change this to a vector in the future.
|
||||
*/
|
||||
struct {
|
||||
char** strings;
|
||||
unsigned int total;
|
||||
unsigned int used;
|
||||
} headers;
|
||||
/* Response string and code supplied on the HTTP status line */
|
||||
struct {
|
||||
const char *string;
|
||||
int code;
|
||||
} response;
|
||||
|
||||
/* Body of the message (most likely an HTML message) */
|
||||
struct {
|
||||
const char* text;
|
||||
size_t length;
|
||||
} body;
|
||||
/*
|
||||
* A group of headers to be sent with this message. Right now
|
||||
* the strings are referenced through pointers in an array.
|
||||
* I might change this to a vector in the future.
|
||||
*/
|
||||
struct {
|
||||
char **strings;
|
||||
unsigned int total;
|
||||
unsigned int used;
|
||||
} headers;
|
||||
|
||||
/* Body of the message (most likely an HTML message) */
|
||||
struct {
|
||||
const char *text;
|
||||
size_t length;
|
||||
} body;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -60,12 +60,16 @@ struct http_message_s {
|
||||
static int
|
||||
is_http_message_valid(http_message_t msg)
|
||||
{
|
||||
if (msg == NULL) return 0;
|
||||
if (msg->headers.strings == NULL) return 0;
|
||||
if (msg->response.string == NULL) return 0;
|
||||
if (msg->response.code < 1 || msg->response.code > 999) return 0;
|
||||
if (msg == NULL)
|
||||
return 0;
|
||||
if (msg->headers.strings == NULL)
|
||||
return 0;
|
||||
if (msg->response.string == NULL)
|
||||
return 0;
|
||||
if (msg->response.code < 1 || msg->response.code > 999)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Initially allocate space for 128 headers */
|
||||
@ -76,32 +80,32 @@ is_http_message_valid(http_message_t msg)
|
||||
* If memory could not be allocated, return a NULL.
|
||||
*/
|
||||
http_message_t
|
||||
http_message_create(int response_code, const char* response_string)
|
||||
http_message_create(int response_code, const char *response_string)
|
||||
{
|
||||
http_message_t msg;
|
||||
int ret;
|
||||
http_message_t msg;
|
||||
int ret;
|
||||
|
||||
msg = safecalloc(1, sizeof(struct http_message_s));
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
msg = safecalloc(1, sizeof(struct http_message_s));
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
msg->headers.strings = safecalloc(NUMBER_OF_HEADERS, sizeof(char*));
|
||||
if (msg->headers.strings == NULL) {
|
||||
safefree(msg);
|
||||
return NULL;
|
||||
}
|
||||
msg->headers.strings = safecalloc(NUMBER_OF_HEADERS, sizeof(char *));
|
||||
if (msg->headers.strings == NULL) {
|
||||
safefree(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
msg->headers.total = NUMBER_OF_HEADERS;
|
||||
msg->headers.total = NUMBER_OF_HEADERS;
|
||||
|
||||
/* Store the HTTP response information in the structure */
|
||||
ret = http_message_set_response(msg, response_code, response_string);
|
||||
if (IS_HTTP_MSG_ERROR(ret)) {
|
||||
safefree(msg->headers.strings);
|
||||
safefree(msg);
|
||||
return NULL;
|
||||
}
|
||||
/* Store the HTTP response information in the structure */
|
||||
ret = http_message_set_response(msg, response_code, response_string);
|
||||
if (IS_HTTP_MSG_ERROR(ret)) {
|
||||
safefree(msg->headers.strings);
|
||||
safefree(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -112,16 +116,17 @@ http_message_create(int response_code, const char* response_string)
|
||||
int
|
||||
http_message_destroy(http_message_t msg)
|
||||
{
|
||||
assert(msg != NULL);
|
||||
assert(msg->headers.strings != NULL);
|
||||
assert(msg != NULL);
|
||||
assert(msg->headers.strings != NULL);
|
||||
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL) return -EFAULT;
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL)
|
||||
return -EFAULT;
|
||||
|
||||
if (msg->headers.strings != NULL)
|
||||
safefree(msg->headers.strings);
|
||||
safefree(msg);
|
||||
return 0;
|
||||
if (msg->headers.strings != NULL)
|
||||
safefree(msg->headers.strings);
|
||||
safefree(msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -130,81 +135,89 @@ http_message_destroy(http_message_t msg)
|
||||
*/
|
||||
int
|
||||
http_message_set_response(http_message_t msg,
|
||||
int response_code,
|
||||
const char* response_string)
|
||||
int response_code, const char *response_string)
|
||||
{
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL) return -EFAULT;
|
||||
if (response_code < 1 || response_code > 999) return -EINVAL;
|
||||
if (response_string == NULL) return -EINVAL;
|
||||
if (strlen(response_string) == 0) return -EINVAL;
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL)
|
||||
return -EFAULT;
|
||||
if (response_code < 1 || response_code > 999)
|
||||
return -EINVAL;
|
||||
if (response_string == NULL)
|
||||
return -EINVAL;
|
||||
if (strlen(response_string) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
msg->response.code = response_code;
|
||||
msg->response.string = response_string;
|
||||
msg->response.code = response_code;
|
||||
msg->response.string = response_string;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the HTTP message body.
|
||||
*/
|
||||
int
|
||||
http_message_set_body(http_message_t msg, const char* body, size_t len)
|
||||
http_message_set_body(http_message_t msg, const char *body, size_t len)
|
||||
{
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL) return -EFAULT;
|
||||
if (body == NULL) return -EINVAL;
|
||||
if (len == 0) return -EINVAL;
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL)
|
||||
return -EFAULT;
|
||||
if (body == NULL)
|
||||
return -EINVAL;
|
||||
if (len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
msg->body.text = body;
|
||||
msg->body.length = len;
|
||||
msg->body.text = body;
|
||||
msg->body.length = len;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add headers to the structure.
|
||||
*/
|
||||
int
|
||||
http_message_add_headers(http_message_t msg, char** headers,
|
||||
int num_headers)
|
||||
http_message_add_headers(http_message_t msg, char **headers, int num_headers)
|
||||
{
|
||||
char** new_headers;
|
||||
int i;
|
||||
char **new_headers;
|
||||
int i;
|
||||
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL) return -EFAULT;
|
||||
if (headers == NULL) return -EINVAL;
|
||||
if (num_headers < 1) return -EINVAL;
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL)
|
||||
return -EFAULT;
|
||||
if (headers == NULL)
|
||||
return -EINVAL;
|
||||
if (num_headers < 1)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If the number of headers to add is greater than the space
|
||||
* available, reallocate the memory.
|
||||
*/
|
||||
if (msg->headers.used + num_headers > msg->headers.total) {
|
||||
new_headers = safecalloc(msg->headers.total * 2,
|
||||
sizeof(char*));
|
||||
if (new_headers == NULL)
|
||||
return -ENOMEM;
|
||||
/*
|
||||
* If the number of headers to add is greater than the space
|
||||
* available, reallocate the memory.
|
||||
*/
|
||||
if (msg->headers.used + num_headers > msg->headers.total) {
|
||||
new_headers = safecalloc(msg->headers.total * 2,
|
||||
sizeof(char *));
|
||||
if (new_headers == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Copy the array */
|
||||
for (i = 0; i != msg->headers.used; ++i)
|
||||
new_headers[i] = msg->headers.strings[i];
|
||||
/* Copy the array */
|
||||
for (i = 0; i != msg->headers.used; ++i)
|
||||
new_headers[i] = msg->headers.strings[i];
|
||||
|
||||
/* Remove the old array and replace it with the new array */
|
||||
safefree(msg->headers.strings);
|
||||
msg->headers.strings = new_headers;
|
||||
msg->headers.total *= 2;
|
||||
}
|
||||
/* Remove the old array and replace it with the new array */
|
||||
safefree(msg->headers.strings);
|
||||
msg->headers.strings = new_headers;
|
||||
msg->headers.total *= 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the new headers to the structure
|
||||
*/
|
||||
for (i = 0; i != num_headers; ++i)
|
||||
msg->headers.strings[i + msg->headers.used] = headers[i];
|
||||
msg->headers.used += num_headers;
|
||||
/*
|
||||
* Add the new headers to the structure
|
||||
*/
|
||||
for (i = 0; i != num_headers; ++i)
|
||||
msg->headers.strings[i + msg->headers.used] = headers[i];
|
||||
msg->headers.used += num_headers;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -213,40 +226,43 @@ http_message_add_headers(http_message_t msg, char** headers,
|
||||
int
|
||||
http_message_send(http_message_t msg, int fd)
|
||||
{
|
||||
char timebuf[30];
|
||||
time_t global_time;
|
||||
unsigned int i;
|
||||
char timebuf[30];
|
||||
time_t global_time;
|
||||
unsigned int i;
|
||||
|
||||
assert(is_http_message_valid(msg));
|
||||
assert(is_http_message_valid(msg));
|
||||
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL) return -EFAULT;
|
||||
if (fd < 1) return -EBADF;
|
||||
if (!is_http_message_valid(msg)) return -EINVAL;
|
||||
/* Check for valid arguments */
|
||||
if (msg == NULL)
|
||||
return -EFAULT;
|
||||
if (fd < 1)
|
||||
return -EBADF;
|
||||
if (!is_http_message_valid(msg))
|
||||
return -EINVAL;
|
||||
|
||||
/* Write the response line */
|
||||
write_message(fd, "HTTP/1.0 %d %s\r\n",
|
||||
msg->response.code, msg->response.string);
|
||||
/* Write the response line */
|
||||
write_message(fd, "HTTP/1.0 %d %s\r\n",
|
||||
msg->response.code, msg->response.string);
|
||||
|
||||
/* Go through all the headers */
|
||||
for (i = 0; i != msg->headers.used; ++i)
|
||||
write_message(fd, "%s\r\n", msg->headers.strings[i]);
|
||||
/* Go through all the headers */
|
||||
for (i = 0; i != msg->headers.used; ++i)
|
||||
write_message(fd, "%s\r\n", msg->headers.strings[i]);
|
||||
|
||||
/* Output the date */
|
||||
global_time = time(NULL);
|
||||
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime(&global_time));
|
||||
write_message(fd, "Date: %s\r\n", timebuf);
|
||||
/* Output the date */
|
||||
global_time = time(NULL);
|
||||
strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime(&global_time));
|
||||
write_message(fd, "Date: %s\r\n", timebuf);
|
||||
|
||||
/* Output the content-length */
|
||||
write_message(fd, "Content-length: %u\r\n", msg->body.length);
|
||||
/* Output the content-length */
|
||||
write_message(fd, "Content-length: %u\r\n", msg->body.length);
|
||||
|
||||
/* Write the separator between the headers and body */
|
||||
safe_write(fd, "\r\n", 2);
|
||||
/* Write the separator between the headers and body */
|
||||
safe_write(fd, "\r\n", 2);
|
||||
|
||||
/* If there's a body, send it! */
|
||||
if (msg->body.length > 0)
|
||||
safe_write(fd, msg->body.text, msg->body.length);
|
||||
/* If there's a body, send it! */
|
||||
if (msg->body.length > 0)
|
||||
safe_write(fd, msg->body.text, msg->body.length);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: http_message.h,v 1.2 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: http_message.h,v 1.3 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* HTTP Message API
|
||||
* ----------------
|
||||
@ -55,7 +55,7 @@ typedef struct http_message_s *http_message_t;
|
||||
|
||||
/* Initialize the internal structure of the HTTP message */
|
||||
extern http_message_t http_message_create(int response_code,
|
||||
const char* response_string);
|
||||
const char *response_string);
|
||||
|
||||
/* Free up an _internal_ resources */
|
||||
extern int http_message_destroy(http_message_t msg);
|
||||
@ -72,10 +72,10 @@ extern int http_message_send(http_message_t msg, int fd);
|
||||
* add a new set of headers.
|
||||
*/
|
||||
extern int http_message_set_body(http_message_t msg,
|
||||
const char* body, size_t len);
|
||||
const char *body, size_t len);
|
||||
extern int http_message_set_response(http_message_t msg,
|
||||
int response_code,
|
||||
const char* response_string);
|
||||
int response_code,
|
||||
const char *response_string);
|
||||
|
||||
/*
|
||||
* Set the headers for this HTTP message. Each string must be NUL ('\0')
|
||||
@ -84,7 +84,6 @@ extern int http_message_set_response(http_message_t msg,
|
||||
* sent.
|
||||
*/
|
||||
extern int http_message_add_headers(http_message_t msg,
|
||||
char** headers,
|
||||
int num_headers);
|
||||
char **headers, int num_headers);
|
||||
|
||||
#endif /* _TINYPROXY_HTTP_MESSAGE_H_ */
|
||||
#endif /* _TINYPROXY_HTTP_MESSAGE_H_ */
|
||||
|
187
src/log.c
187
src/log.c
@ -1,4 +1,4 @@
|
||||
/* $Id: log.c,v 1.30 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: log.c,v 1.31 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Logs the various messages which tinyproxy produces to either a log file or
|
||||
* the syslog daemon. Not much to it...
|
||||
@ -25,15 +25,15 @@
|
||||
#include "vector.h"
|
||||
|
||||
static char *syslog_level[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
"CRITICAL",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"NOTICE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
"CONNECT"
|
||||
NULL,
|
||||
NULL,
|
||||
"CRITICAL",
|
||||
"ERROR",
|
||||
"WARNING",
|
||||
"NOTICE",
|
||||
"INFO",
|
||||
"DEBUG",
|
||||
"CONNECT"
|
||||
};
|
||||
|
||||
#define TIME_LENGTH 16
|
||||
@ -61,10 +61,10 @@ static vector_t log_message_storage;
|
||||
* Open the log file and store the file descriptor in a global location.
|
||||
*/
|
||||
int
|
||||
open_log_file(const char* log_file_name)
|
||||
open_log_file(const char *log_file_name)
|
||||
{
|
||||
log_file_fd = create_file_safely(log_file_name, FALSE);
|
||||
return log_file_fd;
|
||||
log_file_fd = create_file_safely(log_file_name, FALSE);
|
||||
return log_file_fd;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -73,7 +73,7 @@ open_log_file(const char* log_file_name)
|
||||
void
|
||||
close_log_file(void)
|
||||
{
|
||||
close(log_file_fd);
|
||||
close(log_file_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -82,8 +82,8 @@ close_log_file(void)
|
||||
void
|
||||
truncate_log_file(void)
|
||||
{
|
||||
lseek(log_file_fd, 0, SEEK_SET);
|
||||
ftruncate(log_file_fd, 0);
|
||||
lseek(log_file_fd, 0, SEEK_SET);
|
||||
ftruncate(log_file_fd, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -92,7 +92,7 @@ truncate_log_file(void)
|
||||
void
|
||||
set_log_level(int level)
|
||||
{
|
||||
log_level = level;
|
||||
log_level = level;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -101,92 +101,91 @@ set_log_level(int level)
|
||||
void
|
||||
log_message(int level, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
time_t nowtime;
|
||||
va_list args;
|
||||
time_t nowtime;
|
||||
|
||||
char time_string[TIME_LENGTH];
|
||||
char str[STRING_LENGTH];
|
||||
char time_string[TIME_LENGTH];
|
||||
char str[STRING_LENGTH];
|
||||
|
||||
#ifdef NDEBUG
|
||||
/*
|
||||
* Figure out if we should write the message or not.
|
||||
*/
|
||||
if (log_level == LOG_CONN) {
|
||||
if (level == LOG_INFO)
|
||||
return;
|
||||
} else if (log_level == LOG_INFO) {
|
||||
if (level > LOG_INFO && level != LOG_CONN)
|
||||
return;
|
||||
} else if (level > log_level)
|
||||
return;
|
||||
/*
|
||||
* Figure out if we should write the message or not.
|
||||
*/
|
||||
if (log_level == LOG_CONN) {
|
||||
if (level == LOG_INFO)
|
||||
return;
|
||||
} else if (log_level == LOG_INFO) {
|
||||
if (level > LOG_INFO && level != LOG_CONN)
|
||||
return;
|
||||
} else if (level > log_level)
|
||||
return;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if (config.syslog && level == LOG_CONN)
|
||||
level = LOG_INFO;
|
||||
if (config.syslog && level == LOG_CONN)
|
||||
level = LOG_INFO;
|
||||
#endif
|
||||
|
||||
va_start(args, fmt);
|
||||
va_start(args, fmt);
|
||||
|
||||
/*
|
||||
* If the config file hasn't been processed, then we need to store
|
||||
* the messages for later processing.
|
||||
*/
|
||||
if (!processed_config_file) {
|
||||
char* entry_buffer;
|
||||
/*
|
||||
* If the config file hasn't been processed, then we need to store
|
||||
* the messages for later processing.
|
||||
*/
|
||||
if (!processed_config_file) {
|
||||
char *entry_buffer;
|
||||
|
||||
if (!log_message_storage) {
|
||||
log_message_storage = vector_create();
|
||||
if (!log_message_storage)
|
||||
return;
|
||||
}
|
||||
if (!log_message_storage) {
|
||||
log_message_storage = vector_create();
|
||||
if (!log_message_storage)
|
||||
return;
|
||||
}
|
||||
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
|
||||
entry_buffer = safemalloc(strlen(str) + 6);
|
||||
if (!entry_buffer)
|
||||
return;
|
||||
|
||||
sprintf(entry_buffer, "%d %s", level, str);
|
||||
vector_append(log_message_storage, entry_buffer,
|
||||
strlen(entry_buffer) + 1);
|
||||
entry_buffer = safemalloc(strlen(str) + 6);
|
||||
if (!entry_buffer)
|
||||
return;
|
||||
|
||||
va_end(args);
|
||||
sprintf(entry_buffer, "%d %s", level, str);
|
||||
vector_append(log_message_storage, entry_buffer,
|
||||
strlen(entry_buffer) + 1);
|
||||
|
||||
return;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
if (config.syslog) {
|
||||
if (config.syslog) {
|
||||
# ifdef HAVE_VSYSLOG_H
|
||||
vsyslog(level, fmt, args);
|
||||
vsyslog(level, fmt, args);
|
||||
# else
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
syslog(level, "%s", str);
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
syslog(level, "%s", str);
|
||||
# endif
|
||||
} else {
|
||||
} else {
|
||||
#endif
|
||||
nowtime = time(NULL);
|
||||
/* Format is month day hour:minute:second (24 time) */
|
||||
strftime(time_string, TIME_LENGTH, "%b %d %H:%M:%S",
|
||||
localtime(&nowtime));
|
||||
nowtime = time(NULL);
|
||||
/* Format is month day hour:minute:second (24 time) */
|
||||
strftime(time_string, TIME_LENGTH, "%b %d %H:%M:%S",
|
||||
localtime(&nowtime));
|
||||
|
||||
snprintf(str, STRING_LENGTH, "%-9s %s [%ld]: ", syslog_level[level],
|
||||
time_string, (long int) getpid());
|
||||
snprintf(str, STRING_LENGTH, "%-9s %s [%ld]: ",
|
||||
syslog_level[level], time_string, (long int)getpid());
|
||||
|
||||
assert(log_file_fd >= 0);
|
||||
assert(log_file_fd >= 0);
|
||||
|
||||
write(log_file_fd, str, strlen(str));
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
write(log_file_fd, str, strlen(str));
|
||||
write(log_file_fd, "\n", 1);
|
||||
write(log_file_fd, str, strlen(str));
|
||||
vsnprintf(str, STRING_LENGTH, fmt, args);
|
||||
write(log_file_fd, str, strlen(str));
|
||||
write(log_file_fd, "\n", 1);
|
||||
fsync(log_file_fd);
|
||||
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
va_end(args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -195,32 +194,32 @@ log_message(int level, char *fmt, ...)
|
||||
void
|
||||
send_stored_logs(void)
|
||||
{
|
||||
char *string;
|
||||
char *ptr;
|
||||
char *string;
|
||||
char *ptr;
|
||||
|
||||
int level;
|
||||
int level;
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != vector_length(log_message_storage); ++i) {
|
||||
string = vector_getentry(log_message_storage, i, NULL);
|
||||
for (i = 0; i != vector_length(log_message_storage); ++i) {
|
||||
string = vector_getentry(log_message_storage, i, NULL);
|
||||
|
||||
ptr = strchr(string, ' ') + 1;
|
||||
level = atoi(string);
|
||||
ptr = strchr(string, ' ') + 1;
|
||||
level = atoi(string);
|
||||
|
||||
#ifdef NDEBUG
|
||||
if (log_level == LOG_CONN && level == LOG_INFO)
|
||||
continue;
|
||||
else if (log_level == LOG_INFO) {
|
||||
if (level > LOG_INFO && level != LOG_CONN)
|
||||
continue;
|
||||
} else if (level > log_level)
|
||||
continue;
|
||||
if (log_level == LOG_CONN && level == LOG_INFO)
|
||||
continue;
|
||||
else if (log_level == LOG_INFO) {
|
||||
if (level > LOG_INFO && level != LOG_CONN)
|
||||
continue;
|
||||
} else if (level > log_level)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
log_message(level, ptr);
|
||||
}
|
||||
log_message(level, ptr);
|
||||
}
|
||||
|
||||
vector_delete(log_message_storage);
|
||||
log_message_storage = NULL;
|
||||
vector_delete(log_message_storage);
|
||||
log_message_storage = NULL;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: log.h,v 1.12 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: log.h,v 1.13 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'log.c' for a detailed description.
|
||||
*
|
||||
@ -84,7 +84,7 @@
|
||||
# define LOG_DEBUG 7
|
||||
#endif
|
||||
|
||||
#define LOG_CONN 8 /* extra to log connections without the INFO stuff */
|
||||
#define LOG_CONN 8 /* extra to log connections without the INFO stuff */
|
||||
|
||||
/*
|
||||
* Use this for debugging. The format is specific:
|
||||
@ -99,7 +99,7 @@
|
||||
# define DEBUG2(x, y...) do { } while(0)
|
||||
#endif
|
||||
|
||||
extern int open_log_file(const char* file);
|
||||
extern int open_log_file(const char *file);
|
||||
extern void close_log_file(void);
|
||||
extern void truncate_log_file(void);
|
||||
|
||||
|
378
src/network.c
378
src/network.c
@ -1,4 +1,4 @@
|
||||
/* $Id: network.c,v 1.4 2004-02-18 20:17:18 rjkaes Exp $
|
||||
/* $Id: network.c,v 1.5 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* The functions found here are used for communicating across a
|
||||
* network. They include both safe reading and writing (which are
|
||||
@ -31,33 +31,33 @@
|
||||
ssize_t
|
||||
safe_write(int fd, const char *buffer, size_t count)
|
||||
{
|
||||
ssize_t len;
|
||||
size_t bytestosend;
|
||||
ssize_t len;
|
||||
size_t bytestosend;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(buffer != NULL);
|
||||
assert(count > 0);
|
||||
assert(fd >= 0);
|
||||
assert(buffer != NULL);
|
||||
assert(count > 0);
|
||||
|
||||
bytestosend = count;
|
||||
bytestosend = count;
|
||||
|
||||
while (1) {
|
||||
len = send(fd, buffer, bytestosend, MSG_NOSIGNAL);
|
||||
while (1) {
|
||||
len = send(fd, buffer, bytestosend, MSG_NOSIGNAL);
|
||||
|
||||
if (len < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
if (len < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (len == bytestosend)
|
||||
break;
|
||||
if (len == bytestosend)
|
||||
break;
|
||||
|
||||
buffer += len;
|
||||
bytestosend -= len;
|
||||
}
|
||||
buffer += len;
|
||||
bytestosend -= len;
|
||||
}
|
||||
|
||||
return count;
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -67,13 +67,13 @@ safe_write(int fd, const char *buffer, size_t count)
|
||||
ssize_t
|
||||
safe_read(int fd, char *buffer, size_t count)
|
||||
{
|
||||
ssize_t len;
|
||||
ssize_t len;
|
||||
|
||||
do {
|
||||
len = read(fd, buffer, count);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
do {
|
||||
len = read(fd, buffer, count);
|
||||
} while (len < 0 && errno == EINTR);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -85,45 +85,45 @@ safe_read(int fd, char *buffer, size_t count)
|
||||
int
|
||||
write_message(int fd, const char *fmt, ...)
|
||||
{
|
||||
ssize_t n;
|
||||
size_t size = (1024 * 8); /* start with 8 KB and go from there */
|
||||
char *buf, *tmpbuf;
|
||||
va_list ap;
|
||||
ssize_t n;
|
||||
size_t size = (1024 * 8); /* start with 8 KB and go from there */
|
||||
char *buf, *tmpbuf;
|
||||
va_list ap;
|
||||
|
||||
if ((buf = safemalloc(size)) == NULL)
|
||||
return -1;
|
||||
if ((buf = safemalloc(size)) == NULL)
|
||||
return -1;
|
||||
|
||||
while (1) {
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(buf, size, fmt, ap);
|
||||
va_end(ap);
|
||||
while (1) {
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(buf, size, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* If that worked, break out so we can send the buffer */
|
||||
if (n > -1 && n < size)
|
||||
break;
|
||||
/* If that worked, break out so we can send the buffer */
|
||||
if (n > -1 && n < size)
|
||||
break;
|
||||
|
||||
/* Else, try again with more space */
|
||||
if (n > -1)
|
||||
/* precisely what is needed (glibc2.1) */
|
||||
size = n + 1;
|
||||
else
|
||||
/* twice the old size (glibc2.0) */
|
||||
size *= 2;
|
||||
/* Else, try again with more space */
|
||||
if (n > -1)
|
||||
/* precisely what is needed (glibc2.1) */
|
||||
size = n + 1;
|
||||
else
|
||||
/* twice the old size (glibc2.0) */
|
||||
size *= 2;
|
||||
|
||||
if ((tmpbuf = saferealloc(buf, size)) == NULL) {
|
||||
safefree(buf);
|
||||
return -1;
|
||||
} else
|
||||
buf = tmpbuf;
|
||||
}
|
||||
if ((tmpbuf = saferealloc(buf, size)) == NULL) {
|
||||
safefree(buf);
|
||||
return -1;
|
||||
} else
|
||||
buf = tmpbuf;
|
||||
}
|
||||
|
||||
if (safe_write(fd, buf, n) < 0) {
|
||||
safefree(buf);
|
||||
return -1;
|
||||
}
|
||||
if (safe_write(fd, buf, n) < 0) {
|
||||
safefree(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safefree(buf);
|
||||
return 0;
|
||||
safefree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -140,132 +140,134 @@ write_message(int fd, const char *fmt, ...)
|
||||
ssize_t
|
||||
readline(int fd, char **whole_buffer)
|
||||
{
|
||||
ssize_t whole_buffer_len;
|
||||
char buffer[SEGMENT_LEN];
|
||||
char *ptr;
|
||||
ssize_t whole_buffer_len;
|
||||
char buffer[SEGMENT_LEN];
|
||||
char *ptr;
|
||||
|
||||
ssize_t ret;
|
||||
ssize_t diff;
|
||||
ssize_t ret;
|
||||
ssize_t diff;
|
||||
|
||||
struct read_lines_s {
|
||||
char *data;
|
||||
size_t len;
|
||||
struct read_lines_s *next;
|
||||
};
|
||||
struct read_lines_s *first_line, *line_ptr;
|
||||
struct read_lines_s {
|
||||
char *data;
|
||||
size_t len;
|
||||
struct read_lines_s *next;
|
||||
};
|
||||
struct read_lines_s *first_line, *line_ptr;
|
||||
|
||||
first_line = safecalloc(sizeof(struct read_lines_s), 1);
|
||||
if (!first_line)
|
||||
return -ENOMEM;
|
||||
first_line = safecalloc(sizeof(struct read_lines_s), 1);
|
||||
if (!first_line)
|
||||
return -ENOMEM;
|
||||
|
||||
line_ptr = first_line;
|
||||
line_ptr = first_line;
|
||||
|
||||
whole_buffer_len = 0;
|
||||
for (;;) {
|
||||
ret = recv(fd, buffer, SEGMENT_LEN, MSG_PEEK);
|
||||
if (ret <= 0)
|
||||
goto CLEANUP;
|
||||
whole_buffer_len = 0;
|
||||
for (;;) {
|
||||
ret = recv(fd, buffer, SEGMENT_LEN, MSG_PEEK);
|
||||
if (ret <= 0)
|
||||
goto CLEANUP;
|
||||
|
||||
ptr = memchr(buffer, '\n', ret);
|
||||
if (ptr)
|
||||
diff = ptr - buffer + 1;
|
||||
else
|
||||
diff = ret;
|
||||
ptr = memchr(buffer, '\n', ret);
|
||||
if (ptr)
|
||||
diff = ptr - buffer + 1;
|
||||
else
|
||||
diff = ret;
|
||||
|
||||
whole_buffer_len += diff;
|
||||
whole_buffer_len += diff;
|
||||
|
||||
/*
|
||||
* Don't allow the buffer to grow without bound. If we
|
||||
* get to more than MAXIMUM_BUFFER_LENGTH close.
|
||||
*/
|
||||
if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) {
|
||||
ret = -ERANGE;
|
||||
goto CLEANUP;
|
||||
}
|
||||
/*
|
||||
* Don't allow the buffer to grow without bound. If we
|
||||
* get to more than MAXIMUM_BUFFER_LENGTH close.
|
||||
*/
|
||||
if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) {
|
||||
ret = -ERANGE;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
line_ptr->data = safemalloc(diff);
|
||||
if (!line_ptr->data) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
line_ptr->data = safemalloc(diff);
|
||||
if (!line_ptr->data) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
recv(fd, line_ptr->data, diff, 0);
|
||||
line_ptr->len = diff;
|
||||
recv(fd, line_ptr->data, diff, 0);
|
||||
line_ptr->len = diff;
|
||||
|
||||
if (ptr) {
|
||||
line_ptr->next = NULL;
|
||||
break;
|
||||
}
|
||||
if (ptr) {
|
||||
line_ptr->next = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
line_ptr->next = safecalloc(sizeof(struct read_lines_s), 1);
|
||||
if (!line_ptr->next) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
line_ptr = line_ptr->next;
|
||||
}
|
||||
line_ptr->next = safecalloc(sizeof(struct read_lines_s), 1);
|
||||
if (!line_ptr->next) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
line_ptr = line_ptr->next;
|
||||
}
|
||||
|
||||
*whole_buffer = safemalloc(whole_buffer_len + 1);
|
||||
if (!*whole_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
*whole_buffer = safemalloc(whole_buffer_len + 1);
|
||||
if (!*whole_buffer) {
|
||||
ret = -ENOMEM;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
*(*whole_buffer + whole_buffer_len) = '\0';
|
||||
*(*whole_buffer + whole_buffer_len) = '\0';
|
||||
|
||||
whole_buffer_len = 0;
|
||||
line_ptr = first_line;
|
||||
while (line_ptr) {
|
||||
memcpy(*whole_buffer + whole_buffer_len, line_ptr->data,
|
||||
line_ptr->len);
|
||||
whole_buffer_len += line_ptr->len;
|
||||
whole_buffer_len = 0;
|
||||
line_ptr = first_line;
|
||||
while (line_ptr) {
|
||||
memcpy(*whole_buffer + whole_buffer_len, line_ptr->data,
|
||||
line_ptr->len);
|
||||
whole_buffer_len += line_ptr->len;
|
||||
|
||||
line_ptr = line_ptr->next;
|
||||
}
|
||||
line_ptr = line_ptr->next;
|
||||
}
|
||||
|
||||
ret = whole_buffer_len;
|
||||
ret = whole_buffer_len;
|
||||
|
||||
CLEANUP:
|
||||
do {
|
||||
line_ptr = first_line->next;
|
||||
if (first_line->data)
|
||||
safefree(first_line->data);
|
||||
safefree(first_line);
|
||||
first_line = line_ptr;
|
||||
} while (first_line);
|
||||
do {
|
||||
line_ptr = first_line->next;
|
||||
if (first_line->data)
|
||||
safefree(first_line->data);
|
||||
safefree(first_line);
|
||||
first_line = line_ptr;
|
||||
} while (first_line);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the network address into either a dotted-decimal or an IPv6
|
||||
* hex string.
|
||||
*/
|
||||
char*
|
||||
get_ip_string(struct sockaddr* sa, char* buf, size_t buflen)
|
||||
char *
|
||||
get_ip_string(struct sockaddr *sa, char *buf, size_t buflen)
|
||||
{
|
||||
assert(sa != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(buflen != 0);
|
||||
buf[0] = '\0'; /* start with an empty string */
|
||||
assert(sa != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(buflen != 0);
|
||||
buf[0] = '\0'; /* start with an empty string */
|
||||
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
|
||||
inet_ntop(AF_INET, &sa_in->sin_addr, buf, buflen);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
|
||||
inet_ntop(AF_INET6, &sa_in6->sin6_addr, buf, buflen);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* no valid family */
|
||||
return NULL;
|
||||
}
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:{
|
||||
struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
|
||||
|
||||
return buf;
|
||||
inet_ntop(AF_INET, &sa_in->sin_addr, buf, buflen);
|
||||
break;
|
||||
}
|
||||
case AF_INET6:{
|
||||
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
|
||||
|
||||
inet_ntop(AF_INET6, &sa_in6->sin6_addr, buf, buflen);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* no valid family */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -276,41 +278,41 @@ get_ip_string(struct sockaddr* sa, char* buf, size_t buflen)
|
||||
* Returns the same as inet_pton().
|
||||
*/
|
||||
int
|
||||
full_inet_pton(const char* ip, void* dst)
|
||||
full_inet_pton(const char *ip, void *dst)
|
||||
{
|
||||
char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */
|
||||
int n;
|
||||
char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */
|
||||
int n;
|
||||
|
||||
assert(ip != NULL && strlen(ip) != 0);
|
||||
assert(dst != NULL);
|
||||
assert(ip != NULL && strlen(ip) != 0);
|
||||
assert(dst != NULL);
|
||||
|
||||
/*
|
||||
* Check if the string is an IPv4 numeric address. We use the
|
||||
* older inet_aton() call since it handles more IPv4 numeric
|
||||
* address formats.
|
||||
*/
|
||||
n = inet_aton(ip, (struct in_addr*)dst);
|
||||
if (n == 0) {
|
||||
/*
|
||||
* Simple case: "ip" wasn't an IPv4 numeric address, so
|
||||
* try doing the conversion as an IPv6 address. This
|
||||
* will either succeed or fail, but we can't do any
|
||||
* more processing anyway.
|
||||
*/
|
||||
return inet_pton(AF_INET6, ip, dst);
|
||||
}
|
||||
/*
|
||||
* Check if the string is an IPv4 numeric address. We use the
|
||||
* older inet_aton() call since it handles more IPv4 numeric
|
||||
* address formats.
|
||||
*/
|
||||
n = inet_aton(ip, (struct in_addr *)dst);
|
||||
if (n == 0) {
|
||||
/*
|
||||
* Simple case: "ip" wasn't an IPv4 numeric address, so
|
||||
* try doing the conversion as an IPv6 address. This
|
||||
* will either succeed or fail, but we can't do any
|
||||
* more processing anyway.
|
||||
*/
|
||||
return inet_pton(AF_INET6, ip, dst);
|
||||
}
|
||||
|
||||
/*
|
||||
* "ip" was an IPv4 address, so we need to convert it to
|
||||
* an IPv4-mapped IPv6 address and do the conversion
|
||||
* again to get the IPv6 network structure.
|
||||
*
|
||||
* We convert the IPv4 binary address back into the
|
||||
* standard dotted-decimal format using inet_ntop()
|
||||
* so we can be sure that inet_pton will accept the
|
||||
* full string.
|
||||
*/
|
||||
snprintf(buf, sizeof(buf), "::ffff:%s",
|
||||
inet_ntop(AF_INET, dst, tmp, sizeof(tmp)));
|
||||
return inet_pton(AF_INET6, buf, dst);
|
||||
/*
|
||||
* "ip" was an IPv4 address, so we need to convert it to
|
||||
* an IPv4-mapped IPv6 address and do the conversion
|
||||
* again to get the IPv6 network structure.
|
||||
*
|
||||
* We convert the IPv4 binary address back into the
|
||||
* standard dotted-decimal format using inet_ntop()
|
||||
* so we can be sure that inet_pton will accept the
|
||||
* full string.
|
||||
*/
|
||||
snprintf(buf, sizeof(buf), "::ffff:%s",
|
||||
inet_ntop(AF_INET, dst, tmp, sizeof(tmp)));
|
||||
return inet_pton(AF_INET6, buf, dst);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: network.h,v 1.2 2004-02-18 20:17:18 rjkaes Exp $
|
||||
/* $Id: network.h,v 1.3 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'network.c' for a detailed description.
|
||||
*
|
||||
@ -24,7 +24,7 @@ extern ssize_t safe_read(int fd, char *buffer, size_t count);
|
||||
extern int write_message(int fd, const char *fmt, ...);
|
||||
extern ssize_t readline(int fd, char **whole_buffer);
|
||||
|
||||
extern char* get_ip_string(struct sockaddr* sa, char* buf, size_t len);
|
||||
extern int full_inet_pton(const char* ip, void* dst);
|
||||
extern char *get_ip_string(struct sockaddr *sa, char *buf, size_t len);
|
||||
extern int full_inet_pton(const char *ip, void *dst);
|
||||
|
||||
#endif
|
||||
|
2385
src/reqs.c
2385
src/reqs.c
File diff suppressed because it is too large
Load Diff
266
src/sock.c
266
src/sock.c
@ -1,4 +1,4 @@
|
||||
/* $Id: sock.c,v 1.42 2005-07-12 20:34:26 rjkaes Exp $
|
||||
/* $Id: sock.c,v 1.43 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* Sockets are created and destroyed here. When a new connection comes in from
|
||||
* a client, we need to copy the socket and the create a second socket to the
|
||||
@ -35,34 +35,34 @@
|
||||
* to indicate an error.
|
||||
*/
|
||||
static int
|
||||
bind_socket(int sockfd, const char* addr)
|
||||
bind_socket(int sockfd, const char *addr)
|
||||
{
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
|
||||
assert(sockfd >= 0);
|
||||
assert(addr != NULL && strlen(addr) != 0);
|
||||
assert(sockfd >= 0);
|
||||
assert(addr != NULL && strlen(addr) != 0);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
/* The local port it not important */
|
||||
if (getaddrinfo(addr, NULL, &hints, &res) != 0)
|
||||
return -1;
|
||||
/* The local port it not important */
|
||||
if (getaddrinfo(addr, NULL, &hints, &res) != 0)
|
||||
return -1;
|
||||
|
||||
ressave = res;
|
||||
ressave = res;
|
||||
|
||||
/* Loop through the addresses and try to bind to each */
|
||||
do {
|
||||
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
||||
break; /* success */
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
/* Loop through the addresses and try to bind to each */
|
||||
do {
|
||||
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
||||
break; /* success */
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
if (res == NULL) /* was not able to bind to any address */
|
||||
return -1;
|
||||
freeaddrinfo(ressave);
|
||||
if (res == NULL) /* was not able to bind to any address */
|
||||
return -1;
|
||||
|
||||
return sockfd;
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -71,62 +71,63 @@ bind_socket(int sockfd, const char* addr)
|
||||
* independent implementation (mostly for IPv4 and IPv6 addresses.)
|
||||
*/
|
||||
int
|
||||
opensock(const char* host, int port, const char* bind_to)
|
||||
opensock(const char *host, int port, const char *bind_to)
|
||||
{
|
||||
int sockfd, n;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
char portstr[6];
|
||||
int sockfd, n;
|
||||
struct addrinfo hints, *res, *ressave;
|
||||
char portstr[6];
|
||||
|
||||
assert(host != NULL);
|
||||
assert(port > 0);
|
||||
assert(host != NULL);
|
||||
assert(port > 0);
|
||||
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
snprintf(portstr, sizeof(portstr), "%d", port);
|
||||
|
||||
n = getaddrinfo(host, portstr, &hints, &res);
|
||||
if (n != 0) {
|
||||
log_message(LOG_ERR, "opensock: Could not retrieve info for %s",
|
||||
host);
|
||||
return -1;
|
||||
}
|
||||
n = getaddrinfo(host, portstr, &hints, &res);
|
||||
if (n != 0) {
|
||||
log_message(LOG_ERR, "opensock: Could not retrieve info for %s",
|
||||
host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ressave = res;
|
||||
do {
|
||||
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sockfd < 0)
|
||||
continue; /* ignore this one */
|
||||
ressave = res;
|
||||
do {
|
||||
sockfd =
|
||||
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
||||
if (sockfd < 0)
|
||||
continue; /* ignore this one */
|
||||
|
||||
/* Bind to the specified address */
|
||||
if (bind_to) {
|
||||
if (bind_socket(sockfd, bind_to) < 0) {
|
||||
close(sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
} else if (config.bind_address) {
|
||||
if (bind_socket(sockfd, config.bind_address) < 0) {
|
||||
close(sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
}
|
||||
/* Bind to the specified address */
|
||||
if (bind_to) {
|
||||
if (bind_socket(sockfd, bind_to) < 0) {
|
||||
close(sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
} else if (config.bind_address) {
|
||||
if (bind_socket(sockfd, config.bind_address) < 0) {
|
||||
close(sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
}
|
||||
|
||||
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
||||
break; /* success */
|
||||
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
|
||||
break; /* success */
|
||||
|
||||
close(sockfd);
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
close(sockfd);
|
||||
} while ((res = res->ai_next) != NULL);
|
||||
|
||||
freeaddrinfo(ressave);
|
||||
if (res == NULL) {
|
||||
log_message(LOG_ERR,
|
||||
"opensock: Could not establish a connection to %s",
|
||||
host);
|
||||
return -1;
|
||||
}
|
||||
freeaddrinfo(ressave);
|
||||
if (res == NULL) {
|
||||
log_message(LOG_ERR,
|
||||
"opensock: Could not establish a connection to %s",
|
||||
host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sockfd;
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -135,12 +136,12 @@ opensock(const char* host, int port, const char* bind_to)
|
||||
int
|
||||
socket_nonblocking(int sock)
|
||||
{
|
||||
int flags;
|
||||
int flags;
|
||||
|
||||
assert(sock >= 0);
|
||||
assert(sock >= 0);
|
||||
|
||||
flags = fcntl(sock, F_GETFL, 0);
|
||||
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||
flags = fcntl(sock, F_GETFL, 0);
|
||||
return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -149,12 +150,12 @@ socket_nonblocking(int sock)
|
||||
int
|
||||
socket_blocking(int sock)
|
||||
{
|
||||
int flags;
|
||||
int flags;
|
||||
|
||||
assert(sock >= 0);
|
||||
assert(sock >= 0);
|
||||
|
||||
flags = fcntl(sock, F_GETFL, 0);
|
||||
return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
|
||||
flags = fcntl(sock, F_GETFL, 0);
|
||||
return fcntl(sock, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -164,94 +165,95 @@ socket_blocking(int sock)
|
||||
* - rjkaes
|
||||
*/
|
||||
int
|
||||
listen_sock(uint16_t port, socklen_t* addrlen)
|
||||
listen_sock(uint16_t port, socklen_t * addrlen)
|
||||
{
|
||||
int listenfd;
|
||||
const int on = 1;
|
||||
struct sockaddr_in addr;
|
||||
int listenfd;
|
||||
const int on = 1;
|
||||
struct sockaddr_in addr;
|
||||
|
||||
assert(port > 0);
|
||||
assert(addrlen != NULL);
|
||||
assert(port > 0);
|
||||
assert(addrlen != NULL);
|
||||
|
||||
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
listenfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (config.ipAddr) {
|
||||
addr.sin_addr.s_addr = inet_addr(config.ipAddr);
|
||||
} else {
|
||||
addr.sin_addr.s_addr = inet_addr("0.0.0.0");
|
||||
}
|
||||
if (config.ipAddr) {
|
||||
addr.sin_addr.s_addr = inet_addr(config.ipAddr);
|
||||
} else {
|
||||
addr.sin_addr.s_addr = inet_addr("0.0.0.0");
|
||||
}
|
||||
|
||||
if (bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
|
||||
log_message(LOG_ERR, "Unable to bind listening socket because of %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (bind(listenfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Unable to bind listening socket because of %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (listen(listenfd, MAXLISTEN) < 0) {
|
||||
log_message(LOG_ERR, "Unable to start listening socket because of %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (listen(listenfd, MAXLISTEN) < 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Unable to start listening socket because of %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
*addrlen = sizeof(addr);
|
||||
*addrlen = sizeof(addr);
|
||||
|
||||
return listenfd;
|
||||
return listenfd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Takes a socket descriptor and returns the socket's IP address.
|
||||
*/
|
||||
int
|
||||
getsock_ip(int fd, char* ipaddr)
|
||||
getsock_ip(int fd, char *ipaddr)
|
||||
{
|
||||
struct sockaddr_storage name;
|
||||
socklen_t namelen = sizeof(name);
|
||||
struct sockaddr_storage name;
|
||||
socklen_t namelen = sizeof(name);
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(fd >= 0);
|
||||
|
||||
if (getsockname(fd, (struct sockaddr *) &name, &namelen) != 0) {
|
||||
log_message(LOG_ERR, "getsock_ip: getsockname() error: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (getsockname(fd, (struct sockaddr *)&name, &namelen) != 0) {
|
||||
log_message(LOG_ERR, "getsock_ip: getsockname() error: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (get_ip_string((struct sockaddr *)&name, ipaddr, IP_LENGTH) == NULL)
|
||||
return -1;
|
||||
if (get_ip_string((struct sockaddr *)&name, ipaddr, IP_LENGTH) == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the peer's socket information.
|
||||
*/
|
||||
int
|
||||
getpeer_information(int fd, char* ipaddr, char* string_addr)
|
||||
getpeer_information(int fd, char *ipaddr, char *string_addr)
|
||||
{
|
||||
struct sockaddr_storage sa;
|
||||
size_t salen = sizeof(sa);
|
||||
struct sockaddr_storage sa;
|
||||
size_t salen = sizeof(sa);
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ipaddr != NULL);
|
||||
assert(string_addr != NULL);
|
||||
assert(fd >= 0);
|
||||
assert(ipaddr != NULL);
|
||||
assert(string_addr != NULL);
|
||||
|
||||
/* Set the strings to default values */
|
||||
ipaddr[0] = '\0';
|
||||
strlcpy(string_addr, "[unknown]", HOSTNAME_LENGTH);
|
||||
/* Set the strings to default values */
|
||||
ipaddr[0] = '\0';
|
||||
strlcpy(string_addr, "[unknown]", HOSTNAME_LENGTH);
|
||||
|
||||
/* Look up the IP address */
|
||||
if (getpeername(fd, (struct sockaddr *)&sa, &salen) != 0)
|
||||
return -1;
|
||||
/* Look up the IP address */
|
||||
if (getpeername(fd, (struct sockaddr *)&sa, &salen) != 0)
|
||||
return -1;
|
||||
|
||||
if (get_ip_string((struct sockaddr *)&sa, ipaddr, IP_LENGTH) == NULL)
|
||||
return -1;
|
||||
if (get_ip_string((struct sockaddr *)&sa, ipaddr, IP_LENGTH) == NULL)
|
||||
return -1;
|
||||
|
||||
/* Get the full host name */
|
||||
return getnameinfo((struct sockaddr *)&sa, salen,
|
||||
string_addr, HOSTNAME_LENGTH,
|
||||
NULL, 0, 0);
|
||||
/* Get the full host name */
|
||||
return getnameinfo((struct sockaddr *)&sa, salen,
|
||||
string_addr, HOSTNAME_LENGTH, NULL, 0, 0);
|
||||
}
|
||||
|
10
src/sock.h
10
src/sock.h
@ -1,4 +1,4 @@
|
||||
/* $Id: sock.h,v 1.13 2004-04-27 18:53:14 rjkaes Exp $
|
||||
/* $Id: sock.h,v 1.14 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'sock.c' for a detailed description.
|
||||
*
|
||||
@ -25,13 +25,13 @@
|
||||
|
||||
#define MAXLINE (1024 * 4)
|
||||
|
||||
extern int opensock(const char* host, int port, const char* bind_to);
|
||||
extern int listen_sock(uint16_t port, socklen_t* addrlen);
|
||||
extern int opensock(const char *host, int port, const char *bind_to);
|
||||
extern int listen_sock(uint16_t port, socklen_t * addrlen);
|
||||
|
||||
extern int socket_nonblocking(int sock);
|
||||
extern int socket_blocking(int sock);
|
||||
|
||||
extern int getsock_ip(int fd, char* ipaddr);
|
||||
extern int getpeer_information(int fd, char* ipaddr, char* string_addr);
|
||||
extern int getsock_ip(int fd, char *ipaddr);
|
||||
extern int getpeer_information(int fd, char *ipaddr, char *string_addr);
|
||||
|
||||
#endif
|
||||
|
153
src/stats.c
153
src/stats.c
@ -1,4 +1,4 @@
|
||||
/* $Id: stats.c,v 1.17 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: stats.c,v 1.18 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* This module handles the statistics for tinyproxy. There are only two
|
||||
* public API functions. The reason for the functions, rather than just a
|
||||
@ -30,11 +30,11 @@
|
||||
#include "utils.h"
|
||||
|
||||
struct stat_s {
|
||||
unsigned long int num_reqs;
|
||||
unsigned long int num_badcons;
|
||||
unsigned long int num_open;
|
||||
unsigned long int num_refused;
|
||||
unsigned long int num_denied;
|
||||
unsigned long int num_reqs;
|
||||
unsigned long int num_badcons;
|
||||
unsigned long int num_open;
|
||||
unsigned long int num_refused;
|
||||
unsigned long int num_denied;
|
||||
};
|
||||
|
||||
static struct stat_s *stats;
|
||||
@ -45,11 +45,11 @@ static struct stat_s *stats;
|
||||
void
|
||||
init_stats(void)
|
||||
{
|
||||
stats = malloc_shared_memory(sizeof(struct stat_s));
|
||||
if (stats == MAP_FAILED)
|
||||
return;
|
||||
stats = malloc_shared_memory(sizeof(struct stat_s));
|
||||
if (stats == MAP_FAILED)
|
||||
return;
|
||||
|
||||
memset(stats, 0, sizeof(struct stat_s));
|
||||
memset(stats, 0, sizeof(struct stat_s));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -58,59 +58,60 @@ init_stats(void)
|
||||
int
|
||||
showstats(struct conn_s *connptr)
|
||||
{
|
||||
static char *msg =
|
||||
"<html><head><title>%s (%s) stats</title></head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<center><h2>%s (%s) run-time statistics</h2></center><hr>\r\n"
|
||||
"<blockquote>\r\n"
|
||||
"Number of open connections: %lu<br>\r\n"
|
||||
"Number of requests: %lu<br>\r\n"
|
||||
"Number of bad connections: %lu<br>\r\n"
|
||||
"Number of denied connections: %lu<br>\r\n"
|
||||
"Number of refused connections due to high load: %lu\r\n"
|
||||
"</blockquote>\r\n</body></html>\r\n";
|
||||
static char *msg =
|
||||
"<html><head><title>%s (%s) stats</title></head>\r\n"
|
||||
"<body>\r\n"
|
||||
"<center><h2>%s (%s) run-time statistics</h2></center><hr>\r\n"
|
||||
"<blockquote>\r\n"
|
||||
"Number of open connections: %lu<br>\r\n"
|
||||
"Number of requests: %lu<br>\r\n"
|
||||
"Number of bad connections: %lu<br>\r\n"
|
||||
"Number of denied connections: %lu<br>\r\n"
|
||||
"Number of refused connections due to high load: %lu\r\n"
|
||||
"</blockquote>\r\n</body></html>\r\n";
|
||||
|
||||
char *message_buffer;
|
||||
char opens[16], reqs[16], badconns[16], denied[16], refused[16];
|
||||
FILE *statfile;
|
||||
char *message_buffer;
|
||||
char opens[16], reqs[16], badconns[16], denied[16], refused[16];
|
||||
FILE *statfile;
|
||||
|
||||
snprintf(opens, sizeof(opens), "%lu", stats->num_open);
|
||||
snprintf(reqs, sizeof(reqs), "%lu", stats->num_reqs);
|
||||
snprintf(badconns, sizeof(badconns), "%lu", stats->num_badcons);
|
||||
snprintf(denied, sizeof(denied), "%lu", stats->num_denied);
|
||||
snprintf(refused, sizeof(refused), "%lu", stats->num_refused);
|
||||
snprintf(opens, sizeof(opens), "%lu", stats->num_open);
|
||||
snprintf(reqs, sizeof(reqs), "%lu", stats->num_reqs);
|
||||
snprintf(badconns, sizeof(badconns), "%lu", stats->num_badcons);
|
||||
snprintf(denied, sizeof(denied), "%lu", stats->num_denied);
|
||||
snprintf(refused, sizeof(refused), "%lu", stats->num_refused);
|
||||
|
||||
if (!config.statpage || (!(statfile = fopen(config.statpage, "r")))) {
|
||||
message_buffer = safemalloc(MAXBUFFSIZE);
|
||||
if (!message_buffer)
|
||||
return -1;
|
||||
if (!config.statpage || (!(statfile = fopen(config.statpage, "r")))) {
|
||||
message_buffer = safemalloc(MAXBUFFSIZE);
|
||||
if (!message_buffer)
|
||||
return -1;
|
||||
|
||||
snprintf(message_buffer, MAXBUFFSIZE, msg,
|
||||
PACKAGE, VERSION, PACKAGE, VERSION,
|
||||
stats->num_open,
|
||||
stats->num_reqs,
|
||||
stats->num_badcons, stats->num_denied, stats->num_refused);
|
||||
snprintf(message_buffer, MAXBUFFSIZE, msg,
|
||||
PACKAGE, VERSION, PACKAGE, VERSION,
|
||||
stats->num_open,
|
||||
stats->num_reqs,
|
||||
stats->num_badcons, stats->num_denied,
|
||||
stats->num_refused);
|
||||
|
||||
if (send_http_message(connptr, 200, "OK", message_buffer) < 0) {
|
||||
safefree(message_buffer);
|
||||
return -1;
|
||||
}
|
||||
if (send_http_message(connptr, 200, "OK", message_buffer) < 0) {
|
||||
safefree(message_buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
safefree(message_buffer);
|
||||
return 0;
|
||||
}
|
||||
safefree(message_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_error_variable(connptr, "opens", opens);
|
||||
add_error_variable(connptr, "reqs", reqs);
|
||||
add_error_variable(connptr, "badconns", badconns);
|
||||
add_error_variable(connptr, "denied", denied);
|
||||
add_error_variable(connptr, "refused", refused);
|
||||
add_standard_vars(connptr);
|
||||
send_http_headers(connptr, 200, "Statistic requested");
|
||||
send_html_file(statfile, connptr);
|
||||
fclose(statfile);
|
||||
add_error_variable(connptr, "opens", opens);
|
||||
add_error_variable(connptr, "reqs", reqs);
|
||||
add_error_variable(connptr, "badconns", badconns);
|
||||
add_error_variable(connptr, "denied", denied);
|
||||
add_error_variable(connptr, "refused", refused);
|
||||
add_standard_vars(connptr);
|
||||
send_http_headers(connptr, 200, "Statistic requested");
|
||||
send_html_file(statfile, connptr);
|
||||
fclose(statfile);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -120,26 +121,26 @@ showstats(struct conn_s *connptr)
|
||||
int
|
||||
update_stats(status_t update_level)
|
||||
{
|
||||
switch (update_level) {
|
||||
case STAT_BADCONN:
|
||||
++stats->num_badcons;
|
||||
break;
|
||||
case STAT_OPEN:
|
||||
++stats->num_open;
|
||||
++stats->num_reqs;
|
||||
break;
|
||||
case STAT_CLOSE:
|
||||
--stats->num_open;
|
||||
break;
|
||||
case STAT_REFUSE:
|
||||
++stats->num_refused;
|
||||
break;
|
||||
case STAT_DENIED:
|
||||
++stats->num_denied;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
switch (update_level) {
|
||||
case STAT_BADCONN:
|
||||
++stats->num_badcons;
|
||||
break;
|
||||
case STAT_OPEN:
|
||||
++stats->num_open;
|
||||
++stats->num_reqs;
|
||||
break;
|
||||
case STAT_CLOSE:
|
||||
--stats->num_open;
|
||||
break;
|
||||
case STAT_REFUSE:
|
||||
++stats->num_refused;
|
||||
break;
|
||||
case STAT_DENIED:
|
||||
++stats->num_denied;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
12
src/stats.h
12
src/stats.h
@ -1,4 +1,4 @@
|
||||
/* $Id: stats.h,v 1.5 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: stats.h,v 1.6 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'stats.h' for a detailed description.
|
||||
*
|
||||
@ -24,11 +24,11 @@
|
||||
* Various logable statistics
|
||||
*/
|
||||
typedef enum {
|
||||
STAT_BADCONN, /* bad connection, for unknown reason */
|
||||
STAT_OPEN, /* connection opened */
|
||||
STAT_CLOSE, /* connection closed */
|
||||
STAT_REFUSE, /* connection refused (to outside world) */
|
||||
STAT_DENIED /* connection denied to tinyproxy itself */
|
||||
STAT_BADCONN, /* bad connection, for unknown reason */
|
||||
STAT_OPEN, /* connection opened */
|
||||
STAT_CLOSE, /* connection closed */
|
||||
STAT_REFUSE, /* connection refused (to outside world) */
|
||||
STAT_DENIED /* connection denied to tinyproxy itself */
|
||||
} status_t;
|
||||
|
||||
/*
|
||||
|
69
src/text.c
69
src/text.c
@ -1,4 +1,4 @@
|
||||
/* $Id: text.c,v 1.4 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: text.c,v 1.5 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* The functions included here are useful for text manipulation. They
|
||||
* replace or augment the standard C string library. These functions
|
||||
@ -31,16 +31,16 @@
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
size_t ret = len;
|
||||
size_t len = strlen(src);
|
||||
size_t ret = len;
|
||||
|
||||
if (len >= size)
|
||||
len = size - 1;
|
||||
if (len >= size)
|
||||
len = size - 1;
|
||||
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
memcpy(dst, src, len);
|
||||
dst[len] = '\0';
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -54,18 +54,18 @@ strlcpy(char *dst, const char *src, size_t size)
|
||||
size_t
|
||||
strlcat(char *dst, const char *src, size_t size)
|
||||
{
|
||||
size_t len1 = strlen(dst);
|
||||
size_t len2 = strlen(src);
|
||||
size_t ret = len1 + len2;
|
||||
size_t len1 = strlen(dst);
|
||||
size_t len2 = strlen(src);
|
||||
size_t ret = len1 + len2;
|
||||
|
||||
if (len1 + len2 >= size)
|
||||
len2 = size - len1 - 1;
|
||||
if (len2 > 0) {
|
||||
memcpy(dst + len1, src, len2);
|
||||
dst[len1 + len2] = '\0';
|
||||
}
|
||||
if (len1 + len2 >= size)
|
||||
len2 = size - len1 - 1;
|
||||
if (len2 > 0) {
|
||||
memcpy(dst + len1, src, len2);
|
||||
dst[len1 + len2] = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -81,25 +81,28 @@ strlcat(char *dst, const char *src, size_t size)
|
||||
ssize_t
|
||||
chomp(char *buffer, size_t length)
|
||||
{
|
||||
size_t chars;
|
||||
size_t chars;
|
||||
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0);
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0);
|
||||
|
||||
/* Make sure the arguments are valid */
|
||||
if (buffer == NULL) return -EFAULT;
|
||||
if (length < 1) return -ERANGE;
|
||||
/* Make sure the arguments are valid */
|
||||
if (buffer == NULL)
|
||||
return -EFAULT;
|
||||
if (length < 1)
|
||||
return -ERANGE;
|
||||
|
||||
chars = 0;
|
||||
chars = 0;
|
||||
|
||||
--length;
|
||||
while (buffer[length] == '\r' || buffer[length] == '\n') {
|
||||
buffer[length] = '\0';
|
||||
chars++;
|
||||
--length;
|
||||
while (buffer[length] == '\r' || buffer[length] == '\n') {
|
||||
buffer[length] = '\0';
|
||||
chars++;
|
||||
|
||||
/* Stop once we get to zero to prevent wrap-around */
|
||||
if (length-- == 0) break;
|
||||
}
|
||||
/* Stop once we get to zero to prevent wrap-around */
|
||||
if (length-- == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return chars;
|
||||
return chars;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: text.h,v 1.3 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: text.h,v 1.4 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'text.c' for a detailed description.
|
||||
*
|
||||
@ -20,11 +20,11 @@
|
||||
|
||||
#ifndef HAVE_STRLCAT
|
||||
extern size_t strlcat(char *dst, const char *src, size_t size);
|
||||
#endif /* HAVE_STRLCAT */
|
||||
#endif /* HAVE_STRLCAT */
|
||||
|
||||
#ifndef HAVE_STRLCPY
|
||||
extern size_t strlcpy(char *dst, const char *src, size_t size);
|
||||
#endif /* HAVE_STRLCPY */
|
||||
#endif /* HAVE_STRLCPY */
|
||||
|
||||
extern ssize_t chomp(char *buffer, size_t length);
|
||||
|
||||
|
509
src/tinyproxy.c
509
src/tinyproxy.c
@ -1,4 +1,4 @@
|
||||
/* $Id: tinyproxy.c,v 1.51 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: tinyproxy.c,v 1.52 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* The initialize routine. Basically sets up all the initial stuff (logfile,
|
||||
* listening socket, config options, etc.) and then sits there and loops
|
||||
@ -44,8 +44,8 @@ RETSIGTYPE takesig(int sig);
|
||||
*/
|
||||
struct config_s config;
|
||||
float load = 0.00;
|
||||
unsigned int received_sighup = FALSE; /* boolean */
|
||||
unsigned int processed_config_file = FALSE; /* boolean */
|
||||
unsigned int received_sighup = FALSE; /* boolean */
|
||||
unsigned int processed_config_file = FALSE; /* boolean */
|
||||
|
||||
/*
|
||||
* Handle a signal
|
||||
@ -53,25 +53,24 @@ unsigned int processed_config_file = FALSE; /* boolean */
|
||||
RETSIGTYPE
|
||||
takesig(int sig)
|
||||
{
|
||||
pid_t pid;
|
||||
int status;
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
received_sighup = TRUE;
|
||||
break;
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
received_sighup = TRUE;
|
||||
break;
|
||||
|
||||
case SIGTERM:
|
||||
config.quit = TRUE;
|
||||
break;
|
||||
case SIGTERM:
|
||||
config.quit = TRUE;
|
||||
break;
|
||||
|
||||
case SIGCHLD:
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
|
||||
;
|
||||
break;
|
||||
}
|
||||
case SIGCHLD:
|
||||
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) ;
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -80,7 +79,7 @@ takesig(int sig)
|
||||
static void
|
||||
display_version(void)
|
||||
{
|
||||
printf("%s %s (%s)\n", PACKAGE, VERSION, TARGET_SYSTEM);
|
||||
printf("%s %s (%s)\n", PACKAGE, VERSION, TARGET_SYSTEM);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -89,9 +88,9 @@ display_version(void)
|
||||
static void
|
||||
display_license(void)
|
||||
{
|
||||
display_version();
|
||||
display_version();
|
||||
|
||||
printf("\
|
||||
printf("\
|
||||
Copyright 1998 Steven Young (sdyoung@well.com)\n\
|
||||
Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\
|
||||
Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\
|
||||
@ -118,8 +117,8 @@ display_license(void)
|
||||
static void
|
||||
display_usage(void)
|
||||
{
|
||||
printf("Usage: %s [options]\n", PACKAGE);
|
||||
printf("\
|
||||
printf("Usage: %s [options]\n", PACKAGE);
|
||||
printf("\
|
||||
Options:\n\
|
||||
-d Operate in DEBUG mode.\n\
|
||||
-c FILE Use an alternate configuration file.\n\
|
||||
@ -127,97 +126,97 @@ Options:\n\
|
||||
-l Display the license.\n\
|
||||
-v Display the version number.\n");
|
||||
|
||||
/* Display the modes compiled into tinyproxy */
|
||||
printf("\nFeatures compiled in:\n");
|
||||
/* Display the modes compiled into tinyproxy */
|
||||
printf("\nFeatures compiled in:\n");
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
printf(" XTinyproxy header\n");
|
||||
#endif /* XTINYPROXY */
|
||||
printf(" XTinyproxy header\n");
|
||||
#endif /* XTINYPROXY */
|
||||
#ifdef FILTER_ENABLE
|
||||
printf(" Filtering\n");
|
||||
#endif /* FILTER_ENABLE */
|
||||
printf(" Filtering\n");
|
||||
#endif /* FILTER_ENABLE */
|
||||
#ifndef NDEBUG
|
||||
printf(" Debugging code\n");
|
||||
#endif /* NDEBUG */
|
||||
printf(" Debugging code\n");
|
||||
#endif /* NDEBUG */
|
||||
#ifdef TRANSPARENT_PROXY
|
||||
printf(" Transparent proxy support\n");
|
||||
printf(" Transparent proxy support\n");
|
||||
#endif /* TRANSPARENT_PROXY */
|
||||
#ifdef REVERSE_SUPPORT
|
||||
printf(" Reverse proxy support\n");
|
||||
#endif /* REVERSE_SUPPORT */
|
||||
printf(" Reverse proxy support\n");
|
||||
#endif /* REVERSE_SUPPORT */
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int optch;
|
||||
unsigned int godaemon = TRUE; /* boolean */
|
||||
struct passwd *thisuser = NULL;
|
||||
struct group *thisgroup = NULL;
|
||||
FILE* config_file;
|
||||
int optch;
|
||||
unsigned int godaemon = TRUE; /* boolean */
|
||||
struct passwd *thisuser = NULL;
|
||||
struct group *thisgroup = NULL;
|
||||
FILE *config_file;
|
||||
|
||||
/*
|
||||
* Disable the creation of CORE files right up front.
|
||||
*/
|
||||
/*
|
||||
* Disable the creation of CORE files right up front.
|
||||
*/
|
||||
#if defined(HAVE_SETRLIMIT) && defined(NDEBUG)
|
||||
struct rlimit core_limit = { 0, 0 };
|
||||
if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
|
||||
fprintf(stderr, "%s: Could not set the core limit to zero.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
#endif /* HAVE_SETRLIMIT */
|
||||
struct rlimit core_limit = { 0, 0 };
|
||||
if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
|
||||
fprintf(stderr, "%s: Could not set the core limit to zero.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
#endif /* HAVE_SETRLIMIT */
|
||||
|
||||
/* Default configuration file location */
|
||||
config.config_file = DEFAULT_CONF_FILE;
|
||||
/* Default configuration file location */
|
||||
config.config_file = DEFAULT_CONF_FILE;
|
||||
|
||||
/*
|
||||
* Process the various options
|
||||
*/
|
||||
while ((optch = getopt(argc, argv, "c:vldh")) != EOF) {
|
||||
switch (optch) {
|
||||
case 'v':
|
||||
display_version();
|
||||
exit(EX_OK);
|
||||
case 'l':
|
||||
display_license();
|
||||
exit(EX_OK);
|
||||
case 'd':
|
||||
godaemon = FALSE;
|
||||
break;
|
||||
case 'c':
|
||||
config.config_file = safestrdup(optarg);
|
||||
if (!config.config_file) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not allocate memory.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
display_usage();
|
||||
exit(EX_OK);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Process the various options
|
||||
*/
|
||||
while ((optch = getopt(argc, argv, "c:vldh")) != EOF) {
|
||||
switch (optch) {
|
||||
case 'v':
|
||||
display_version();
|
||||
exit(EX_OK);
|
||||
case 'l':
|
||||
display_license();
|
||||
exit(EX_OK);
|
||||
case 'd':
|
||||
godaemon = FALSE;
|
||||
break;
|
||||
case 'c':
|
||||
config.config_file = safestrdup(optarg);
|
||||
if (!config.config_file) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not allocate memory.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
display_usage();
|
||||
exit(EX_OK);
|
||||
}
|
||||
}
|
||||
|
||||
log_message(LOG_INFO, "Initializing " PACKAGE " ...");
|
||||
log_message(LOG_INFO, "Initializing " PACKAGE " ...");
|
||||
|
||||
/*
|
||||
* Make sure the HTML error pages array is NULL to begin with.
|
||||
* (FIXME: Should have a better API for all this)
|
||||
*/
|
||||
config.errorpages = NULL;
|
||||
/*
|
||||
* Make sure the HTML error pages array is NULL to begin with.
|
||||
* (FIXME: Should have a better API for all this)
|
||||
*/
|
||||
config.errorpages = NULL;
|
||||
|
||||
/*
|
||||
* Read in the settings from the config file.
|
||||
*/
|
||||
/*
|
||||
* Read in the settings from the config file.
|
||||
*/
|
||||
config_file = fopen(config.config_file, "r");
|
||||
if (!config_file) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not open configuration file \"%s\".\n",
|
||||
argv[0], config.config_file);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"%s: Could not open configuration file \"%s\".\n",
|
||||
argv[0], config.config_file);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
if (config_compile() || config_parse(&config, config_file)) {
|
||||
fprintf(stderr,
|
||||
"Unable to parse configuration file. Not starting.\n");
|
||||
@ -232,194 +231,192 @@ main(int argc, char **argv)
|
||||
if (config.logf_name) {
|
||||
if (open_log_file(config.logf_name) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not create log file.\n",
|
||||
argv[0]);
|
||||
"%s: Could not create log file.\n", argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
config.syslog = FALSE; /* disable syslog */
|
||||
config.syslog = FALSE; /* disable syslog */
|
||||
} else if (config.syslog) {
|
||||
if (godaemon == TRUE)
|
||||
openlog("tinyproxy", LOG_PID, LOG_DAEMON);
|
||||
else
|
||||
openlog("tinyproxy", LOG_PID, LOG_USER);
|
||||
} else {
|
||||
if (godaemon == TRUE)
|
||||
openlog("tinyproxy", LOG_PID, LOG_DAEMON);
|
||||
else
|
||||
openlog("tinyproxy", LOG_PID, LOG_USER);
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"%s: Either define a logfile or enable syslog logging\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
|
||||
processed_config_file = TRUE;
|
||||
send_stored_logs();
|
||||
processed_config_file = TRUE;
|
||||
send_stored_logs();
|
||||
|
||||
/*
|
||||
* Set the default values if they were not set in the config file.
|
||||
*/
|
||||
if (config.port == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: You MUST set a Port in the configuration file.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
if (!config.stathost) {
|
||||
log_message(LOG_INFO, "Setting stathost to \"%s\".",
|
||||
DEFAULT_STATHOST);
|
||||
config.stathost = DEFAULT_STATHOST;
|
||||
}
|
||||
if (!config.username) {
|
||||
log_message(LOG_WARNING,
|
||||
"You SHOULD set a UserName in the configuration file. Using current user instead.");
|
||||
}
|
||||
if (config.idletimeout == 0) {
|
||||
log_message(LOG_WARNING, "Invalid idle time setting. Only values greater than zero allowed; therefore setting idle timeout to %u seconds.",
|
||||
MAX_IDLE_TIME);
|
||||
config.idletimeout = MAX_IDLE_TIME;
|
||||
}
|
||||
/*
|
||||
* Set the default values if they were not set in the config file.
|
||||
*/
|
||||
if (config.port == 0) {
|
||||
fprintf(stderr,
|
||||
"%s: You MUST set a Port in the configuration file.\n",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
if (!config.stathost) {
|
||||
log_message(LOG_INFO, "Setting stathost to \"%s\".",
|
||||
DEFAULT_STATHOST);
|
||||
config.stathost = DEFAULT_STATHOST;
|
||||
}
|
||||
if (!config.username) {
|
||||
log_message(LOG_WARNING,
|
||||
"You SHOULD set a UserName in the configuration file. Using current user instead.");
|
||||
}
|
||||
if (config.idletimeout == 0) {
|
||||
log_message(LOG_WARNING,
|
||||
"Invalid idle time setting. Only values greater than zero allowed; therefore setting idle timeout to %u seconds.",
|
||||
MAX_IDLE_TIME);
|
||||
config.idletimeout = MAX_IDLE_TIME;
|
||||
}
|
||||
|
||||
init_stats();
|
||||
init_stats();
|
||||
|
||||
/*
|
||||
* If ANONYMOUS is turned on, make sure that Content-Length is
|
||||
* in the list of allowed headers, since it is required in a
|
||||
* HTTP/1.0 request. Also add the Content-Type header since it goes
|
||||
* hand in hand with Content-Length.
|
||||
* - rjkaes
|
||||
*/
|
||||
if (is_anonymous_enabled()) {
|
||||
anonymous_insert("Content-Length");
|
||||
anonymous_insert("Content-Type");
|
||||
}
|
||||
/*
|
||||
* If ANONYMOUS is turned on, make sure that Content-Length is
|
||||
* in the list of allowed headers, since it is required in a
|
||||
* HTTP/1.0 request. Also add the Content-Type header since it goes
|
||||
* hand in hand with Content-Length.
|
||||
* - rjkaes
|
||||
*/
|
||||
if (is_anonymous_enabled()) {
|
||||
anonymous_insert("Content-Length");
|
||||
anonymous_insert("Content-Type");
|
||||
}
|
||||
|
||||
if (godaemon == TRUE)
|
||||
makedaemon();
|
||||
if (godaemon == TRUE)
|
||||
makedaemon();
|
||||
|
||||
if (config.pidpath) {
|
||||
if (pidfile_create(config.pidpath) < 0) {
|
||||
fprintf(stderr, "%s: Could not create PID file.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
}
|
||||
|
||||
if (set_signal_handler(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGPIPE\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
if (config.pidpath) {
|
||||
if (pidfile_create(config.pidpath) < 0) {
|
||||
fprintf(stderr, "%s: Could not create PID file.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
}
|
||||
|
||||
if (set_signal_handler(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGPIPE\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
#ifdef FILTER_ENABLE
|
||||
if (config.filter)
|
||||
filter_init();
|
||||
#endif /* FILTER_ENABLE */
|
||||
if (config.filter)
|
||||
filter_init();
|
||||
#endif /* FILTER_ENABLE */
|
||||
|
||||
/*
|
||||
* Start listening on the selected port.
|
||||
*/
|
||||
if (child_listening_sock(config.port) < 0) {
|
||||
fprintf(stderr, "%s: Could not create listening socket.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
/*
|
||||
* Start listening on the selected port.
|
||||
*/
|
||||
if (child_listening_sock(config.port) < 0) {
|
||||
fprintf(stderr, "%s: Could not create listening socket.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Switch to a different user.
|
||||
*/
|
||||
if (geteuid() == 0) {
|
||||
if (config.group && strlen(config.group) > 0) {
|
||||
thisgroup = getgrnam(config.group);
|
||||
if (!thisgroup) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to find group \"%s\".\n",
|
||||
argv[0], config.group);
|
||||
exit(EX_NOUSER);
|
||||
}
|
||||
if (setgid(thisgroup->gr_gid) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to change to group \"%s\".\n",
|
||||
argv[0], config.group);
|
||||
exit(EX_CANTCREAT);
|
||||
}
|
||||
log_message(LOG_INFO, "Now running as group \"%s\".",
|
||||
config.group);
|
||||
}
|
||||
if (config.username && strlen(config.username) > 0) {
|
||||
thisuser = getpwnam(config.username);
|
||||
if (!thisuser) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to find user \"%s\".",
|
||||
argv[0], config.username);
|
||||
exit(EX_NOUSER);
|
||||
}
|
||||
if (setuid(thisuser->pw_uid) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to change to user \"%s\".",
|
||||
argv[0], config.username);
|
||||
exit(EX_CANTCREAT);
|
||||
}
|
||||
log_message(LOG_INFO, "Now running as user \"%s\".",
|
||||
config.username);
|
||||
}
|
||||
} else {
|
||||
log_message(LOG_WARNING,
|
||||
"Not running as root, so not changing UID/GID.");
|
||||
}
|
||||
/*
|
||||
* Switch to a different user.
|
||||
*/
|
||||
if (geteuid() == 0) {
|
||||
if (config.group && strlen(config.group) > 0) {
|
||||
thisgroup = getgrnam(config.group);
|
||||
if (!thisgroup) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to find group \"%s\".\n",
|
||||
argv[0], config.group);
|
||||
exit(EX_NOUSER);
|
||||
}
|
||||
if (setgid(thisgroup->gr_gid) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to change to group \"%s\".\n",
|
||||
argv[0], config.group);
|
||||
exit(EX_CANTCREAT);
|
||||
}
|
||||
log_message(LOG_INFO, "Now running as group \"%s\".",
|
||||
config.group);
|
||||
}
|
||||
if (config.username && strlen(config.username) > 0) {
|
||||
thisuser = getpwnam(config.username);
|
||||
if (!thisuser) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to find user \"%s\".",
|
||||
argv[0], config.username);
|
||||
exit(EX_NOUSER);
|
||||
}
|
||||
if (setuid(thisuser->pw_uid) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Unable to change to user \"%s\".",
|
||||
argv[0], config.username);
|
||||
exit(EX_CANTCREAT);
|
||||
}
|
||||
log_message(LOG_INFO, "Now running as user \"%s\".",
|
||||
config.username);
|
||||
}
|
||||
} else {
|
||||
log_message(LOG_WARNING,
|
||||
"Not running as root, so not changing UID/GID.");
|
||||
}
|
||||
|
||||
if (child_pool_create() < 0) {
|
||||
fprintf(stderr, "%s: Could not create the pool of children.",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
if (child_pool_create() < 0) {
|
||||
fprintf(stderr, "%s: Could not create the pool of children.",
|
||||
argv[0]);
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
|
||||
/*
|
||||
* These signals are only for the parent process.
|
||||
*/
|
||||
log_message(LOG_INFO, "Setting the various signals.");
|
||||
if (set_signal_handler(SIGCHLD, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGCHLD\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
if (set_signal_handler(SIGTERM, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGTERM\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
if (set_signal_handler(SIGHUP, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGHUP\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
/*
|
||||
* These signals are only for the parent process.
|
||||
*/
|
||||
log_message(LOG_INFO, "Setting the various signals.");
|
||||
if (set_signal_handler(SIGCHLD, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGCHLD\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
if (set_signal_handler(SIGTERM, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGTERM\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
if (set_signal_handler(SIGHUP, takesig) == SIG_ERR) {
|
||||
fprintf(stderr, "%s: Could not set the \"SIGHUP\" signal.\n",
|
||||
argv[0]);
|
||||
exit(EX_OSERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start the main loop.
|
||||
*/
|
||||
log_message(LOG_INFO, "Starting main loop. Accepting connections.");
|
||||
/*
|
||||
* Start the main loop.
|
||||
*/
|
||||
log_message(LOG_INFO, "Starting main loop. Accepting connections.");
|
||||
|
||||
child_main_loop();
|
||||
child_main_loop();
|
||||
|
||||
log_message(LOG_INFO, "Shutting down.");
|
||||
log_message(LOG_INFO, "Shutting down.");
|
||||
|
||||
child_kill_children();
|
||||
child_close_sock();
|
||||
|
||||
/*
|
||||
* Remove the PID file.
|
||||
*/
|
||||
if (unlink(config.pidpath) < 0) {
|
||||
log_message(LOG_WARNING,
|
||||
"Could not remove PID file \"%s\": %s.",
|
||||
config.pidpath, strerror(errno));
|
||||
}
|
||||
child_kill_children();
|
||||
child_close_sock();
|
||||
|
||||
/*
|
||||
* Remove the PID file.
|
||||
*/
|
||||
if (unlink(config.pidpath) < 0) {
|
||||
log_message(LOG_WARNING,
|
||||
"Could not remove PID file \"%s\": %s.",
|
||||
config.pidpath, strerror(errno));
|
||||
}
|
||||
#ifdef FILTER_ENABLE
|
||||
if (config.filter)
|
||||
filter_destroy();
|
||||
#endif /* FILTER_ENABLE */
|
||||
if (config.filter)
|
||||
filter_destroy();
|
||||
#endif /* FILTER_ENABLE */
|
||||
|
||||
if (config.syslog)
|
||||
closelog();
|
||||
else
|
||||
close_log_file();
|
||||
if (config.syslog)
|
||||
closelog();
|
||||
else
|
||||
close_log_file();
|
||||
|
||||
exit(EX_OK);
|
||||
exit(EX_OK);
|
||||
}
|
||||
|
108
src/tinyproxy.h
108
src/tinyproxy.h
@ -1,4 +1,4 @@
|
||||
/* $Id: tinyproxy.h,v 1.46 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: tinyproxy.h,v 1.47 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'tinyproxy.c' for a detailed description.
|
||||
*
|
||||
@ -23,26 +23,26 @@
|
||||
#include "hashmap.h"
|
||||
|
||||
/* Global variables for the main controls of the program */
|
||||
#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */
|
||||
#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */
|
||||
#define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */
|
||||
#define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */
|
||||
|
||||
/*
|
||||
* Even if upstream support is not compiled into tinyproxy, this
|
||||
* structure still needs to be defined.
|
||||
*/
|
||||
struct upstream {
|
||||
struct upstream *next;
|
||||
char *domain; /* optional */
|
||||
char *host;
|
||||
int port;
|
||||
in_addr_t ip, mask;
|
||||
struct upstream *next;
|
||||
char *domain; /* optional */
|
||||
char *host;
|
||||
int port;
|
||||
in_addr_t ip, mask;
|
||||
};
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
struct reversepath {
|
||||
struct reversepath *next;
|
||||
char *path;
|
||||
char *url;
|
||||
struct reversepath *next;
|
||||
char *path;
|
||||
char *url;
|
||||
};
|
||||
|
||||
#define REVERSE_COOKIE "yummy_magical_cookie"
|
||||
@ -52,63 +52,63 @@ struct reversepath {
|
||||
* Hold all the configuration time information.
|
||||
*/
|
||||
struct config_s {
|
||||
char *logf_name;
|
||||
char *config_file;
|
||||
unsigned int syslog; /* boolean */
|
||||
int port;
|
||||
char *stathost;
|
||||
unsigned int quit; /* boolean */
|
||||
char *username;
|
||||
char *group;
|
||||
char *ipAddr;
|
||||
char *logf_name;
|
||||
char *config_file;
|
||||
unsigned int syslog; /* boolean */
|
||||
int port;
|
||||
char *stathost;
|
||||
unsigned int quit; /* boolean */
|
||||
char *username;
|
||||
char *group;
|
||||
char *ipAddr;
|
||||
#ifdef FILTER_ENABLE
|
||||
char *filter;
|
||||
unsigned int filter_url; /* boolean */
|
||||
unsigned int filter_extended; /* boolean */
|
||||
unsigned int filter_casesensitive; /* boolean */
|
||||
#endif /* FILTER_ENABLE */
|
||||
char *filter;
|
||||
unsigned int filter_url; /* boolean */
|
||||
unsigned int filter_extended; /* boolean */
|
||||
unsigned int filter_casesensitive; /* boolean */
|
||||
#endif /* FILTER_ENABLE */
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
char *my_domain;
|
||||
char *my_domain;
|
||||
#endif
|
||||
#ifdef REVERSE_SUPPORT
|
||||
struct reversepath *reversepath_list;
|
||||
unsigned int reverseonly; /* boolean */
|
||||
unsigned int reversemagic; /* boolean */
|
||||
char *reversebaseurl;
|
||||
struct reversepath *reversepath_list;
|
||||
unsigned int reverseonly; /* boolean */
|
||||
unsigned int reversemagic; /* boolean */
|
||||
char *reversebaseurl;
|
||||
#endif
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
struct upstream *upstream_list;
|
||||
#endif /* UPSTREAM_SUPPORT */
|
||||
char *pidpath;
|
||||
unsigned int idletimeout;
|
||||
char* bind_address;
|
||||
unsigned int bindsame;
|
||||
struct upstream *upstream_list;
|
||||
#endif /* UPSTREAM_SUPPORT */
|
||||
char *pidpath;
|
||||
unsigned int idletimeout;
|
||||
char *bind_address;
|
||||
unsigned int bindsame;
|
||||
|
||||
/*
|
||||
* The configured name to use in the HTTP "Via" header field.
|
||||
*/
|
||||
char* via_proxy_name;
|
||||
/*
|
||||
* The configured name to use in the HTTP "Via" header field.
|
||||
*/
|
||||
char *via_proxy_name;
|
||||
|
||||
/*
|
||||
* Error page support. Map error numbers to file paths.
|
||||
*/
|
||||
hashmap_t errorpages;
|
||||
* Error page support. Map error numbers to file paths.
|
||||
*/
|
||||
hashmap_t errorpages;
|
||||
|
||||
/*
|
||||
* Error page to be displayed if appropriate page cannot be located
|
||||
* in the errorpages structure.
|
||||
*/
|
||||
char *errorpage_undef;
|
||||
/*
|
||||
* Error page to be displayed if appropriate page cannot be located
|
||||
* in the errorpages structure.
|
||||
*/
|
||||
char *errorpage_undef;
|
||||
|
||||
/*
|
||||
* The HTML statistics page.
|
||||
*/
|
||||
char *statpage;
|
||||
/*
|
||||
* The HTML statistics page.
|
||||
*/
|
||||
char *statpage;
|
||||
};
|
||||
|
||||
/* Global Structures used in the program */
|
||||
extern struct config_s config;
|
||||
extern unsigned int received_sighup; /* boolean */
|
||||
extern unsigned int processed_config_file; /* boolean */
|
||||
extern unsigned int received_sighup; /* boolean */
|
||||
extern unsigned int processed_config_file; /* boolean */
|
||||
|
||||
#endif
|
||||
|
272
src/utils.c
272
src/utils.c
@ -1,4 +1,4 @@
|
||||
/* $Id: utils.c,v 1.39 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: utils.c,v 1.40 2005-08-15 03:54:31 rjkaes 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,
|
||||
@ -31,26 +31,26 @@
|
||||
*/
|
||||
int
|
||||
send_http_message(struct conn_s *connptr, int http_code,
|
||||
const char *error_title, const char *message)
|
||||
const char *error_title, const char *message)
|
||||
{
|
||||
static char* headers[] = {
|
||||
"Server: " PACKAGE "/" VERSION,
|
||||
"Content-type: text/html",
|
||||
"Connection: close"
|
||||
};
|
||||
static char *headers[] = {
|
||||
"Server: " PACKAGE "/" VERSION,
|
||||
"Content-type: text/html",
|
||||
"Connection: close"
|
||||
};
|
||||
|
||||
http_message_t msg;
|
||||
http_message_t msg;
|
||||
|
||||
msg = http_message_create(http_code, error_title);
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
msg = http_message_create(http_code, error_title);
|
||||
if (msg == NULL)
|
||||
return -1;
|
||||
|
||||
http_message_add_headers(msg, headers, 3);
|
||||
http_message_set_body(msg, message, strlen(message));
|
||||
http_message_send(msg, connptr->client_fd);
|
||||
http_message_destroy(msg);
|
||||
http_message_add_headers(msg, headers, 3);
|
||||
http_message_set_body(msg, message, strlen(message));
|
||||
http_message_send(msg, connptr->client_fd);
|
||||
http_message_destroy(msg);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -59,116 +59,116 @@ send_http_message(struct conn_s *connptr, int http_code,
|
||||
int
|
||||
create_file_safely(const char *filename, unsigned int truncate_file)
|
||||
{
|
||||
struct stat lstatinfo;
|
||||
int fildes;
|
||||
struct stat lstatinfo;
|
||||
int fildes;
|
||||
|
||||
/*
|
||||
* lstat() the file. If it doesn't exist, create it with O_EXCL.
|
||||
* If it does exist, open it for writing and perform the fstat()
|
||||
* check.
|
||||
*/
|
||||
if (lstat(filename, &lstatinfo) < 0) {
|
||||
/*
|
||||
* If lstat() failed for any reason other than "file not
|
||||
* existing", exit.
|
||||
*/
|
||||
if (errno != ENOENT) {
|
||||
fprintf(stderr,
|
||||
"%s: Error checking file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return -EACCES;
|
||||
}
|
||||
/*
|
||||
* lstat() the file. If it doesn't exist, create it with O_EXCL.
|
||||
* If it does exist, open it for writing and perform the fstat()
|
||||
* check.
|
||||
*/
|
||||
if (lstat(filename, &lstatinfo) < 0) {
|
||||
/*
|
||||
* If lstat() failed for any reason other than "file not
|
||||
* existing", exit.
|
||||
*/
|
||||
if (errno != ENOENT) {
|
||||
fprintf(stderr,
|
||||
"%s: Error checking file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return -EACCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* The file doesn't exist, so create it with O_EXCL to make
|
||||
* sure an attacker can't slip in a file between the lstat()
|
||||
* and open()
|
||||
*/
|
||||
if ((fildes =
|
||||
open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not create file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
} else {
|
||||
struct stat fstatinfo;
|
||||
int flags;
|
||||
/*
|
||||
* The file doesn't exist, so create it with O_EXCL to make
|
||||
* sure an attacker can't slip in a file between the lstat()
|
||||
* and open()
|
||||
*/
|
||||
if ((fildes =
|
||||
open(filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not create file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
} else {
|
||||
struct stat fstatinfo;
|
||||
int flags;
|
||||
|
||||
flags = O_RDWR;
|
||||
if (!truncate_file)
|
||||
flags |= O_APPEND;
|
||||
flags = O_RDWR;
|
||||
if (!truncate_file)
|
||||
flags |= O_APPEND;
|
||||
|
||||
/*
|
||||
* Open an existing file.
|
||||
*/
|
||||
if ((fildes = open(filename, flags)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not open file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
/*
|
||||
* Open an existing file.
|
||||
*/
|
||||
if ((fildes = open(filename, flags)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not open file %s: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
|
||||
/*
|
||||
* fstat() the opened file and check that the file mode bits,
|
||||
* inode, and device match.
|
||||
*/
|
||||
if (fstat(fildes, &fstatinfo) < 0
|
||||
|| lstatinfo.st_mode != fstatinfo.st_mode
|
||||
|| lstatinfo.st_ino != fstatinfo.st_ino
|
||||
|| lstatinfo.st_dev != fstatinfo.st_dev) {
|
||||
fprintf(stderr,
|
||||
"%s: The file %s has been changed before it could be opened\n",
|
||||
PACKAGE, filename);
|
||||
close(fildes);
|
||||
return -EIO;
|
||||
}
|
||||
/*
|
||||
* fstat() the opened file and check that the file mode bits,
|
||||
* inode, and device match.
|
||||
*/
|
||||
if (fstat(fildes, &fstatinfo) < 0
|
||||
|| lstatinfo.st_mode != fstatinfo.st_mode
|
||||
|| lstatinfo.st_ino != fstatinfo.st_ino
|
||||
|| lstatinfo.st_dev != fstatinfo.st_dev) {
|
||||
fprintf(stderr,
|
||||
"%s: The file %s has been changed before it could be opened\n",
|
||||
PACKAGE, filename);
|
||||
close(fildes);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the above check was passed, we know that the lstat()
|
||||
* and fstat() were done on the same file. Now we check that
|
||||
* there's only one link, and that it's a normal file (this
|
||||
* isn't strictly necessary because the fstat() vs lstat()
|
||||
* st_mode check would also find this)
|
||||
*/
|
||||
if (fstatinfo.st_nlink > 1 || !S_ISREG(lstatinfo.st_mode)) {
|
||||
fprintf(stderr,
|
||||
"%s: The file %s has too many links, or is not a regular file: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
close(fildes);
|
||||
return -EMLINK;
|
||||
}
|
||||
/*
|
||||
* If the above check was passed, we know that the lstat()
|
||||
* and fstat() were done on the same file. Now we check that
|
||||
* there's only one link, and that it's a normal file (this
|
||||
* isn't strictly necessary because the fstat() vs lstat()
|
||||
* st_mode check would also find this)
|
||||
*/
|
||||
if (fstatinfo.st_nlink > 1 || !S_ISREG(lstatinfo.st_mode)) {
|
||||
fprintf(stderr,
|
||||
"%s: The file %s has too many links, or is not a regular file: %s\n",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
close(fildes);
|
||||
return -EMLINK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Just return the file descriptor if we _don't_ want the file
|
||||
* truncated.
|
||||
*/
|
||||
if (!truncate_file)
|
||||
return fildes;
|
||||
/*
|
||||
* Just return the file descriptor if we _don't_ want the file
|
||||
* truncated.
|
||||
*/
|
||||
if (!truncate_file)
|
||||
return fildes;
|
||||
|
||||
/*
|
||||
* On systems which don't support ftruncate() the best we can
|
||||
* do is to close the file and reopen it in create mode, which
|
||||
* unfortunately leads to a race condition, however "systems
|
||||
* which don't support ftruncate()" is pretty much SCO only,
|
||||
* and if you're using that you deserve what you get.
|
||||
* ("Little sympathy has been extended")
|
||||
*/
|
||||
/*
|
||||
* On systems which don't support ftruncate() the best we can
|
||||
* do is to close the file and reopen it in create mode, which
|
||||
* unfortunately leads to a race condition, however "systems
|
||||
* which don't support ftruncate()" is pretty much SCO only,
|
||||
* and if you're using that you deserve what you get.
|
||||
* ("Little sympathy has been extended")
|
||||
*/
|
||||
#ifdef HAVE_FTRUNCATE
|
||||
ftruncate(fildes, 0);
|
||||
ftruncate(fildes, 0);
|
||||
#else
|
||||
close(fildes);
|
||||
if ((fildes =
|
||||
open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not open file %s: %s.",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
#endif /* HAVE_FTRUNCATE */
|
||||
}
|
||||
close(fildes);
|
||||
if ((fildes =
|
||||
open(filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not open file %s: %s.",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
return fildes;
|
||||
}
|
||||
#endif /* HAVE_FTRUNCATE */
|
||||
}
|
||||
|
||||
return fildes;
|
||||
return fildes;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -177,28 +177,28 @@ create_file_safely(const char *filename, unsigned int truncate_file)
|
||||
int
|
||||
pidfile_create(const char *filename)
|
||||
{
|
||||
int fildes;
|
||||
FILE *fd;
|
||||
int fildes;
|
||||
FILE *fd;
|
||||
|
||||
/*
|
||||
* Create a new file
|
||||
*/
|
||||
if ((fildes = create_file_safely(filename, TRUE)) < 0)
|
||||
return fildes;
|
||||
/*
|
||||
* Create a new file
|
||||
*/
|
||||
if ((fildes = create_file_safely(filename, TRUE)) < 0)
|
||||
return fildes;
|
||||
|
||||
/*
|
||||
* Open a stdio file over the low-level one.
|
||||
*/
|
||||
if ((fd = fdopen(fildes, "w")) == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not write PID file %s: %s.",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
close(fildes);
|
||||
unlink(filename);
|
||||
return -EIO;
|
||||
}
|
||||
/*
|
||||
* Open a stdio file over the low-level one.
|
||||
*/
|
||||
if ((fd = fdopen(fildes, "w")) == NULL) {
|
||||
fprintf(stderr,
|
||||
"%s: Could not write PID file %s: %s.",
|
||||
PACKAGE, filename, strerror(errno));
|
||||
close(fildes);
|
||||
unlink(filename);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fprintf(fd, "%ld\n", (long) getpid());
|
||||
fclose(fd);
|
||||
return 0;
|
||||
fprintf(fd, "%ld\n", (long)getpid());
|
||||
fclose(fd);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $Id: utils.h,v 1.24 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: utils.h,v 1.25 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* See 'utils.h' for a detailed description.
|
||||
*
|
||||
@ -25,7 +25,7 @@
|
||||
struct conn_s;
|
||||
|
||||
extern int send_http_message(struct conn_s *connptr, int http_code,
|
||||
const char *error_title, const char *message);
|
||||
const char *error_title, const char *message);
|
||||
|
||||
extern int pidfile_create(const char *path);
|
||||
extern int create_file_safely(const char *filename, unsigned int truncate_file);
|
||||
|
154
src/vector.c
154
src/vector.c
@ -1,4 +1,4 @@
|
||||
/* $Id: vector.c,v 1.12 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: vector.c,v 1.13 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* A vector implementation. The vector can be of an arbitrary length, and
|
||||
* the data for each entry is an lump of data (the size is stored in the
|
||||
@ -34,16 +34,16 @@
|
||||
* count of the number of entries (or how long the vector is.)
|
||||
*/
|
||||
struct vectorentry_s {
|
||||
void *data;
|
||||
size_t len;
|
||||
void *data;
|
||||
size_t len;
|
||||
|
||||
struct vectorentry_s *next;
|
||||
struct vectorentry_s *next;
|
||||
};
|
||||
|
||||
struct vector_s {
|
||||
size_t num_entries;
|
||||
struct vectorentry_s *head;
|
||||
struct vectorentry_s *tail;
|
||||
size_t num_entries;
|
||||
struct vectorentry_s *head;
|
||||
struct vectorentry_s *tail;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -56,16 +56,16 @@ struct vector_s {
|
||||
vector_t
|
||||
vector_create(void)
|
||||
{
|
||||
vector_t vector;
|
||||
vector_t vector;
|
||||
|
||||
vector = safemalloc(sizeof(struct vector_s));
|
||||
if (!vector)
|
||||
return NULL;
|
||||
vector = safemalloc(sizeof(struct vector_s));
|
||||
if (!vector)
|
||||
return NULL;
|
||||
|
||||
vector->num_entries = 0;
|
||||
vector->head = vector->tail = NULL;
|
||||
|
||||
return vector;
|
||||
vector->num_entries = 0;
|
||||
vector->head = vector->tail = NULL;
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -77,23 +77,23 @@ vector_create(void)
|
||||
int
|
||||
vector_delete(vector_t vector)
|
||||
{
|
||||
struct vectorentry_s *ptr, *next;
|
||||
struct vectorentry_s *ptr, *next;
|
||||
|
||||
if (!vector)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = vector->head;
|
||||
while (ptr) {
|
||||
next = ptr->next;
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
if (!vector)
|
||||
return -EINVAL;
|
||||
|
||||
ptr = next;
|
||||
}
|
||||
ptr = vector->head;
|
||||
while (ptr) {
|
||||
next = ptr->next;
|
||||
safefree(ptr->data);
|
||||
safefree(ptr);
|
||||
|
||||
safefree(vector);
|
||||
ptr = next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
safefree(vector);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -112,42 +112,42 @@ vector_delete(vector_t vector)
|
||||
static int
|
||||
vector_insert(vector_t vector, void *data, ssize_t len, int pos)
|
||||
{
|
||||
struct vectorentry_s *entry;
|
||||
struct vectorentry_s *entry;
|
||||
|
||||
if (!vector || !data || len <= 0 ||
|
||||
(pos != INSERT_PREPEND && pos != INSERT_APPEND))
|
||||
return -EINVAL;
|
||||
if (!vector || !data || len <= 0 ||
|
||||
(pos != INSERT_PREPEND && pos != INSERT_APPEND))
|
||||
return -EINVAL;
|
||||
|
||||
entry = safemalloc(sizeof(struct vectorentry_s));
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
entry = safemalloc(sizeof(struct vectorentry_s));
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
|
||||
entry->data = safemalloc(len);
|
||||
if (!entry->data) {
|
||||
safefree(entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
entry->data = safemalloc(len);
|
||||
if (!entry->data) {
|
||||
safefree(entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(entry->data, data, len);
|
||||
entry->len = len;
|
||||
entry->next = NULL;
|
||||
memcpy(entry->data, data, len);
|
||||
entry->len = len;
|
||||
entry->next = NULL;
|
||||
|
||||
/* If there is no head or tail, create them */
|
||||
if (!vector->head && !vector->tail)
|
||||
vector->head = vector->tail = entry;
|
||||
else if (pos == 0) {
|
||||
/* prepend the entry */
|
||||
entry->next = vector->head;
|
||||
vector->head = entry;
|
||||
} else {
|
||||
/* append the entry */
|
||||
vector->tail->next = entry;
|
||||
vector->tail = entry;
|
||||
}
|
||||
|
||||
vector->num_entries++;
|
||||
/* If there is no head or tail, create them */
|
||||
if (!vector->head && !vector->tail)
|
||||
vector->head = vector->tail = entry;
|
||||
else if (pos == 0) {
|
||||
/* prepend the entry */
|
||||
entry->next = vector->head;
|
||||
vector->head = entry;
|
||||
} else {
|
||||
/* append the entry */
|
||||
vector->tail->next = entry;
|
||||
vector->tail = entry;
|
||||
}
|
||||
|
||||
return 0;
|
||||
vector->num_entries++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -158,13 +158,13 @@ vector_insert(vector_t vector, void *data, ssize_t len, int pos)
|
||||
int
|
||||
vector_append(vector_t vector, void *data, ssize_t len)
|
||||
{
|
||||
return vector_insert(vector, data, len, INSERT_APPEND);
|
||||
return vector_insert(vector, data, len, INSERT_APPEND);
|
||||
}
|
||||
|
||||
int
|
||||
vector_prepend(vector_t vector, void *data, ssize_t len)
|
||||
{
|
||||
return vector_insert(vector, data, len, INSERT_PREPEND);
|
||||
return vector_insert(vector, data, len, INSERT_PREPEND);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -175,26 +175,26 @@ vector_prepend(vector_t vector, void *data, ssize_t len)
|
||||
* length of data if position is valid
|
||||
*/
|
||||
void *
|
||||
vector_getentry(vector_t vector, size_t pos, size_t* size)
|
||||
vector_getentry(vector_t vector, size_t pos, size_t * size)
|
||||
{
|
||||
struct vectorentry_s *ptr;
|
||||
size_t loc;
|
||||
struct vectorentry_s *ptr;
|
||||
size_t loc;
|
||||
|
||||
if (!vector || pos < 0 || pos >= vector->num_entries)
|
||||
return NULL;
|
||||
if (!vector || pos < 0 || pos >= vector->num_entries)
|
||||
return NULL;
|
||||
|
||||
loc = 0;
|
||||
ptr = vector->head;
|
||||
loc = 0;
|
||||
ptr = vector->head;
|
||||
|
||||
while (loc != pos) {
|
||||
ptr = ptr->next;
|
||||
loc++;
|
||||
}
|
||||
while (loc != pos) {
|
||||
ptr = ptr->next;
|
||||
loc++;
|
||||
}
|
||||
|
||||
if (size)
|
||||
*size = ptr->len;
|
||||
if (size)
|
||||
*size = ptr->len;
|
||||
|
||||
return ptr->data;
|
||||
return ptr->data;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -206,8 +206,8 @@ vector_getentry(vector_t vector, size_t pos, size_t* size)
|
||||
ssize_t
|
||||
vector_length(vector_t vector)
|
||||
{
|
||||
if (!vector)
|
||||
return -EINVAL;
|
||||
if (!vector)
|
||||
return -EINVAL;
|
||||
|
||||
return vector->num_entries;
|
||||
return vector->num_entries;
|
||||
}
|
||||
|
22
src/vector.h
22
src/vector.h
@ -1,4 +1,4 @@
|
||||
/* $Id: vector.h,v 1.6 2005-07-12 17:39:44 rjkaes Exp $
|
||||
/* $Id: vector.h,v 1.7 2005-08-15 03:54:31 rjkaes Exp $
|
||||
*
|
||||
* A vector implementation. The vector can be of an arbritrary length, and
|
||||
* the data for each entry is an lump of data (the size is stored in the
|
||||
@ -34,14 +34,14 @@ extern "C" {
|
||||
* vector. Sure, it's a pointer, but the struct is hidden in the C file.
|
||||
* So, just use the vector_t like it's a cookie. :)
|
||||
*/
|
||||
typedef struct vector_s *vector_t;
|
||||
typedef struct vector_s *vector_t;
|
||||
|
||||
/*
|
||||
* vector_create() takes no arguments.
|
||||
* vector_delete() is self explanatory.
|
||||
*/
|
||||
extern vector_t vector_create(void);
|
||||
extern int vector_delete(vector_t vector);
|
||||
extern vector_t vector_create(void);
|
||||
extern int vector_delete(vector_t vector);
|
||||
|
||||
/*
|
||||
* When you insert a piece of data into the vector, the data will be
|
||||
@ -51,8 +51,8 @@ extern int vector_delete(vector_t vector);
|
||||
* Returns: negative on error
|
||||
* 0 upon successful insert.
|
||||
*/
|
||||
extern int vector_append(vector_t vector, void *data, ssize_t len);
|
||||
extern int vector_prepend(vector_t vector, void *data, ssize_t len);
|
||||
extern int vector_append(vector_t vector, void *data, ssize_t len);
|
||||
extern int vector_prepend(vector_t vector, void *data, ssize_t len);
|
||||
|
||||
/*
|
||||
* A pointer to the data at position "pos" (zero based) is returned and the
|
||||
@ -70,7 +70,8 @@ extern int vector_prepend(vector_t vector, void *data, ssize_t len);
|
||||
* Returns: NULL on error
|
||||
* valid pointer to data
|
||||
*/
|
||||
extern void* vector_getentry(vector_t vector, size_t pos, size_t* size);
|
||||
extern void *vector_getentry(vector_t vector, size_t pos,
|
||||
size_t * size);
|
||||
|
||||
/*
|
||||
* Returns the number of enteries (or the length) of the vector.
|
||||
@ -78,10 +79,9 @@ extern void* vector_getentry(vector_t vector, size_t pos, size_t* size);
|
||||
* Returns: negative if vector is not valid
|
||||
* positive length of vector otherwise
|
||||
*/
|
||||
extern ssize_t vector_length(vector_t vector);
|
||||
extern ssize_t vector_length(vector_t vector);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif /* C++ */
|
||||
|
||||
#endif /* _VECTOR_H */
|
||||
#endif /* C++ */
|
||||
#endif /* _VECTOR_H */
|
||||
|
Loading…
x
Reference in New Issue
Block a user