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