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