]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
cleanup after big merge
authorwessels <>
Tue, 9 Jul 1996 09:40:58 +0000 (09:40 +0000)
committerwessels <>
Tue, 9 Jul 1996 09:40:58 +0000 (09:40 +0000)
52 files changed:
CONTRIBUTORS
COPYING [new file with mode: 0644]
ChangeLog
INSTALL
README
configure
configure.in
doc/HTTP-codes.txt [new file with mode: 0644]
include/autoconf.h.in
include/tempnam.h [new file with mode: 0644]
include/util.h
lib/GNUregex.c
lib/Makefile.in
lib/getfullhostname.c
lib/rfc1738.c
lib/tempnam.c [new file with mode: 0644]
lib/util.c
scripts/RunAccel.in
scripts/RunCache.in
scripts/check_cache.pl
scripts/udp-banger.pl
src/Makefile.in
src/acl.cc
src/cache_cf.cc
src/cachemgr.cc
src/client.cc
src/comm.cc
src/debug.cc
src/disk.cc
src/dnsserver.cc
src/errorpage.cc
src/filemap.cc
src/ftp.cc
src/gopher.cc
src/http.cc
src/ident.cc
src/ipcache.cc
src/main.cc
src/mime.cc
src/neighbors.cc
src/recv-announce.cc
src/redirect.cc [new file with mode: 0644]
src/send-announce.cc
src/squid.h
src/ssl.cc
src/stat.cc
src/stmem.cc
src/store.cc
src/tools.cc
src/tunnel.cc
src/url.cc
src/wais.cc

index f18bc737af9f0544b572e2c0ad49dbef07e0469c..da3777106a84dd2d27c20739b8b4cbed7478274f 100644 (file)
@@ -3,13 +3,34 @@ and ideas to make this software available.
 
        Henrik Nordstrom <henrik.nordstrom@ida.his.se>
        Daniel O'Callaghan <danny@miriworld.its.unimelb.EDU.AU>
+       George Michaelson <ggm@connect.com.au>
+       Taavi Talvik <taavi@uninet.ee>
+       Luke Howard <lukeh@vurt.schnet.edu.au>
+       Assar Westerlund <assar@pdc.kth.se>
+       James R Grinter <jrg@demon.net>
+       Shigechika Aikawa <shige@luck.imasy.or.jp>
+       Russell Vincent <vincent@ucthpx.uct.ac.za>
        Edward Moy <moy@parc.xerox.com>
        Jean-Francois Micouleau <Jean-Francois.Micouleau@utc.fr>
+       Ansgar Hockmann <Ansgar.Hockmann@hrz.uni-dortmund.de>
+       Joe Ramey <ramey@jello.csc.ti.com>
+       Kolics Bertold <bertold@tohotom.vein.hu>
+       Doug Urner <dlu@wobble.albatross.com>
+       Markus Gyger <mgyger@itr.ch>
+       Richard Huveneers <Richard.Huveneers@hekkihek.hacom.nl>
+       Markus Stumpf <maex@Space.NET>
        Wojtek Sylwestrzak <W.Sylwestrzak@icm.edu.pl>
+       Brian Denehy <B-Denehy@adfa.oz.au>
+       David Luyer <luyer@ucs.uwa.edu.au>
+       Carson Gaspar (carson@lehman.com, carson@cs.columbia.edu)
+       Pete Bentley <pete@demon.net>
+       Alexander B. Demenshin <aldem@barnet.kharkov.ua>
+       Tony Lorimer <tlorimer@au.mdis.com>
 
 
 Development of this caching software is funded by the National Science
-Foundation.  Paid staff members on the caching project are:
+Foundation (grant NCR-9521745).  Paid staff members on the caching
+project are:
 
        Duane Wessels <wessels@nlanr.net>
        K Claffy <kc@nlanr.net>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..a43ea21
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
index b2517d4105d6ad88a5a3e795b8e636fd9be64194..7cde21279e2fe7b4b9ecd7b45c311c37d98cf342 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,280 @@
-
 Changes to squid-1.1.alpha2:
 
        - Added Support for RFC931/ident
 
-==============================================================================
+Changes to squid-1.0.1 (July 8, 1996):
+
+       - Fixed ftpget server looping on socket EOF condition.
+       - Fixed SA_RESETHAND undefined bug.
+       - Fixed half-hour timezone offset bug.
+       - Fixed parse_rfc850() to return -1 instead of 0 upon error.
+       - Added patch for Motorola systems from Tony Lorimer.
+       - Added support for HTTP PUT method.
+       - Added check for <netinet/tcp.h> for HP-UX.
+       - Added GNU General Public License.
+       - Changed ttlSet() to use Date field if Last-Modified is absent.
+       - Changed http.c to not save objects from neighbors which do
+         not have Date, Last-Modified, or Expires values.
+       - Changed some large local character arrays to static.
+
+Changes to squid-1.0.0 (July 1, 1996):
+
+       - Fixed beta17 "fd_lifetime" typo bug
+       - Added 'firewall_ip_list' to configuration options
+       - Set resolver options to disable searching default domains
+         and parent domains.
+       - Added blocking-rebuild -F option.
+       - Fixed storeMaintainSwapSpace to be called every 10 seconds.
+       - Fixed ICP_HIT_OBJ bug causing objects to get stuck in VM.
+       - Fixed matching the ends of domain names (e.g. bar.com no 
+         longer matches foobar.com).
+       - Fixed checking return code from fprintf() while writing the
+         clean swap log.
+       - Fixed fatal_dump from storeSwapoutHandle running out of disk
+         space.
+       - Added disabling of a neighbor cache if 95% of replies are
+         UDP_DENIED.
+       - Added accounting for misc memory/data structures
+       - Added 'no-query' option for 'cache_host' config line
+       - Added error reporting to SSL requests.
+       - Fixed SSL bug, client abort was not closing the server
+         side connection.
+       - Fixed checking hierarchy_stoplist bug.
+       - Fixed ipcache error messages by giving each entry its
+         own string.
+       - Use sigaction() instead of signal() if available.
+       - Fixed ipcache bug causing some lookups to get stuck in
+         PENDING state if all dnsservers are busy.
+       - Fixed domain name matching bug when using '.com' instead of
+         'com'.
+       - Fixed close_handler coredump bug in comm.c.
+       - Removed unnecessary DNS lookup of hostnames in WAIS URLs.
+
+Changes to squid-1.0.beta17 (June 12, 1996):
+
+       - Fixed another ipcache coredump problem where an entry could
+         be released between writing to and reading from dnsserver.
+       - Fixed store.c bug of purging aborted objects.
+       - Cleaned up checkLifetimes() function to make it simpler.
+       - Added visible_hostname support to ftpget.
+       - Fixed null edge dereferencing bug for UDP_HIT_OBJ.
+
+Changes to squid-1.0.beta16 (June 10, 1996):
+
+       - Fixed two coredump-causing bugs in ipcache_unregister().
+       - Changed 'close_handler' to a linked list.
+       - Changed freeing of protodispatch_data structures to use
+         new close_handler (attached to client FD).
+       - Fixed URL handling to accomodate browswers which do not handle
+         relative URL parsing.
+
+Changes to squid-1.0.beta15 (June 9, 1996):
+
+       - Fixed storeSwapoutHandle coredump bug
+       - Fixed DNS lookup failure of neighbor hosts after a few hours
+         of operation
+       - Changed memcpy() to memmove() for overlapping memory copies
+       - Changed store rebuidling to unlink the log-last-clean file
+         in case of a crash during rebuild
+       - Added forwarding loop detection
+       - Changed all memcpy to use xmemcpy which is memmove, bcopy, or
+         memcpy.
+       - Fixed coredump bug from partial dnsserver reads, manifest on
+         FreeBSD and NetBSD.
+
+Changes to squid-1.0.beta14 (June 7, 1996):
+
+       - Fixed coredump bug in icp.c when generating ``Not Modified''
+         replies.
+       - Fixed SSL bug which assumed the requested host name would
+         already be in the IP cache.
+       - Fixed names of generated HTTP reply headers.
+
+Changes to squid-1.0.beta13 (June 7, 1996):
+
+       - Fixed coredump bug where StoreEntry key was free'd too soon.
+       - Fixed UDP_HIT_OBJ bug: cancel the hierarchy timeout and set
+         the ping_status to DONE for UDP_HIT_OBJ replies.
+
+Changes to squid-1.0.beta12 (June 6, 1996):
+
+       - Fixed problem when using udp_outgoing_addr where no ICP
+         packets would be recieved because they were getting sent
+         to the "outgoing" instead of the "incoming" socket.
+       - Fixed objects hanging around in cache after a keychange.
+       - Added ability to restrict neighbor caches with ACLs.
+         ('cache_host_acl').
+       - Fixed ssl FD mismatch bug.
+       - Fixed INADDR_NONE bug on 64bit systems.
+       - Fixed store rebuilding bug; temporary log file was not being
+         truncated.
+       - Made all external processes communicate with TCP sockets
+         (no more Unix domain sockets).
+       - Semi-major rewrite of ipcache implementation.
+       - Fixed a couple memory bugs found by purify.
+       - Fixed sending large (>8192 bytes) HTTP requests.
+       - Added "lazy" server IP address ACL checks (type 'dst').
+       - Changed handling of IMS requests.  Now will return "304
+         Not Modified" if the requested object is in the cache
+         and not expired.
+
+Changes to squid-1.0.beta11 (June 1, 1996):
+
+       - Fixed serious memory leak of MemObject->reply structures.
+
+
+Changes to squid-1.0.beta10 (May 31, 1996):
+
+       - Fixed bug when request arrives in fragmented IP packets.
+       - Fixed ACL bug which denied cache manager access while in
+         httpd_accel mode.
+       - Changed ftpget to "fail nicely" for sites which do not allow
+         PORT requests (if compiled with PASVONLY).
+       - Fixed Unix domain socket off-by-one bug in ftpget.
+       - Fixed lingering sockets after shutdown by SIGTERM.
+       - Added dnsserver use histogram to ipcache stats.
+       - Changed domain ACL's to match only the end of the hostname, not
+         just anywhere in the string.
+       - Fixed setuid bugs when pid_filename was not defined
+       - Fixed zero-sized object getting stuck in VM.
+       - Configure checks for working UNIX domain stream sockets
+       - Rotate cache.log before the others
+       - SIGUSR2 now toggles between full and normal debugging
+       - Close and restart ftpget server during logfile rotation
+       - Added memory pools for request_t and MemObject data structures.
+       - Added new address binding options for more control
+
+Changes to squid-1.0.beta9 (May 23, 1996):
+
+       - Fixed storeToString() coredump bug on 'swap_buf'
+       - Added back the CIDR notation functionality to decoding IP
+         address ACLs.
+       - Fixed ftpget listing parsing coredump bug.
+       - Fixed neighborsUdpAck() coredump for late-arriving ICP replies.
+
+Changes to squid-1.0.beta8 (May 22, 1996):
+
+       - More friendly CFLAGS and LDFLAGS for configure
+       - ACL_ALLWEEK bugfix
+       - Added missing increment of UDP connection counter.
+       - Changed ftpget select to check for EWOULDBLOCK/EAGAIN
+         (workaround for broken Solaris select(2)).
+       - Fixed MALLINFO calls for Linux
+       - Fixed strerror() problems on SunOS 4.1.x
+       - Fixed DefaultAnnounceRate; set to zero by defult.
+       - Changed all port variables to u_short.
+       - Created AF_UNIX versions of comm_open(), comm_connect().
+       - Changed ftpget server to use UNIX domain socket.
+       - Removed RESET_SIGNAL_HANDLER check--always reset the signal
+         handler.
+       - Added instrumentation of basic IPCache stats.
+       - Fixed calculation of neighbor average RTT.
+       - Added 'outbound_addr_list' to config
+       - Change getFirstParent() to getFirstUpParent().
+       - Changed ftpget to use an additional pipe() for crash detection
+       - Added ICP_OP_DENIED message type
+       - Added patches for Nextstep port from Luke Howard
+         <lukeh@vurt.schnet.edu.au>
+       - Added a lifetime to HTTP server connections being deferred.
+       - Added IP address ranges in 'src' ACLs
+       - Added FQDN's in 'src' ACLs
+       - Fixed request structure free-memory-read/coredump bug.
+       - Changed icp.c to select on client socket to detect aborts.
+       - Better compliance with HTTP/1.1 *DRAFT* regarding which reply
+         codes can be cached.
+       - Added 'hierarchy_stoplist' configuration option.
+       - Changed mallopt option M_MXFAST to 512 bytes.
+       - Added -Y option to only return UDP_HIT or UDP_DENIED during
+         store reload.
+       - Added UDP_HIT_OBJ type.  Just like a UDP_HIT, but object data
+         is returned in the UDP packet if it will fit; saves a TCP
+         connection.  Not compiled in by default, add -DUDP_HIT_WITH_OBJ
+         to src/Makefile DEFINES.
+
+Changes to squid-1.0.beta7:
+
+       - Fixed comm_udp_sendto continuous loop bug
+       - Fixed URLs-with-colon-but-no-port-number bug
+       - Fixed sending ICP queries for HEAD requests
+       - Changed 'server_list' output.  Added RTT, Fetches, Hits, Misses,
+         and percents.
+       - Fixed setuid bug causing some logs to be owned by root.
+       - Fixed virtual host mode (-V option)
+       - Added read(2) instrumentation for HTTP and FTP.
+       - Changed neighbor initialization to continue if DNS lookup fails.
+       - Lint cleanup
+
+Changes to squid-1.0.beta6:
+
+       - Fixed null error message coredump in ftpget.
+       - Added -m Method option to `client'.
+       - Fixed ftpget server bug with missing trailing slash.
+       - Removed 'connect_ports' from config, use general ACLs instead.
+       - Changed requested listen queue length to 1/4 of getMaxFD().
+       - Rewrote SSL/CONNECT handlers.  Now doesn't use a StoreEntry.
+       - Fixed some aborted objects getting stuck in VM bug.
+       - Fixed ftpget PASV reply sscanf to work for VMS ftpd.
+       - Changed FTP URL parsing to use urlParse().
+       - Changed ftpget to skip RETR command if URLs ends with '/'.
+       - Changed ftpget to display README at the bottom if there are other
+         server messages.
+       - Changed ftpget to not reopen a new data connection
+         if one is already open.
+       - Fixed handling of FTP URLs with spaces (and other unsafe characters)
+       - Changed ftpget to only generate BASE HREF if the FTP URL does
+         not end with '/'.
+
+Changes to squid-1.0.beta5:
+
+       - Fixed cachemgr to send 'HTTP/1.0' on request so it works
+         with beta4 fixes to icp.c.
+
+Changes to squid-1.0.beta4:
+
+       - Added a handler to restart the ftpget server.
+       - Fixed access checks for ICP by parsing the requested URL.
+       - Added "magic marker" to ftpget-generated errors so they can
+         be negative-cached.
+       - Added a small run-time check to configure to see if signal
+         handlers should be restarted after invocation (ala SYSV).
+       - Determine Maximum filedescriptors in configure and change
+         FD_SETSIZE if needed.
+       - Changed read stall algorithm for HTTP.  No don't wait until
+         the object is in DELETE_BEHIND mode to stall the server read
+         and wait for the client to catch up.  Also changed from 4k to
+         16k read buffer.
+       - Fixed HTTP request parsing to check for blank line at the
+         end of all requests.  Symptoms were "connection reset"
+         messages.
+
+Changes to squid-1.0.beta3:
+
+       - Added ftpget '-C minport:maxport' option
+       - Fixed PROTO_MAX fencepost bug in stat_init().
+       - Fixed Fixed CheckQuickAbort() coredump.
+       - Fixed disabling store.log and hierarchy.log when set to "none"
+       - Fixed numerous problems related to setuid().
+       - Fixed 'check_cache.pl' to use new swaplog format (without "FILE").
+       - Fixed ACL coredumps when checking NULL words.
+       - Changed pid_filename to be written and unlinked as root.
+       - Added "-i seconds" option to 'client' for testing IMS GET.
+       - Fixed a bug where an IMS request caused the valid object to
+         get ejected from the cache.
+       - Fixed continual DEAD_PARENT/REVIVE bug
+       - Fixed ERR_INVALID_URL bug for URLs with a password field.
+       - Added to Release-Notes info about converting 'cache/log' and
+         difference between stoplists and ttl_pattern.
+
+Changes to squid-1.0.beta2:
+
+       - Fixed /bin/csh "$#argv" leftover in RunCache.
+       - Fixed ACL day-of-week bitmask bug.
+       - Fixed missing checks for WAIS in some places.
+       - Fixed chdir(swappath(0)) bug; do chdir() after storeInit().
+       - Changed enumerated structure members to be defined outside
+         of the structure itself (for AIX).
+       - Changed ftpget to fork before reading the request and make
+         sure the entire request is read.
 
 Changes to squid-1.0.beta1 (Apr 19, 1996) from Harvest cached-1.4.pl3:
 
@@ -75,75 +346,3 @@ Changes to squid-1.0.beta1 (Apr 19, 1996) from Harvest cached-1.4.pl3:
        - Removed all code and references to binary port.
        - Removed dual logging to stderr/cache.log.
        - Removed old IP access controls ('proxy_allow', etc.)
-
-Changes to 1.0.beta2:
-
-       - Fixed /bin/csh "$#argv" leftover in RunCache.
-       - Fixed ACL day-of-week bitmask bug.
-       - Fixed missing checks for WAIS in some places.
-       - Fixed chdir(swappath(0)) bug; do chdir() after storeInit().
-       - Changed enumerated structure members to be defined outside
-         of the structure itself (for AIX).
-       - Changed ftpget to fork before reading the request and make
-         sure the entire request is read.
-
-Changes to 1.0.beta3:
-
-       - Added ftpget '-C minport:maxport' option
-       - Fixed PROTO_MAX fencepost bug in stat_init().
-       - Fixed Fixed CheckQuickAbort() coredump.
-       - Fixed disabling store.log and hierarchy.log when set to "none"
-       - Fixed numerous problems related to setuid().
-       - Fixed 'check_cache.pl' to use new swaplog format (without "FILE").
-       - Fixed ACL coredumps when checking NULL words.
-       - Changed pid_filename to be written and unlinked as root.
-       - Added "-i seconds" option to 'client' for testing IMS GET.
-       - Fixed a bug where an IMS request caused the valid object to
-         get ejected from the cache.
-       - Fixed continual DEAD_PARENT/REVIVE bug
-       - Fixed ERR_INVALID_URL bug for URLs with a password field.
-       - Added to Release-Notes info about converting 'cache/log' and
-         difference between stoplists and ttl_pattern.
-
-Changes to squid-1.0.beta4:
-
-       - Added a handler to restart the ftpget server.
-       - Fixed access checks for ICP by parsing the requested URL.
-       - Added "magic marker" to ftpget-generated errors so they can
-         be negative-cached.
-       - Added a small run-time check to configure to see if signal
-         handlers should be restarted after invocation (ala SYSV).
-       - Determine Maximum filedescriptors in configure and change
-         FD_SETSIZE if needed.
-       - Changed read stall algorithm for HTTP.  No don't wait until
-         the object is in DELETE_BEHIND mode to stall the server read
-         and wait for the client to catch up.  Also changed from 4k to
-         16k read buffer.
-       - Fixed HTTP request parsing to check for blank line at the
-         end of all requests.  Symptoms were "connection reset"
-         messages.
-
-Changes to squid-1.0.beta5:
-
-       - Fixed cachemgr to send 'HTTP/1.0' on request so it works
-         with beta4 fixes to icp.c.
-
-Changes to squid-1.0.beta6:
-
-       - Fixed null error message coredump in ftpget.
-       - Added -m Method option to `client'.
-       - Fixed ftpget server bug with missing trailing slash.
-       - Removed 'connect_ports' from config, use general ACLs instead.
-       - Changed requested listen queue length to 1/4 of getMaxFD().
-       - Rewrote SSL/CONNECT handlers.  Now doesn't use a StoreEntry.
-       - Fixed some aborted objects getting stuck in VM bug.
-       - Fixed ftpget PASV reply sscanf to work for VMS ftpd.
-       - Changed FTP URL parsing to use urlParse().
-       - Changed ftpget to skip RETR command if URLs ends with '/'.
-       - Changed ftpget to display README at the bottom if there are other
-         server messages.
-       - Changed ftpget to not reopen a new data connection
-         if one is already open.
-       - Fixed handling of FTP URLs with spaces (and other unsafe characters)
-       - Changed ftpget to only generate BASE HREF if the FTP URL does
-         not end with '/'.
diff --git a/INSTALL b/INSTALL
index 05ae179cf0b75ad28f687a6de2475d16e718cfe1..79869444235af0771f53408de6eb7abbf96f25dc 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,4 +1,4 @@
-To build and install the Harvest Cache, type:
+To build and install the Squid Cache, type:
 
        % ./configure --prefix=/usr/local/squid
         % make all
diff --git a/README b/README
index aaf263d3c2649b53aa102ac89d89a08ec37b589b..2d56ad94746e3d74e9b4820513a3faf49d96056a 100644 (file)
--- a/README
+++ b/README
@@ -1,10 +1,33 @@
 
-This is the Squid Internet Object Cache developed by the National
-Laboratory for Applied Networking Research (NLANR) and Internet
-volunteers.  This software is freely available for anyone to use.
-The Squid home page is http://www.nlanr.net/Squid/.
-
-This software is based on the Harvest Object Cache developed by
-the University of Colorado and the University of Southern California.
-The Harvest home page is http://harvest.cs.colorado.edu/.
+SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+--------------------------------------------------------
+
+  Squid is the result of efforts by numerous individuals from the
+  Internet community.  Development is led by Duane Wessels of the
+  National Laboratory for Applied Network Research and funded by
+  the National Science Foundation.
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+  
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+  
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Squid is derived from the ``cached'' software from the ARPA-funded
+Harvest research project.  The Harvest home page is
+http://harvest.cs.colorado.edu/.
+
+Please use our mailing lists for questions, feedback and bug fixes
+
+        squid-users@nlanr.net  # general questions, pubilc forum
+        squid-bugs@nlanr.net   # bugs and fixes
+        squid@nlanr.net                # other feedback
 
index 03c1970b6fec6b06f18f7d2f2325c77a21770d5c..e00726abb8a62b1b3d229822f91222eaa9a3c81e 100755 (executable)
--- a/configure
+++ b/configure
@@ -517,7 +517,7 @@ fi
 
 
 
-# From configure.in Revision: 1.19 
+# From configure.in Revision: 1.18.2.31 
 ac_aux_dir=
 for ac_dir in aux $srcdir/aux; do
   if test -f $ac_dir/install-sh; then
@@ -565,7 +565,6 @@ host_os=`echo $host | sed 's/^\(.*\)-\(.*\)-\(.*\)$/\3/'`
 echo "$ac_t""$host" 1>&6
 
 
-XTRA_CFLAGS=''
 CRYPT_LIB=''
 
 if test "$libexecdir" = '${exec_prefix}/libexec'; then
@@ -588,6 +587,16 @@ fi
 
 
 
+cat >> confdefs.h <<EOF
+#define CONFIG_HOST_TYPE "$host"
+EOF
+
+
+if test -z "$LDFLAGS"; then
+       LDFLAGS="-g"
+fi
+
+PREST_CFLAGS="$CFLAGS"
 
 # Extract the first word of "gcc", so it can be a program name with args.
 set dummy gcc; ac_word=$2
@@ -678,6 +687,44 @@ if test "`basename $XXXCC`" != "gcc"; then
        sleep 5
 fi
 
+if test -z "$PRESET_CFLAGS"; then
+    if test "$GCC" = "yes"; then
+        case "$host" in
+        *-sun-sunos*|*m88k*)
+           # sunos has too many warnings for this to be useful
+           # motorola too
+           ;;
+        *)
+           CFLAGS="$CFLAGS -Wall"
+           ;;
+        esac
+    fi
+
+            case "$host" in
+       *-sgi-irix*)
+               echo "Adding ANSI compile flags for IRIX..."
+               if test "$GCC" = "yes"; then
+                       CFLAGS="$CFLAGS -ansi"
+               else
+                       CFLAGS="$CFLAGS -D__STRICT_ANSI__"
+               fi
+               ;;
+       *-hp-hpux*)
+               echo "Disabling 'ranlib' for HP-UX..."
+               RANLIB=":"
+               ;;
+    esac
+fi
+
+if test -z "$PRESET_LDFLAGS"; then
+    if test "$GCC" = "yes"; then
+        case "$host" in
+        *)
+           # nothing
+           ;;
+        esac
+    fi
+fi
 
 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
 # On Suns, sometimes $CPP names a directory.
@@ -694,7 +741,7 @@ else
   # On the NeXT, cc -E runs the code through the compiler's parser,
   # not just through cpp.
   cat > conftest.$ac_ext <<EOF
-#line 698 "configure"
+#line 745 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
@@ -708,7 +755,7 @@ else
   rm -rf conftest*
   CPP="${CC-cc} -E -traditional-cpp"
   cat > conftest.$ac_ext <<EOF
-#line 712 "configure"
+#line 759 "configure"
 #include "confdefs.h"
 #include <assert.h>
 Syntax Error
@@ -1006,7 +1053,7 @@ if eval "test \"`echo '$''{'ac_cv_header_dirent_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1010 "configure"
+#line 1057 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <$ac_hdr>
@@ -1046,7 +1093,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-ldir  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1050 "configure"
+#line 1097 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1081,7 +1128,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lx  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1085 "configure"
+#line 1132 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1118,7 +1165,7 @@ else
   ac_cv_c_cross=yes
 else
 cat > conftest.$ac_ext <<EOF
-#line 1122 "configure"
+#line 1169 "configure"
 #include "confdefs.h"
 main(){return(0);}
 EOF
@@ -1140,7 +1187,7 @@ if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1144 "configure"
+#line 1191 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 #include <stdarg.h>
@@ -1162,7 +1209,7 @@ rm -f conftest*
 if test $ac_cv_header_stdc = yes; then
   # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1166 "configure"
+#line 1213 "configure"
 #include "confdefs.h"
 #include <string.h>
 EOF
@@ -1180,7 +1227,7 @@ fi
 if test $ac_cv_header_stdc = yes; then
   # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
 cat > conftest.$ac_ext <<EOF
-#line 1184 "configure"
+#line 1231 "configure"
 #include "confdefs.h"
 #include <stdlib.h>
 EOF
@@ -1201,7 +1248,7 @@ if test "$cross_compiling" = yes; then
   :
 else
 cat > conftest.$ac_ext <<EOF
-#line 1205 "configure"
+#line 1252 "configure"
 #include "confdefs.h"
 #include <ctype.h>
 #define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@@ -1236,23 +1283,45 @@ fi
 for ac_hdr in \
        alloca.h \
        arpa/inet.h \
+       arpa/nameser.h \
        bstring.h \
        config.h \
        crypt.h \
+       ctype.h \
+       errno.h \
        fcntl.h \
+       grp.h \
+       libc.h \
+       malloc.h \
        memory.h \
+       netdb.h \
        netinet/in.h \
+       netinet/tcp.h \
+       pwd.h \
+       regex.h \
+       resolv.h \
+       signal.h \
+       stdarg.h \
+       stddef.h \
+       stdio.h \
        stdlib.h \
        string.h \
        strings.h \
        sys/file.h \
+       sys/param.h \
+       sys/resource.h \
        sys/select.h\
+       sys/socket.h \
+       sys/stat.h \
+       sys/syscall.h \
        sys/time.h \
        sys/types.h \
-       sys/syscall.h \
-       unistd.h \
-       regex.h \
+       sys/un.h \
+       sys/wait.h \
        syslog.h \
+       time.h \
+       unistd.h \
+       varargs.h \
 
 do
 ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
@@ -1261,7 +1330,7 @@ if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1265 "configure"
+#line 1334 "configure"
 #include "confdefs.h"
 #include <$ac_hdr>
 EOF
@@ -1292,7 +1361,7 @@ done
 
 echo $ac_n "checking for tm->tm_gmtoff""... $ac_c" 1>&6
 cat > conftest.$ac_ext <<EOF
-#line 1296 "configure"
+#line 1365 "configure"
 #include "confdefs.h"
 #include <time.h>
 #include <sys/time.h>
@@ -1318,7 +1387,7 @@ rm -f conftest*
 
 echo $ac_n "checking for extended mallinfo""... $ac_c" 1>&6
 cat > conftest.$ac_ext <<EOF
-#line 1322 "configure"
+#line 1391 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <malloc.h>
@@ -1342,33 +1411,6 @@ fi
 rm -f conftest*
 
 
-echo $ac_n "checking if signal handlers need to be reset""... $ac_c" 1>&6
-if test "$cross_compiling" = yes; then
-  cat >> confdefs.h <<\EOF
-#define RESET_SIGNAL_HANDLER 1
-EOF
-
-echo "$ac_t""yes" 1>&6
-else
-cat > conftest.$ac_ext <<EOF
-#line 1355 "configure"
-#include "confdefs.h"
-void handle(s) int s; { return; }
-main(){signal(15,handle);kill(getpid(),15);kill(getpid(),15);exit(0);}
-EOF
-eval $ac_link
-if test -s conftest && (./conftest; exit) 2>/dev/null; then
-  echo "$ac_t""no" 1>&6
-else
-  cat >> confdefs.h <<\EOF
-#define RESET_SIGNAL_HANDLER 1
-EOF
-
-echo "$ac_t""yes" 1>&6
-fi
-fi
-rm -fr conftest*
-
 echo $ac_n "checking size of int""... $ac_c" 1>&6
 if eval "test \"`echo '$''{'ac_cv_sizeof_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1377,7 +1419,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
 cat > conftest.$ac_ext <<EOF
-#line 1381 "configure"
+#line 1423 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1411,7 +1453,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
 cat > conftest.$ac_ext <<EOF
-#line 1415 "configure"
+#line 1457 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 main()
@@ -1445,7 +1487,7 @@ if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1449 "configure"
+#line 1491 "configure"
 #include "confdefs.h"
 #include <alloca.h>
 int main() { return 0; }
@@ -1477,7 +1519,7 @@ if eval "test \"`echo '$''{'ac_cv_func_alloca'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1481 "configure"
+#line 1523 "configure"
 #include "confdefs.h"
 
 #ifdef __GNUC__
@@ -1536,7 +1578,7 @@ if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1540 "configure"
+#line 1582 "configure"
 #include "confdefs.h"
 #if defined(CRAY) && ! defined(CRAY2)
 webecray
@@ -1565,7 +1607,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1569 "configure"
+#line 1611 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1619,7 +1661,7 @@ else
   ac_cv_c_stack_direction=0
 else
 cat > conftest.$ac_ext <<EOF
-#line 1623 "configure"
+#line 1665 "configure"
 #include "confdefs.h"
 find_stack_direction ()
 {
@@ -1656,15 +1698,15 @@ EOF
 fi
 
 
-echo $ac_n "checking for -lsocket""... $ac_c" 1>&6
-ac_lib_var=`echo socket | tr '.-/+' '___p'`
+echo $ac_n "checking for -lnsl""... $ac_c" 1>&6
+ac_lib_var=`echo nsl | tr '.-/+' '___p'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
-LIBS="-lsocket  $LIBS"
+LIBS="-lnsl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1668 "configure"
+#line 1710 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1685,26 +1727,26 @@ LIBS="$ac_save_LIBS"
 fi
 if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
   echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo socket | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+    ac_tr_lib=HAVE_LIB`echo nsl | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
   cat >> confdefs.h <<EOF
 #define $ac_tr_lib 1
 EOF
 
-  LIBS="-lsocket $LIBS"
+  LIBS="-lnsl $LIBS"
 
 else
   echo "$ac_t""no" 1>&6
 fi
 
-echo $ac_n "checking for -lmalloc""... $ac_c" 1>&6
-ac_lib_var=`echo malloc | tr '.-/+' '___p'`
+echo $ac_n "checking for -lsocket""... $ac_c" 1>&6
+ac_lib_var=`echo socket | tr '.-/+' '___p'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
-LIBS="-lmalloc  $LIBS"
+LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1708 "configure"
+#line 1750 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1725,20 +1767,26 @@ LIBS="$ac_save_LIBS"
 fi
 if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
   echo "$ac_t""yes" 1>&6
-  HAVE_LIBMALLOC="yes"; LIBS="$LIBS -lmalloc"
+    ac_tr_lib=HAVE_LIB`echo socket | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+  LIBS="-lsocket $LIBS"
+
 else
   echo "$ac_t""no" 1>&6
 fi
 
-echo $ac_n "checking for -lnsl""... $ac_c" 1>&6
-ac_lib_var=`echo nsl | tr '.-/+' '___p'`
+echo $ac_n "checking for -lmalloc""... $ac_c" 1>&6
+ac_lib_var=`echo malloc | tr '.-/+' '___p'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_save_LIBS="$LIBS"
-LIBS="-lnsl  $LIBS"
+LIBS="-lmalloc  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1742 "configure"
+#line 1790 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1759,13 +1807,7 @@ LIBS="$ac_save_LIBS"
 fi
 if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
   echo "$ac_t""yes" 1>&6
-    ac_tr_lib=HAVE_LIB`echo nsl | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
-  cat >> confdefs.h <<EOF
-#define $ac_tr_lib 1
-EOF
-
-  LIBS="-lnsl $LIBS"
-
+  HAVE_LIBMALLOC="yes"; LIBS="$LIBS -lmalloc"
 else
   echo "$ac_t""no" 1>&6
 fi
@@ -1778,7 +1820,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lresolv  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1782 "configure"
+#line 1824 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1818,7 +1860,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lbsd  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1822 "configure"
+#line 1864 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1859,7 +1901,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-l44bsd  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1863 "configure"
+#line 1905 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1893,7 +1935,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lresolv  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1897 "configure"
+#line 1939 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1928,7 +1970,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lcrypt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1932 "configure"
+#line 1974 "configure"
 #include "confdefs.h"
 
 int main() { return 0; }
@@ -1968,22 +2010,36 @@ case "$host" in
                echo "Removing -lnsl for IRIX..."
                LIBS=`echo $LIBS | sed -e s/-lnsl//`
                ;;
+       *m88k*)
+               CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_"
+               ;;
+
 esac
 
 for ac_func in \
+       bcopy \
        getdtablesize \
+       getrusage \
+       lrand48 \
        mallinfo \
        mallopt \
+       memmove \
        regcomp \
        regexec \
        regfree \
+       res_init \
        seteuid \
+       setpgrp \
        setresuid \
        setrlimit \
+       setsid \
+       sigaction \
+       socketpair \
+       srand48 \
        strdup \
-       strerror \
        sysconf \
        syslog \
+       tempnam \
        timegm \
 
 do
@@ -1992,7 +2048,7 @@ if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1996 "configure"
+#line 2052 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2042,10 +2098,11 @@ if test "$cross_compiling" = yes; then
   SQUID_FD_SETSIZE=256
 else
 cat > conftest.$ac_ext <<EOF
-#line 2046 "configure"
+#line 2102 "configure"
 #include "confdefs.h"
 
 #include <unistd.h>
+#include <sys/time.h>  /* needed on FreeBSD */
 #include <sys/param.h>
 #include <sys/resource.h>
 main() {
@@ -2104,6 +2161,174 @@ cat >> confdefs.h <<EOF
 EOF
 
 
+echo $ac_n "checking Default UDP send buffer size""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+  SQUID_UDP_SO_SNDBUF=8192
+else
+cat > conftest.$ac_ext <<EOF
+#line 2170 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
+       if (val<=0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  SQUID_UDP_SO_SNDBUF=`cat conftestval`
+else
+  SQUID_UDP_SO_SNDBUF=8192
+fi
+fi
+rm -fr conftest*
+echo "$ac_t""$SQUID_UDP_SO_SNDBUF" 1>&6
+cat >> confdefs.h <<EOF
+#define SQUID_UDP_SO_SNDBUF $SQUID_UDP_SO_SNDBUF
+EOF
+
+
+echo $ac_n "checking Default UDP receive buffer size""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+  SQUID_UDP_SO_RCVBUF=8192
+else
+cat > conftest.$ac_ext <<EOF
+#line 2206 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  SQUID_UDP_SO_RCVBUF=`cat conftestval`
+else
+  SQUID_UDP_SO_RCVBUF=8192
+fi
+fi
+rm -fr conftest*
+echo "$ac_t""$SQUID_UDP_SO_RCVBUF" 1>&6
+cat >> confdefs.h <<EOF
+#define SQUID_UDP_SO_RCVBUF $SQUID_UDP_SO_RCVBUF
+EOF
+
+
+echo $ac_n "checking Default TCP send buffer size""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+  SQUID_TCP_SO_SNDBUF=8192
+else
+cat > conftest.$ac_ext <<EOF
+#line 2242 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  SQUID_TCP_SO_SNDBUF=`cat conftestval`
+else
+  SQUID_TCP_SO_SNDBUF=8192
+fi
+fi
+rm -fr conftest*
+echo "$ac_t""$SQUID_TCP_SO_SNDBUF" 1>&6
+cat >> confdefs.h <<EOF
+#define SQUID_TCP_SO_SNDBUF $SQUID_TCP_SO_SNDBUF
+EOF
+
+
+echo $ac_n "checking Default TCP receive buffer size""... $ac_c" 1>&6
+if test "$cross_compiling" = yes; then
+  SQUID_TCP_SO_RCVBUF=8192
+else
+cat > conftest.$ac_ext <<EOF
+#line 2278 "configure"
+#include "confdefs.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+  SQUID_TCP_SO_RCVBUF=`cat conftestval`
+else
+  SQUID_TCP_SO_RCVBUF=8192
+fi
+fi
+rm -fr conftest*
+echo "$ac_t""$SQUID_TCP_SO_RCVBUF" 1>&6
+cat >> confdefs.h <<EOF
+#define SQUID_TCP_SO_RCVBUF $SQUID_TCP_SO_RCVBUF
+EOF
+
+
+echo $ac_n "checking if sys_errlist is already defined""... $ac_c" 1>&6
+cat > conftest.$ac_ext <<EOF
+#line 2311 "configure"
+#include "confdefs.h"
+#include <stdio.h>
+int main() { return 0; }
+int t() {
+char *s = sys_errlist[0];
+; return 0; }
+EOF
+if eval $ac_compile; then
+  rm -rf conftest*
+  echo "$ac_t""yes" 1>&6
+else
+  rm -rf conftest*
+  echo "$ac_t""no" 1>&6
+cat >> confdefs.h <<\EOF
+#define NEED_SYS_ERRLIST 1
+EOF
+
+fi
+rm -f conftest*
+
+
 XTRA_OBJS=''
 if test "$HAVE_LIBMALLOC" = "yes" ; then
        if test -r /usr/lib/debug/malloc.o ; then
@@ -2119,43 +2344,6 @@ XTRA_LIBS="$LIBS"
 LIBS=''
 
 
-if test -z "$STD_CFLAGS"; then
-    STD_CFLAGS="-g"
-    XXXCC=`echo $CC | awk '{print $1}'`
-    if test "`basename $XXXCC`" = "gcc"; then
-       case "$host" in
-       *-sun-sunos*)
-               # sunos has too many warnings for this to be useful
-               ;;
-       *)
-               STD_CFLAGS="$STD_CFLAGS -Wall"
-               ;;
-       esac
-    fi
-fi
-
-
-if test -z "$STD_LDFLAGS"; then
-    STD_LDFLAGS="-g"
-fi
-
-
-case "$host" in
-       *-sgi-irix*)
-               echo "Adding ANSI compile flags for IRIX..."
-               XXXCC=`echo $CC | awk '{print $1}'`
-               if test "`basename $XXXCC`" = "gcc"; then
-                       XTRA_CFLAGS="$XTRA_CFLAGS -ansi"
-               else
-                       XTRA_CFLAGS="$XTRA_CFLAGS -D__STRICT_ANSI__"
-               fi
-               ;;
-       *-hp-hpux*)
-               echo "Disabling 'ranlib' for HP-UX..."
-               RANLIB=":"
-               ;;
-esac
-
 
 rm -f core 
 
@@ -2290,7 +2478,6 @@ s%@host_alias@%$host_alias%g
 s%@host_cpu@%$host_cpu%g
 s%@host_vendor@%$host_vendor%g
 s%@host_os@%$host_os%g
-s%@XTRA_CFLAGS@%$XTRA_CFLAGS%g
 s%@CACHE_HTTP_PORT@%$CACHE_HTTP_PORT%g
 s%@CACHE_ICP_PORT@%$CACHE_ICP_PORT%g
 s%@CACHE_FTP_PORT@%$CACHE_FTP_PORT%g
@@ -2309,8 +2496,6 @@ s%@ALLOCA@%$ALLOCA%g
 s%@CRYPT_LIB@%$CRYPT_LIB%g
 s%@XTRA_OBJS@%$XTRA_OBJS%g
 s%@XTRA_LIBS@%$XTRA_LIBS%g
-s%@STD_CFLAGS@%$STD_CFLAGS%g
-s%@STD_LDFLAGS@%$STD_LDFLAGS%g
 
 CEOF
 EOF
index fb6d342ae96d8d03633234577703bdf9112c3b9a..23d12f526ffd25ad3ecbad0937b6fbb8896d8331 100644 (file)
@@ -3,19 +3,18 @@ dnl  Configuration input file for Squid
 dnl
 dnl  Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9)
 dnl
-dnl  $Id: configure.in,v 1.20 1996/05/03 22:56:16 wessels Exp $
+dnl  $Id: configure.in,v 1.21 1996/07/09 03:41:04 wessels Exp $
 dnl
 dnl
 dnl
 AC_INIT(src/main.c)
 AC_CONFIG_HEADER(include/autoconf.h)
-AC_REVISION($Revision: 1.20 $)dnl
+AC_REVISION($Revision: 1.21 $)dnl
 AC_PREFIX_DEFAULT(/usr/local/squid)
 AC_CONFIG_AUX_DIR(aux)
 
 AC_CANONICAL_HOST
 
-XTRA_CFLAGS=''
 CRYPT_LIB=''
 
 dnl use directory structure of cached as default (hack)
@@ -36,11 +35,19 @@ if test -z "$CACHE_FTP_PORT"; then
 fi
 
 dnl Subsitutions
-AC_SUBST(XTRA_CFLAGS)
 AC_SUBST(CACHE_HTTP_PORT)
 AC_SUBST(CACHE_ICP_PORT)
 AC_SUBST(CACHE_FTP_PORT)
 
+AC_DEFINE_UNQUOTED(CONFIG_HOST_TYPE, "$host")
+
+dnl Set default LDFLAGS
+if test -z "$LDFLAGS"; then
+       LDFLAGS="-g"
+fi
+
+PREST_CFLAGS="$CFLAGS"
+
 dnl Check for GNU cc
 AC_PROG_CC
 
@@ -58,6 +65,48 @@ if test "`basename $XXXCC`" != "gcc"; then
        sleep 5
 fi
 
+dnl Set Default CFLAGS
+if test -z "$PRESET_CFLAGS"; then
+    if test "$GCC" = "yes"; then
+        case "$host" in
+        *-sun-sunos*|*m88k*)
+           # sunos has too many warnings for this to be useful
+           # motorola too
+           ;;
+        *)
+           CFLAGS="$CFLAGS -Wall"
+           ;;
+        esac
+    fi
+
+    dnl Check if ANSI compile options are needed
+    dnl
+    case "$host" in
+       *-sgi-irix*)
+               echo "Adding ANSI compile flags for IRIX..."
+               if test "$GCC" = "yes"; then
+                       [CFLAGS="$CFLAGS -ansi"]
+               else
+                       [CFLAGS="$CFLAGS -D__STRICT_ANSI__"]
+               fi
+               ;;
+       *-hp-hpux*)
+               echo "Disabling 'ranlib' for HP-UX..."
+               RANLIB=":"
+               ;;
+    esac
+fi
+
+dnl Set LDFLAGS
+if test -z "$PRESET_LDFLAGS"; then
+    if test "$GCC" = "yes"; then
+        case "$host" in
+        *)
+           # nothing
+           ;;
+        esac
+    fi
+fi
 
 dnl Check for programs
 AC_PROG_CPP
@@ -79,23 +128,45 @@ AC_HEADER_STDC
 AC_CHECK_HEADERS( \
        alloca.h \
        arpa/inet.h \
+       arpa/nameser.h \
        bstring.h \
        config.h \
        crypt.h \
+       ctype.h \
+       errno.h \
        fcntl.h \
+       grp.h \
+       libc.h \
+       malloc.h \
        memory.h \
+       netdb.h \
        netinet/in.h \
+       netinet/tcp.h \
+       pwd.h \
+       regex.h \
+       resolv.h \
+       signal.h \
+       stdarg.h \
+       stddef.h \
+       stdio.h \
        stdlib.h \
        string.h \
        strings.h \
        sys/file.h \
+       sys/param.h \
+       sys/resource.h \
        sys/select.h\
+       sys/socket.h \
+       sys/stat.h \
+       sys/syscall.h \
        sys/time.h \
        sys/types.h \
-       sys/syscall.h \
-       unistd.h \
-       regex.h \
+       sys/un.h \
+       sys/wait.h \
        syslog.h \
+       time.h \
+       unistd.h \
+       varargs.h \
 )
 
 AC_MSG_CHECKING(for tm->tm_gmtoff)
@@ -116,16 +187,6 @@ foo.mxfast = 0;],
 AC_MSG_RESULT(yes)],
 AC_MSG_RESULT(no))
 
-AC_MSG_CHECKING(if signal handlers need to be reset)
-AC_TRY_RUN([void handle(s) int s; { return; }
-main(){signal(15,handle);kill(getpid(),15);kill(getpid(),15);exit(0);}],
-AC_MSG_RESULT(no),
-[AC_DEFINE(RESET_SIGNAL_HANDLER)
-AC_MSG_RESULT(yes)],
-dnl default
-[AC_DEFINE(RESET_SIGNAL_HANDLER)
-AC_MSG_RESULT(yes)],)
-
 dnl Check for typedefs
 AC_CHECK_SIZEOF(int)
 AC_CHECK_SIZEOF(long)
@@ -134,9 +195,9 @@ dnl Check for special functions
 AC_FUNC_ALLOCA
 
 dnl Check for needed libraries
+AC_CHECK_LIB(nsl, main)
 AC_CHECK_LIB(socket, main)
 AC_CHECK_LIB(malloc, main, [HAVE_LIBMALLOC="yes"; LIBS="$LIBS -lmalloc"])
-AC_CHECK_LIB(nsl, main)
 AC_CHECK_LIB(resolv, main)
 AC_CHECK_LIB(bsd, main)
 
@@ -165,29 +226,44 @@ case "$host" in
                echo "Removing -lnsl for IRIX..."
                LIBS=`echo $LIBS | sed -e s/-lnsl//`
                ;;
+       *m88k*)
+               CFLAGS="$CFLAGS -D_SQUID_MOTOROLA_"
+               ;;
+
 esac
 
 dnl Check for library functions
 AC_CHECK_FUNCS(\
+       bcopy \
        getdtablesize \
+       getrusage \
+       lrand48 \
        mallinfo \
        mallopt \
+       memmove \
        regcomp \
        regexec \
        regfree \
+       res_init \
        seteuid \
+       setpgrp \
        setresuid \
        setrlimit \
+       setsid \
+       sigaction \
+       socketpair \
+       srand48 \
        strdup \
-       strerror \
        sysconf \
        syslog \
+       tempnam \
        timegm \
 )
 
 AC_MSG_CHECKING(Maximum number of filedescriptors we can open)
 AC_TRY_RUN([
 #include <unistd.h>
+#include <sys/time.h>  /* needed on FreeBSD */
 #include <sys/param.h>
 #include <sys/resource.h>
 main() {
@@ -237,6 +313,97 @@ SQUID_FD_SETSIZE=256)
 AC_MSG_RESULT($SQUID_FD_SETSIZE)
 AC_DEFINE_UNQUOTED(SQUID_FD_SETSIZE, $SQUID_FD_SETSIZE)
 
+AC_MSG_CHECKING(Default UDP send buffer size)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
+       if (val<=0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+],
+SQUID_UDP_SO_SNDBUF=`cat conftestval`,
+SQUID_UDP_SO_SNDBUF=8192,
+SQUID_UDP_SO_SNDBUF=8192)
+AC_MSG_RESULT($SQUID_UDP_SO_SNDBUF)
+AC_DEFINE_UNQUOTED(SQUID_UDP_SO_SNDBUF, $SQUID_UDP_SO_SNDBUF)
+
+AC_MSG_CHECKING(Default UDP receive buffer size)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+],
+SQUID_UDP_SO_RCVBUF=`cat conftestval`,
+SQUID_UDP_SO_RCVBUF=8192,
+SQUID_UDP_SO_RCVBUF=8192)
+AC_MSG_RESULT($SQUID_UDP_SO_RCVBUF)
+AC_DEFINE_UNQUOTED(SQUID_UDP_SO_RCVBUF, $SQUID_UDP_SO_RCVBUF)
+
+AC_MSG_CHECKING(Default TCP send buffer size)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+],
+SQUID_TCP_SO_SNDBUF=`cat conftestval`,
+SQUID_TCP_SO_SNDBUF=8192,
+SQUID_TCP_SO_SNDBUF=8192)
+AC_MSG_RESULT($SQUID_TCP_SO_SNDBUF)
+AC_DEFINE_UNQUOTED(SQUID_TCP_SO_SNDBUF, $SQUID_TCP_SO_SNDBUF)
+
+AC_MSG_CHECKING(Default TCP receive buffer size)
+AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+main ()
+{
+        int fd,val=0,len=sizeof(int);
+       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) exit(1);
+        if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &val, &len) < 0) exit(1);
+       if (val <= 0) exit(1);
+        fprintf (fopen("conftestval", "w"), "%d\n", val);
+       exit(0);
+}
+],
+SQUID_TCP_SO_RCVBUF=`cat conftestval`,
+SQUID_TCP_SO_RCVBUF=8192,
+SQUID_TCP_SO_RCVBUF=8192)
+AC_MSG_RESULT($SQUID_TCP_SO_RCVBUF)
+AC_DEFINE_UNQUOTED(SQUID_TCP_SO_RCVBUF, $SQUID_TCP_SO_RCVBUF)
+
+AC_MSG_CHECKING(if sys_errlist[] is already defined)
+AC_TRY_COMPILE([#include <stdio.h>],
+[char *s = sys_errlist[0];],
+AC_MSG_RESULT(yes),
+[AC_MSG_RESULT(no)
+AC_DEFINE(NEED_SYS_ERRLIST)])
+
 dnl Need the debugging version of malloc if available
 XTRA_OBJS=''
 if test "$HAVE_LIBMALLOC" = "yes" ; then
@@ -253,47 +420,6 @@ XTRA_LIBS="$LIBS"
 LIBS=''
 AC_SUBST(XTRA_LIBS)
 
-dnl Set STD_CFLAGS
-if test -z "$STD_CFLAGS"; then
-    STD_CFLAGS="-g"
-    XXXCC=`echo $CC | awk '{print $1}'`
-    if test "`basename $XXXCC`" = "gcc"; then
-       case "$host" in
-       *-sun-sunos*)
-               # sunos has too many warnings for this to be useful
-               ;;
-       *)
-               STD_CFLAGS="$STD_CFLAGS -Wall"
-               ;;
-       esac
-    fi
-fi
-AC_SUBST(STD_CFLAGS)
-
-dnl Set STD_LDFLAGS
-if test -z "$STD_LDFLAGS"; then
-    STD_LDFLAGS="-g"
-fi
-AC_SUBST(STD_LDFLAGS)
-
-dnl Last minute system specific modifications
-dnl
-case "$host" in
-       *-sgi-irix*)
-               echo "Adding ANSI compile flags for IRIX..."
-               XXXCC=`echo $CC | awk '{print $1}'`
-               if test "`basename $XXXCC`" = "gcc"; then
-                       [XTRA_CFLAGS="$XTRA_CFLAGS -ansi"]
-               else
-                       [XTRA_CFLAGS="$XTRA_CFLAGS -D__STRICT_ANSI__"]
-               fi
-               ;;
-       *-hp-hpux*)
-               echo "Disabling 'ranlib' for HP-UX..."
-               RANLIB=":"
-               ;;
-esac
-
 
 dnl Clean up after OSF/1 core dump bug
 rm -f core 
diff --git a/doc/HTTP-codes.txt b/doc/HTTP-codes.txt
new file mode 100644 (file)
index 0000000..887d69e
--- /dev/null
@@ -0,0 +1,50 @@
+Caching  Code
+       Successful 2xx
+c        200 OK
+         201 Created
+         202 Accepted
+c        203 Non-Authoriative Information *
+E        204 No Content
+         205 Reset Content *
+         206 Partial Content *
+       Redirection 3xx
+C        300 Multiple Choices
+C        301 Moved Permanently
+t        302 Moved Temporarily
+-        303 See Other *
+-        304 Not Modified
+E        305 Use Proxy (proxy redirect) *
+        Client Error 4xx
+E        400 Bad Request
+-        401 Unauthorized
+         402 Payment Required *
+E        403 Forbidden
+E        404 Not Found
+E        405 Method Not Allowed *
+         406 Not Acceptable *
+-        407 Proxy Authentication Required *
+         408 Request Timeout *
+         409 Confict *
+C        410 Gone *
+         411 Length Required *
+         412 Precondition Failed *
+         413 Request Entity To Large *
+E        414 Request-URI Too Long *
+         415 Unsupported Media Type
+        Server Error 5xx
+E        500 Internal Server Error
+E        501 Not Implemented
+E        502 Bad Gateway
+E        503 Service Unavailable
+E        504 Gateway Timeout *
+         505 HTTP Version Not Supported *
+
+Notes:
+* HTTP 1.1
+c Cached unless a query response without expiry information
+C Cached
+E Negatively cached if no expiry headers.
+t Cached only if expiry information
+- Not cached
+
+Unless other said, the response code is not cached.
index 3b8caf10d422ac0bb6ef439cd9608cc1dac258da..8f9bd102723ddbe4f90ce70ce9e188c994510281 100644 (file)
 /* Define if struct mallinfo has mxfast member */
 #undef HAVE_EXT_MALLINFO
 
-/* Define if signal handlers must be reset after invocation */
-#undef RESET_SIGNAL_HANDLER
-
 /* Maximum number of open filedescriptors */
 #undef SQUID_FD_SETSIZE
 
+/* UDP send buffer size */
+#undef SQUID_UDP_SO_SNDBUF
+
+/* UDP receive buffer size */
+#undef SQUID_UDP_SO_RCVBUF
+
+/* TCP send buffer size */
+#undef SQUID_TCP_SO_SNDBUF
+
+/* TCP receive buffer size */
+#undef SQUID_TCP_SO_RCVBUF
+
+/* Host type from configure */
+#undef CONFIG_HOST_TYPE
+
+/* If we need to declare sys_errlist[] as external */
+#undef NEED_SYS_ERRLIST
+
 /* The number of bytes in a int.  */
 #undef SIZEOF_INT
 
 /* The number of bytes in a long.  */
 #undef SIZEOF_LONG
 
+/* Define if you have the bcopy function.  */
+#undef HAVE_BCOPY
+
 /* Define if you have the getdtablesize function.  */
 #undef HAVE_GETDTABLESIZE
 
+/* Define if you have the getrusage function.  */
+#undef HAVE_GETRUSAGE
+
+/* Define if you have the lrand48 function.  */
+#undef HAVE_LRAND48
+
 /* Define if you have the mallinfo function.  */
 #undef HAVE_MALLINFO
 
 /* Define if you have the mallopt function.  */
 #undef HAVE_MALLOPT
 
+/* Define if you have the memmove function.  */
+#undef HAVE_MEMMOVE
+
 /* Define if you have the regcomp function.  */
 #undef HAVE_REGCOMP
 
 /* Define if you have the regfree function.  */
 #undef HAVE_REGFREE
 
+/* Define if you have the res_init function.  */
+#undef HAVE_RES_INIT
+
 /* Define if you have the seteuid function.  */
 #undef HAVE_SETEUID
 
+/* Define if you have the setpgrp function.  */
+#undef HAVE_SETPGRP
+
 /* Define if you have the setresuid function.  */
 #undef HAVE_SETRESUID
 
 /* Define if you have the setrlimit function.  */
 #undef HAVE_SETRLIMIT
 
+/* Define if you have the setsid function.  */
+#undef HAVE_SETSID
+
+/* Define if you have the sigaction function.  */
+#undef HAVE_SIGACTION
+
+/* Define if you have the socketpair function.  */
+#undef HAVE_SOCKETPAIR
+
+/* Define if you have the srand48 function.  */
+#undef HAVE_SRAND48
+
 /* Define if you have the strdup function.  */
 #undef HAVE_STRDUP
 
-/* Define if you have the strerror function.  */
-#undef HAVE_STRERROR
-
 /* Define if you have the sysconf function.  */
 #undef HAVE_SYSCONF
 
 /* Define if you have the syslog function.  */
 #undef HAVE_SYSLOG
 
+/* Define if you have the tempnam function.  */
+#undef HAVE_TEMPNAM
+
 /* Define if you have the timegm function.  */
 #undef HAVE_TIMEGM
 
 /* Define if you have the <arpa/inet.h> header file.  */
 #undef HAVE_ARPA_INET_H
 
+/* Define if you have the <arpa/nameser.h> header file.  */
+#undef HAVE_ARPA_NAMESER_H
+
 /* Define if you have the <bstring.h> header file.  */
 #undef HAVE_BSTRING_H
 
 /* Define if you have the <crypt.h> header file.  */
 #undef HAVE_CRYPT_H
 
+/* Define if you have the <ctype.h> header file.  */
+#undef HAVE_CTYPE_H
+
 /* Define if you have the <dirent.h> header file.  */
 #undef HAVE_DIRENT_H
 
+/* Define if you have the <errno.h> header file.  */
+#undef HAVE_ERRNO_H
+
 /* Define if you have the <fcntl.h> header file.  */
 #undef HAVE_FCNTL_H
 
+/* Define if you have the <grp.h> header file.  */
+#undef HAVE_GRP_H
+
+/* Define if you have the <libc.h> header file.  */
+#undef HAVE_LIBC_H
+
+/* Define if you have the <malloc.h> header file.  */
+#undef HAVE_MALLOC_H
+
 /* Define if you have the <memory.h> header file.  */
 #undef HAVE_MEMORY_H
 
 /* Define if you have the <ndir.h> header file.  */
 #undef HAVE_NDIR_H
 
+/* Define if you have the <netdb.h> header file.  */
+#undef HAVE_NETDB_H
+
 /* Define if you have the <netinet/in.h> header file.  */
 #undef HAVE_NETINET_IN_H
 
+/* Define if you have the <netinet/tcp.h> header file.  */
+#undef HAVE_NETINET_TCP_H
+
+/* Define if you have the <pwd.h> header file.  */
+#undef HAVE_PWD_H
+
 /* Define if you have the <regex.h> header file.  */
 #undef HAVE_REGEX_H
 
+/* Define if you have the <resolv.h> header file.  */
+#undef HAVE_RESOLV_H
+
+/* Define if you have the <signal.h> header file.  */
+#undef HAVE_SIGNAL_H
+
+/* Define if you have the <stdarg.h> header file.  */
+#undef HAVE_STDARG_H
+
+/* Define if you have the <stddef.h> header file.  */
+#undef HAVE_STDDEF_H
+
+/* Define if you have the <stdio.h> header file.  */
+#undef HAVE_STDIO_H
+
 /* Define if you have the <stdlib.h> header file.  */
 #undef HAVE_STDLIB_H
 
 /* Define if you have the <sys/ndir.h> header file.  */
 #undef HAVE_SYS_NDIR_H
 
+/* Define if you have the <sys/param.h> header file.  */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/resource.h> header file.  */
+#undef HAVE_SYS_RESOURCE_H
+
 /* Define if you have the <sys/select.h> header file.  */
 #undef HAVE_SYS_SELECT_H
 
+/* Define if you have the <sys/socket.h> header file.  */
+#undef HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/stat.h> header file.  */
+#undef HAVE_SYS_STAT_H
+
 /* Define if you have the <sys/syscall.h> header file.  */
 #undef HAVE_SYS_SYSCALL_H
 
 /* Define if you have the <sys/types.h> header file.  */
 #undef HAVE_SYS_TYPES_H
 
+/* Define if you have the <sys/un.h> header file.  */
+#undef HAVE_SYS_UN_H
+
+/* Define if you have the <sys/wait.h> header file.  */
+#undef HAVE_SYS_WAIT_H
+
 /* Define if you have the <syslog.h> header file.  */
 #undef HAVE_SYSLOG_H
 
+/* Define if you have the <time.h> header file.  */
+#undef HAVE_TIME_H
+
 /* Define if you have the <unistd.h> header file.  */
 #undef HAVE_UNISTD_H
 
+/* Define if you have the <varargs.h> header file.  */
+#undef HAVE_VARARGS_H
+
 /* Define if you have the bsd library (-lbsd).  */
 #undef HAVE_LIBBSD
 
diff --git a/include/tempnam.h b/include/tempnam.h
new file mode 100644 (file)
index 0000000..311a4b4
--- /dev/null
@@ -0,0 +1,21 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#ifndef _TEMPNAM_H
+#define _TEMPNAM_H
+extern char *tempnam (const char *, const char *);
+#endif /* _TEMPNAM_H */
index fe339ef84d8584dff2f3a91727782d28e84bbc7b..3df79042c72db57b0661e5939f282258c61c2fd9 100644 (file)
@@ -1,7 +1,106 @@
 /*
- * $Id: util.h,v 1.6 1996/04/14 03:34:28 wessels Exp $
+ * $Id: util.h,v 1.7 1996/07/09 03:41:08 wessels Exp $
+ *
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
 
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 #ifndef _UTIL_H_
 #define _UTIL_H_
 
 
 #if !defined(SQUIDHOSTNAMELEN)
 #include <sys/param.h>
+#ifndef _SQUID_NETDB_H_                /* need protection on NEXTSTEP */
+#define _SQUID_NETDB_H_
 #include <netdb.h>
+#endif
 #if !defined(MAXHOSTNAMELEN) || (MAXHOSTNAMELEN < 128)
 #define SQUIDHOSTNAMELEN 128
 #else
 #ifndef _PARAMS
 #if defined(__STDC__) || defined(__cplusplus) || defined(__STRICT_ANSI__)
 #define _PARAMS(ARGS) ARGS
-#else /* Traditional C */     
-#define _PARAMS(ARGS) ()      
-#endif /* __STDC__ */              
-#endif /* _PARAMS */   
+#else /* Traditional C */
+#define _PARAMS(ARGS) ()
+#endif /* __STDC__ */
+#endif /* _PARAMS */
 
-#ifdef NO_STRDUP
-char *strdup _PARAMS((char *));                        /* Duplicate a string */
+#if !HAVE_STRDUP
+extern char *strdup _PARAMS((char *));
 #endif
-char *xstrdup _PARAMS((char *));               /* Duplicate a string */
+extern char *xstrdup _PARAMS((char *));                /* Duplicate a string */
 
 /* from xmalloc.c */
-void *xmalloc _PARAMS((size_t));               /* Wrapper for malloc(3) */
+void *xmalloc _PARAMS((size_t));       /* Wrapper for malloc(3) */
 void *xrealloc _PARAMS((void *, size_t));      /* Wrapper for realloc(3) */
-void *xcalloc _PARAMS((int, size_t));          /* Wrapper for calloc(3) */
-void xfree _PARAMS((void *));                  /* Wrapper for free(3) */
-void xxfree _PARAMS((void *));                 /* Wrapper for free(3) */
-char *xstrdup _PARAMS ((char *));
-char *xstrerror _PARAMS(());
-
-char *getfullhostname _PARAMS(());
+void *xcalloc _PARAMS((int, size_t));  /* Wrapper for calloc(3) */
+void xfree _PARAMS((void *));  /* Wrapper for free(3) */
+void xxfree _PARAMS((void *)); /* Wrapper for free(3) */
+char *xstrdup _PARAMS((char *));
+char *xstrerror _PARAMS((void));
+char *getfullhostname _PARAMS((void));
+void xmemcpy _PARAMS((void *, void*, int));
+
+#if XMALLOC_STATISTICS
+void malloc_statistics _PARAMS((void (*)(int, int, void *), void *));
+#endif
 
 /* from debug.c */
 #ifndef MAX_DEBUG_LEVELS
@@ -51,7 +157,7 @@ char *getfullhostname _PARAMS(());
 #ifndef MAIN
 extern int Harvest_do_debug;
 extern int Harvest_debug_levels[];
-#endif /* MAIN */
+#endif /* MAIN */
 
 #undef debug_ok_fast
 #if USE_NO_DEBUGGING
@@ -74,48 +180,49 @@ extern int Harvest_debug_levels[];
         {if (debug_ok_fast((section),(level))) {Log X;}}
 #endif
 
-void debug_reset _PARAMS((void));
+void debug_flag _PARAMS((char *));
+#ifdef UNUSED_CODE
 void debug_enable _PARAMS((int, int));
 void debug_disable _PARAMS((int));
-void debug_flag _PARAMS((char *));
-int  debug_ok _PARAMS((int, int));
+void debug_reset _PARAMS((void));
+int debug_ok _PARAMS((int, int));
+#endif /* UNUSED_CODE */
 
 #define HOST_CACHE_TTL 3600
 
 typedef struct _host {
-    char        key[SQUIDHOSTNAMELEN];    /* www.bar.com */
-    char        fqdn[SQUIDHOSTNAMELEN];   /* real.bar.com */
-    char        dotaddr[16];            /* 128.138.213.10 */
-    char        ipaddr[4];
-    time_t      last_t;                 /* last access of this info */
-    int         n;                      /* # of requests for this host */
-    int         addrlen;                /* length of 'ipaddr', always 4 */
+    char key[SQUIDHOSTNAMELEN];        /* www.bar.com */
+    char fqdn[SQUIDHOSTNAMELEN];       /* real.bar.com */
+    char dotaddr[16];          /* 128.138.213.10 */
+    char ipaddr[4];
+    time_t last_t;             /* last access of this info */
+    int n;                     /* # of requests for this host */
+    int addrlen;               /* length of 'ipaddr', always 4 */
     struct _host *next;
 } Host;
 
-extern Host   *thisHost;
-
-void   host_cache_init _PARAMS((void));
-Host  *get_host _PARAMS((char *hostname));
-int   delete_host _PARAMS((Host *h));
-int   expire_host_cache _PARAMS((time_t timeout));
-void  dump_host_cache _PARAMS((int, int));
-
+extern Host *thisHost;
 
+Host *get_host _PARAMS((char *hostname));
+int delete_host _PARAMS((Host * h));
+int expire_host_cache _PARAMS((time_t timeout));
+#ifdef UNUSED_CODE
+void dump_host_cache _PARAMS((int, int));
+#endif
 
 char *mkhttpdlogtime _PARAMS((time_t *));
 extern char *mkrfc850 _PARAMS((time_t *));
 extern time_t parse_rfc850 _PARAMS((char *str));
-extern void init_log3 _PARAMS((char *pn, FILE *a, FILE *b));
+extern void init_log3 _PARAMS((char *pn, FILE * a, FILE * b));
 extern void debug_init();
 extern void log_errno2 _PARAMS((char *, int, char *));
 
 #if defined(__STRICT_ANSI__)
-extern void Log _PARAMS((char *, ...));
-extern void errorlog  _PARAMS((char *, ...));
+extern void Log _PARAMS((char *,...));
+extern void errorlog _PARAMS((char *,...));
 #else
-extern void Log ();
-extern void errorlog ();
+extern void Log();
+extern void errorlog();
 #endif /* __STRICT_ANSI__ */
 
 
index cc5e5d9a7d89bf02a0d90e44528c5374abe2ab65..47a580353c800e3aa3991ed6a2f5108f11bc7407 100644 (file)
@@ -1,4 +1,3 @@
-#include "autoconf.h"  /* get the #defines from GNU autoconf */
 /* Extended regular expression matching and search library,
    version 0.12.
    (Implements POSIX draft P10003.2/D11.2, except for
 
 #define _GNU_SOURCE
 
-/* We need this for `regex.h', and perhaps for the Emacs include files.  */
-#include <sys/types.h>
-
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #if !HAVE_ALLOCA
 #define REGEX_MALLOC 1
@@ -2497,10 +2491,10 @@ typedef struct
   DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);                      \
                                                                        \
   /* Restore register info.  */                                                \
-  high_reg = (unsigned) POP_FAILURE_ITEM ();                           \
+  high_reg = (unsigned long) POP_FAILURE_ITEM ();                      \
   DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);          \
                                                                        \
-  low_reg = (unsigned) POP_FAILURE_ITEM ();                            \
+  low_reg = (unsigned long) POP_FAILURE_ITEM ();                       \
   DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);           \
                                                                        \
   for (this_reg = high_reg; this_reg >= low_reg; this_reg--)           \
@@ -3213,8 +3207,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
   unsigned num_regs = bufp->re_nsub + 1;
   
   /* The currently active registers.  */
-  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
-  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+  unsigned long lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+  unsigned long highest_active_reg = NO_HIGHEST_ACTIVE_REG;
 
   /* Information on the contents of registers. These are pointers into
      the input strings; they record just what was matched (on this
@@ -3223,14 +3217,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
      matching and the regnum-th regend points to right after where we
      stopped matching the regnum-th subexpression.  (The zeroth register
      keeps track of what the whole pattern matches.)  */
-  const char **regstart, **regend;
+  const char **regstart = NULL, **regend = NULL;
 
   /* If a group that's operated upon by a repetition operator fails to
      match anything, then the register for its start will need to be
      restored because it will have been set to wherever in the string we
      are when we last see its open-group operator.  Similarly for a
      register's end.  */
-  const char **old_regstart, **old_regend;
+  const char **old_regstart = NULL, **old_regend = NULL;
 
   /* The is_active field of reg_info helps us keep track of which (possibly
      nested) subexpressions we are currently in. The matched_something
@@ -3238,14 +3232,14 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
      matched any of the pattern so far this time through the reg_num-th
      subexpression.  These two fields get reset each time through any
      loop their register is in.  */
-  register_info_type *reg_info; 
+  register_info_type *reg_info = NULL
 
   /* The following record the register info as found in the above
      variables when we find a match better than any we've seen before. 
      This happens as we backtrack through the failure points, which in
      turn happens only if we have not yet matched the entire string. */
   unsigned best_regs_set = false;
-  const char **best_regstart, **best_regend;
+  const char **best_regstart = NULL, **best_regend = NULL;
   
   /* Logically, this is `best_regend[0]'.  But we don't want to have to
      allocate space for that if we're not allocating space for anything
@@ -3258,8 +3252,8 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
   const char *match_end = NULL;
 
   /* Used when we pop values we don't care about.  */
-  const char **reg_dummy;
-  register_info_type *reg_info_dummy;
+  const char **reg_dummy = NULL;
+  register_info_type *reg_info_dummy = NULL;
 
 #ifdef DEBUG
   /* Counts the total number of registers pushed.  */
@@ -3767,13 +3761,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
                           regstart[r] = old_regstart[r];
 
                           /* xx why this test?  */
-                          if ((int) old_regend[r] >= (int) regstart[r])
+                          if ((long) old_regend[r] >= (long) regstart[r])
                             regend[r] = old_regend[r];
                         }     
                     }
                  p1++;
                   EXTRACT_NUMBER_AND_INCR (mcnt, p1);
-                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+                  PUSH_FAILURE_POINT ( p1 + mcnt, d, -2);
 
                   goto fail;
                 }
@@ -4074,7 +4068,7 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
                actual values.  Otherwise, we will restore only one
                register from the stack, since lowest will == highest in
                `pop_failure_point'.  */
-            unsigned dummy_low_reg, dummy_high_reg;
+            unsigned long dummy_low_reg, dummy_high_reg;
             unsigned char *pdummy;
             const char *sdummy;
 
index 676bcc926d7bcc89116363e53e008c7463e5cfb4..3f5cbb5adaf289647f04f923072601d050fb27a1 100644 (file)
@@ -3,7 +3,7 @@
 #
 #  Darren Hardy, hardy@cs.colorado.edu, April 1994
 #
-#  $Id: Makefile.in,v 1.8 1996/05/01 22:36:21 wessels Exp $
+#  $Id: Makefile.in,v 1.9 1996/07/09 03:41:10 wessels Exp $
 #
 prefix         = @prefix@
 srcdir         = @srcdir@
@@ -15,10 +15,9 @@ INSTALL              = @INSTALL@
 INSTALL_BIN    = @INSTALL_PROGRAM@
 INSTALL_FILE   = @INSTALL_DATA@
 RANLIB         = @RANLIB@
-STD_CFLAGS     = @STD_CFLAGS@
-STD_LDFLAGS    = @STD_LDFLAGS@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
 XTRA_LIBS      = @XTRA_LIBS@
-XTRA_CFLAGS     = @XTRA_CFLAGS@
 
 INCLUDE                = -I../include -I$(srcdir)/../include
 UTILOBJS       = rfc850.o \
@@ -27,16 +26,16 @@ UTILOBJS    = rfc850.o \
                  host_cache.o \
                  getfullhostname.o \
                  debug.o \
-                 log.o
+                 log.o \
+                 tempnam.o
 REGEXOBJS      = GNUregex.o
-LIBS           = libutil.a libregex.a
+LIBS           = libmiscutil.a libregex.a
 
-CFLAGS         = $(STD_CFLAGS) $(XTRA_CFLAGS) $(INCLUDE)
-LDFLAGS                = $(STD_LDFLAGS)
+CFLAGS         = $(AC_CFLAGS) $(INCLUDE)
 
 all: $(LIBS)
 
-libutil.a: $(UTILOBJS)
+libmiscutil.a: $(UTILOBJS)
        ar r $@ $(UTILOBJS)
        $(RANLIB) $@
 
index 26bea61396dfa3973f2487ed0c9d2c5093c4d571..8b168e429eb422a100ad0a22b67c7f044fe88188 100644 (file)
+/*
+ * $Id: getfullhostname.c,v 1.5 1996/07/09 03:41:11 wessels Exp $
+ *
+ * DEBUG: 
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
-/* $Id: getfullhostname.c,v 1.4 1996/04/14 03:25:23 wessels Exp $ */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
+#include "config.h"
+
+#if HAVE_STDIO_H
 #include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#if HAVE_STRING_H
 #include <string.h>
+#endif
+#if HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
+#if HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
+#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)  /* protect on NEXTSTEP */
+#define _SQUID_NETDB_H_
 #include <netdb.h>
-#include "util.h"
+#endif
 
+#include "util.h"
 
 /*
  *  getfullhostname() - Returns the fully qualified name of the current 
index ca15f393d674d869cd5682c1bbeda53afacd9605..d90037d9ddaabb442eac2a596633d1679fc1ea35 100644 (file)
@@ -1,7 +1,117 @@
-/* $Id: rfc1738.c,v 1.2 1996/02/29 08:15:23 wessels Exp $ */
+/*
+ * $Id: rfc1738.c,v 1.3 1996/07/09 03:41:13 wessels Exp $
+ *
+ * DEBUG: 
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
+
+#include "config.h"
 
+#if HAVE_STDIO_H
 #include <stdio.h>
+#endif
+#if HAVE_STRING_H
 #include <string.h>
+#endif
+
 #include "util.h"
 #define BIG_BUFSIZ (BUFSIZ * 4)
 
@@ -9,7 +119,7 @@
  *  RFC 1738 defines that these characters should be escaped, as well
  *  any non-US-ASCII character or anything between 0x00 - 0x1F.
  */
-char rfc1738_unsafe_chars[] =
+static char rfc1738_unsafe_chars[] =
 {
     (char) 0x3C,               /* < */
     (char) 0x3E,               /* > */
@@ -51,7 +161,7 @@ char *rfc1738_escape(url)
            }
        }
        /* RFC 1738 says any control chars (0x00-0x1F) are encoded */
-       if ((*p >= (char) 0x00) && (*p <= (char) 0x1F)) {
+       if (*p <= (char) 0x1F) {
            do_escape = 1;
        }
        /* RFC 1738 says 0x7f is encoded */
diff --git a/lib/tempnam.c b/lib/tempnam.c
new file mode 100644 (file)
index 0000000..ba5f7ca
--- /dev/null
@@ -0,0 +1,256 @@
+/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
+ * This file is part of the GNU C Library.
+ * 
+ * The GNU C Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ * 
+ * The GNU C Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU C Library; see the file COPYING.LIB.  If
+ * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+ * Cambridge, MA 02139, USA.  */
+
+/* tempnam for NEXTSTEP. from Linux GNU libc. Hacked by lukeh@schnet.edu.au */
+
+#include "config.h"
+
+#if !HAVE_TEMPNAM
+
+#ifdef __NeXT__
+#ifndef _POSIX_SOURCE
+#define _POSIX_SOURCE
+#endif /* _POSIX_SOURCE_ */
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#endif /* __NeXT__ */
+
+#if HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef __STDC__
+#if HAVE_STDDEF_H
+#include <stddef.h>
+#endif
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define P_tmpdir      "/tmp"
+
+/* These are the characters used in temporary filenames.  */
+static const char letters[] =
+
+"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+/* Return nonzero if DIR is an existent directory.  */
+static int diraccess (const char *dir) {
+    struct stat buf;
+    uid_t euid;
+
+    if (stat(dir, &buf) != 0 || !S_ISDIR(buf.st_mode))
+       return 0;
+
+    /* That is going to be tough. */
+
+    euid = geteuid();
+
+    /* super user */
+    if (!euid)
+       return 1;
+
+    if (euid == buf.st_uid)
+       return ((buf.st_mode & S_IWUSR) && (buf.st_mode & S_IXUSR));
+
+    if (getegid() == buf.st_gid)
+       return ((buf.st_mode & S_IWGRP) && (buf.st_mode & S_IXGRP));
+
+    return ((buf.st_mode & S_IWOTH) && (buf.st_mode & S_IXOTH));
+}
+
+/* Return nonzero if FILE exists.  */
+static int exists(const char *file) {
+    /* We can stat the file even if we can't read its data.  */
+    struct stat st;
+    int save = errno;
+    if (stat(file, &st) == 0)
+       return 1;
+    else {
+       /* We report that the file exists if stat failed for a
+        * reason other
+        * than nonexistence.  In this case, it may or may not exist, and
+        * we
+        * don't know; but reporting that it does exist will never cause
+        * any
+        * trouble, while reporting that it doesn't exist when it does
+        * would
+        * violate the interface of __stdio_gen_tempname.  */
+       int exists = errno != ENOENT;
+       errno = save;
+       return exists;
+    }
+}
+
+
+/* Generate a temporary filename and return it (in a static buffer).  If
+  STREAMPTR is not NULL, open a stream "w+b" on the file and set
+  *STREAMPTR to it.  If DIR_SEARCH is nonzero, DIR and PFX are used as
+  described for tempnam.  If not, a temporary filename in P_tmpdir with
+  no special prefix is generated.  If LENPTR is not NULL, *LENPTR is
+  set the to length (including the terminating '\0') of the resultant
+  filename, which is returned.  This goes through a cyclic pattern of
+  all possible filenames consisting of five decimal digits of the
+  current pid and three of the characters in `letters'.  Data for
+  tempnam and tmpnam is kept separate, but when tempnam is using
+  P_tmpdir and no prefix (i.e, it is identical to tmpnam), the same
+  data is used.  Each potential filename is tested for an
+  already-existing file of the same name, and no name of an existing
+  file will be returned.  When the cycle reaches its end (12345ZZZ),
+  NULL is returned. */
+
+static char *gen_tempname (
+    const char *dir,
+    const char *pfx,
+    int dir_search,
+    size_t * lenptr,
+    FILE ** streamptr
+) {
+    int saverrno = errno;
+    static const char tmpdir[] = P_tmpdir;
+    static struct {
+       unsigned char digits[4];
+    } infos[2], *info;
+    static char buf[FILENAME_MAX];
+    static pid_t oldpid = (pid_t) 0;
+    pid_t pid = getpid();
+    register size_t len, plen, dlen, flen;
+    int i, carry;
+
+    if (dir_search) {
+       register const char *d = getenv("TMPDIR");
+       if (d != NULL && !diraccess(d))
+           d = NULL;
+       if (d == NULL && dir != NULL && diraccess(dir))
+           d = dir;
+       if (d == NULL && diraccess(tmpdir))
+           d = tmpdir;
+       if (d == NULL && diraccess("/tmp"))
+           d = "/tmp";
+       if (d == NULL) {
+           errno = ENOENT;
+           return NULL;
+       }
+       dir = d;
+    } else
+       dir = tmpdir;
+    dlen = strlen(dir);
+
+    /* Remove trailing slashes from the directory name.  */
+    while (dlen > 1 && dir[dlen - 1] == '/')
+       --dlen;
+
+    if (pfx != NULL && *pfx != '\0') {
+       plen = strlen(pfx);
+       if (plen > 5)
+           plen = 5;
+    } else
+       plen = 0;
+
+    if (dir != tmpdir && !strcmp(dir, tmpdir))
+       dir = tmpdir;
+    info = &infos[(plen == 0 && dir == tmpdir) ? 1 : 0];
+
+    if (pid != oldpid) {
+       oldpid = pid;
+       for (i = 0; i < sizeof(info->digits); i++)
+           infos[0].digits[i] = infos[1].digits[i] = 0;
+    }
+    flen = dlen + 1 + plen + 5;
+    for (;;) {
+       if (info->digits[sizeof(info->digits) - 1]) {
+           errno = EEXIST;
+           return NULL;
+       }
+       len = flen;
+       if ((sizeof(buf) - sizeof(info->digits)) < len ||
+           sprintf(buf, "%.*s/%.*s%.5d", (int) dlen, dir,
+               (int) plen, pfx, pid % 100000) != (int) len)
+           return NULL;
+
+       /* Get the last part of string */
+       for (i = 0; i < sizeof(info->digits) - 1; i++)
+           buf[len++] = letters[info->digits[i]];
+       buf[len] = '\0';
+
+       /* Always return a unique string.  */
+       carry = ++info->digits[0] / (sizeof(letters) - 1);
+       info->digits[0] %= (sizeof(letters) - 1);
+       for (i = 1; i < sizeof(info->digits); i++) {
+           info->digits[i] += carry;
+           carry = info->digits[i] / (sizeof(letters) - 1);
+           info->digits[i] %= (sizeof(letters) - 1);
+       }
+
+       if (streamptr != NULL) {
+           int fd = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666);
+           if (fd >= 0) {
+               *streamptr = fdopen(fd, "w+b");
+               if (*streamptr == NULL) {
+                   int save = errno;
+                   (void) close(fd);
+                   errno = save;
+                   return NULL;
+               }
+               break;
+           }
+       } else if (!exists(buf))
+           break;
+    }
+
+    errno = saverrno;
+
+    if (lenptr != NULL)
+       *lenptr = len + 1;
+    return buf;
+}
+
+char *tempnam(const char *dir, const char *pfx) {
+    size_t len;
+    register char *s;
+    register char *t = gen_tempname(dir, pfx, 1, &len, (FILE **)
+       NULL);
+
+    if (t == NULL)
+       return NULL;
+
+    s = (char *) malloc(len);
+    if (s == NULL)
+       return NULL;
+
+    (void) memcpy(s, t, len);
+    return s;
+}
+
+#endif /* !HAVE_TEMPNAM */
index 983b1d3ad552b7187abd57e4c478153b324ed404..7f4c3c9e2b963088dd2c6c0aa0691b97d955f075 100644 (file)
-/* $Id: util.c,v 1.7 1996/05/03 22:56:18 wessels Exp $ */
+/*
+ * $Id: util.c,v 1.8 1996/07/09 03:41:14 wessels Exp $
+ *
+ * DEBUG: 
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
+#include "config.h"
+
+#if HAVE_STDIO_H
 #include <stdio.h>
+#endif
+#if HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#if HAVE_STRING_H
 #include <string.h>
+#endif
+#if HAVE_UNISTD_H
 #include <unistd.h>
-#ifndef _SQUID_FREEBSD_                /* "Obsolete" Markus Stumpf <maex@Space.NET> */
+#endif
+#if HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
 #include <malloc.h>
 #endif
+#if HAVE_ERRNO_H
 #include <errno.h>
+#endif
 
-void (*failure_notify) () = NULL;
+#include "util.h"
+
+void (*failure_notify) _PARAMS((char *)) = NULL;
 static char msg[128];
 
 extern int sys_nerr;
-#if !defined(__FreeBSD__) && !defined(__NetBSD__)
+#if NEED_SYS_ERRLIST && !defined(_SQUID_NETBSD_)
 extern char *sys_errlist[];
 #endif
 
-#include "autoconf.h"
+#if XMALLOC_STATISTICS
+#define DBG_MAXSIZE   (1024*1024)
+#define DBG_GRAIN     (16)
+#define DBG_MAXINDEX  (DBG_MAXSIZE/DBG_GRAIN)
+#define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX)
+static int malloc_sizes[DBG_MAXINDEX + 1];
+static int dbg_stat_init = 0;
+
+static void stat_init()
+{
+    int i;
+    for (i = 0; i <= DBG_MAXINDEX; i++)
+       malloc_sizes[i] = 0;
+    dbg_stat_init = 1;
+}
+
+static int malloc_stat(sz)
+     int sz;
+{
+    if (!dbg_stat_init)
+       stat_init();
+    return malloc_sizes[DBG_INDEX(sz)] += 1;
+}
+
+void malloc_statistics(func, data)
+     void (*func) _PARAMS((int, int, void *));
+     void *data;
+{
+    int i;
+    for (i = 0; i <= DBG_MAXSIZE; i += DBG_GRAIN)
+       func(i, malloc_sizes[DBG_INDEX(i)], data);
+}
+#endif /* XMALLOC_STATISTICS */
+
 
 
 #if XMALLOC_DEBUG
@@ -34,10 +184,10 @@ static void *Q;
 static void check_init()
 {
     for (B = 0; B < DBG_ARRY_SZ; B++) {
-      for (I = 0; I < DBG_ARRY_SZ; I++) {
-       malloc_ptrs[B][I] = NULL;
-       malloc_size[B][I] = 0;
-      }
+       for (I = 0; I < DBG_ARRY_SZ; I++) {
+           malloc_ptrs[B][I] = NULL;
+           malloc_size[B][I] = 0;
+       }
     }
     dbg_initd = 1;
 }
@@ -111,6 +261,9 @@ void *xmalloc(sz)
     }
 #if XMALLOC_DEBUG
     check_malloc(p, sz);
+#endif
+#if XMALLOC_STATISTICS
+    malloc_stat(sz);
 #endif
     return (p);
 }
@@ -162,6 +315,9 @@ void *xrealloc(s, sz)
     }
 #if XMALLOC_DEBUG
     check_malloc(p, sz);
+#endif
+#if XMALLOC_STATISTICS
+    malloc_stat(sz);
 #endif
     return (p);
 }
@@ -192,6 +348,9 @@ void *xcalloc(n, sz)
     }
 #if XMALLOC_DEBUG
     check_malloc(p, sz * n);
+#endif
+#if XMALLOC_STATISTICS
+    malloc_stat(sz);
 #endif
     return (p);
 }
@@ -204,7 +363,7 @@ char *xstrdup(s)
      char *s;
 {
     static char *p = NULL;
-    int sz;
+    size_t sz;
 
     if (s == NULL) {
        if (failure_notify) {
@@ -215,7 +374,7 @@ char *xstrdup(s)
        exit(1);
     }
     sz = strlen(s);
-    p = (char *) xmalloc((size_t) sz + 1);
+    p = xmalloc((size_t) sz + 1);
     memcpy(p, s, sz);          /* copy string */
     p[sz] = '\0';              /* terminate string */
     return (p);
@@ -244,10 +403,16 @@ char *strdup(s)
 }
 #endif
 
-#if !HAVE_STRERROR
-char *strerror(n)
-int n;
+void xmemcpy(from, to, len)
+     void *from;
+     void *to;
+     int len;
 {
-    return (xstrerror(n));
-}
+#if HAVE_MEMMOVE
+    (void) memmove(from, to, len);
+#elif HAVE_BCOPY
+    bcopy(to, from, len);
+#else
+    (void) memcpy(from, to, len);
 #endif
+}
index ae639ec336cd9301e3a57d9408c7ce0523903dfd..3b7c4bfb1565e43499872d514be1c723a2ee38a6 100644 (file)
@@ -1,13 +1,14 @@
 #!/bin/sh
 #
-#  $Id: RunAccel.in,v 1.3 1996/05/03 22:56:19 wessels Exp $
+#  $Id: RunAccel.in,v 1.4 1996/07/09 03:41:15 wessels Exp $
 
 # enable HTTP requests on port 80
 port="-a 80"
 
 prefix=@prefix@
 exec_prefix=@exec_prefix@
-PATH=@bindir@:/bin
+logdir=@localstatedir@
+PATH=@bindir@:/bin:/usr/bin
 export PATH
 
 if test $# = 1 ; then
@@ -17,9 +18,9 @@ fi
 
 failcount=0
 while : ; do
-       echo "Running: squid $port -s $conf >> squid.out 2>&1"
+       echo "Running: squid $port -s $conf >> $logdir/squid.out 2>&1"
        start=`date '+%d%H%M%S'`
-       squid $port -s $conf >> squid.out 2>&1
+       squid $port -s $conf >> $logdir/squid.out 2>&1
        stop=`date '+%d%H%M%S'`
        t=`expr $stop - $start`
        if test 0 -le $t -a $t -lt 5 ; then
index cf420550454d0ecea04c80404bbbce48bed42b13..7e7fbcb2bd5270544c73eb6e8729eb021150137f 100644 (file)
@@ -1,10 +1,11 @@
 #!/bin/sh
 #
-#  $Id: RunCache.in,v 1.5 1996/05/03 22:56:19 wessels Exp $
+#  $Id: RunCache.in,v 1.6 1996/07/09 03:41:15 wessels Exp $
 
 prefix=@prefix@
 exec_prefix=@exec_prefix@
-PATH=@bindir@:/bin
+logdir=@localstatedir@
+PATH=@bindir@:/bin:/usr/bin
 export PATH
 
 conf=""
@@ -15,9 +16,9 @@ fi
 
 failcount=0
 while : ; do
-       echo "Running: squid -s $conf >> squid.out 2>&1"
+       echo "Running: squid -s $conf >> $logdir/squid.out 2>&1"
        start=`date '+%d%H%M%S'`
-       squid -s $conf >> squid.out 2>&1
+       squid -s $conf >> $logdir/squid.out 2>&1
        stop=`date '+%d%H%M%S'`
        t=`expr $stop - $start`
        if test 0 -le $t -a $t -lt 5 ; then
index e650ebb75872de41bc886293fd82792f835ad3d9..cdf3bf17f2484d1d5533a53262e70eed0946fe6e 100755 (executable)
@@ -7,7 +7,7 @@
 # Version 1 did all this in memory, but the log file can be a
 # little on the large side... 8-(
 
-# $Id: check_cache.pl,v 1.2 1996/05/01 22:36:22 wessels Exp $
+# $Id: check_cache.pl,v 1.3 1996/07/09 03:41:16 wessels Exp $
 
 require "getopts.pl";
 &Getopts("c:dl:rt:v");
index e5871697ac122549643cf965917fcccf12d66653..85b5f8337c220932ff20869e29482353ccaefe9d 100755 (executable)
@@ -16,7 +16,34 @@ $|=1;
 $host=(shift || 'localhost') ;
 $port=(shift || '3130') ;
 
-@CODES=('xxx', 'QUERY', 'HIT', 'MISS', 'ERROR');
+# just copy this from src/proto.c
+@CODES=(
+    "ICP_INVALID",
+    "ICP_QUERY",
+    "UDP_HIT",
+    "UDP_MISS",
+    "ICP_ERR",
+    "ICP_SEND",
+    "ICP_SENDA",
+    "ICP_DATABEG",
+    "ICP_DATA",
+    "ICP_DATAEND",
+    "ICP_SECHO",
+    "ICP_DECHO",
+    "ICP_OP_UNUSED0",
+    "ICP_OP_UNUSED1",
+    "ICP_OP_UNUSED2",
+    "ICP_OP_UNUSED3",
+    "ICP_OP_UNUSED4",
+    "ICP_OP_UNUSED5",
+    "ICP_OP_UNUSED6",
+    "ICP_OP_UNUSED7",
+    "ICP_OP_UNUSED8",
+    "ICP_OP_UNUSED9",
+    "UDP_DENIED",
+    "UDP_HIT_OBJ",
+    "ICP_END"
+);
 
 require 'sys/socket.ph';
 
@@ -34,13 +61,15 @@ die "socket: $!\n" unless
 
 while (<>) {
        chop;
-       $request_template = 'CCnx4x8x4a4a' . length;
-       $request = pack($request_template, 1, 1, 24 + length, $myip, $_);
+       $request_template = 'CCnx4Nx4x4a4a' . length;
+       $request = pack($request_template, 1, 1, 24 + length, ~0, $myip, $_);
        die "send: $!\n" unless
                send(SOCK, $request, 0, $them);
        die "recv: $!\n" unless
-               recv(SOCK, $reply, 1024, 0);
-       ($type,$ver,$len,$payload) = unpack('CCnx4x8x4A', $reply);
-       print $CODES[$type] . " $_\n";
+                $theiraddr = recv(SOCK, $reply, 1024, 0);
+       ($junk, $junk, $sourceaddr, $junk) = unpack($sockaddr, $theiraddr);
+       @theirip = unpack('C4', $sourceaddr);
+        ($type,$ver,$len,$payload) = unpack('CCnx4x8x4A', $reply);
+        print join('.', @theirip) . ' ' . $CODES[$type] . " $_\n";
 }
 
index 490700e8119bdb0895a0a874a3413d635a9d7a1b..d288a4d8e5c4d09d9ce44b98888b0af8971a2bab 100644 (file)
@@ -1,7 +1,7 @@
 #
 #  Makefile for the Squid Object Cache server
 #
-#  $Id: Makefile.in,v 1.25 1996/05/03 22:56:20 wessels Exp $
+#  $Id: Makefile.in,v 1.26 1996/07/09 03:41:17 wessels Exp $
 #
 #  Uncomment and customize the following to suit your needs:
 #
@@ -35,19 +35,19 @@ RANLIB              = @RANLIB@
 LN_S           = @LN_S@
 PERL            = @PERL@
 CRYPT_LIB      = @CRYPT_LIB@
-STD_CFLAGS     = @STD_CFLAGS@
-STD_LDFLAGS    = @STD_LDFLAGS@
-XTRA_CFLAGS    = @XTRA_CFLAGS@
+AC_CFLAGS      = @CFLAGS@
+LDFLAGS                = @LDFLAGS@
 XTRA_LIBS      = @XTRA_LIBS@
 XTRA_OBJS      = @XTRA_OBJS@
+MV             = @MV@
+RM             = @RM@
 SHELL          = /bin/sh
 
 
 INCLUDE                = -I. -I../include -I$(srcdir)/../include
-CFLAGS                 = $(STD_CFLAGS) $(XTRA_CFLAGS) $(INCLUDE) $(DEFINES)
-LDFLAGS         = $(STD_LDFLAGS)
-LIBS           = -L../lib -lregex -lutil $(XTRA_LIBS)
-CLIENT_LIBS    = -L../lib -lutil $(XTRA_LIBS)
+CFLAGS                 = $(AC_CFLAGS) $(INCLUDE) $(DEFINES)
+LIBS           = -L../lib -lregex -lmiscutil $(XTRA_LIBS)
+CLIENT_LIBS    = -L../lib -lmiscutil $(XTRA_LIBS)
 
 PROGS           = squid client
 UTILS           = dnsserver ftpget
@@ -103,47 +103,71 @@ squid.conf: squid.conf.pre
        s%@DEFAULT_SWAP_DIR@%$(DEFAULT_SWAP_DIR)%g" <$? >$@
 
 install-mkdirs:
-       @if test ! -d $(prefix); then \
+       -@if test ! -d $(prefix); then \
                echo "mkdir $(prefix)"; \
                mkdir $(prefix); \
        fi
-       @if test ! -d $(exec_prefix); then \
+       -@if test ! -d $(exec_prefix); then \
                echo "mkdir $(exec_prefix)"; \
                mkdir $(exec_prefix); \
        fi
-       @if test ! -d $(bindir); then \
+       -@if test ! -d $(bindir); then \
                echo "mkdir $(bindir)"; \
                mkdir $(bindir); \
        fi
-       @if test ! -d $(libexecdir); then \
+       -@if test ! -d $(libexecdir); then \
                echo "mkdir $(libexecdir)"; \
                mkdir $(libexecdir); \
        fi
-       @if test ! -d $(sysconfdir); then \
+       -@if test ! -d $(sysconfdir); then \
                echo "mkdir $(sysconfdir)"; \
                mkdir $(sysconfdir); \
        fi
-       @if test ! -d $(localstatedir); then \
+       -@if test ! -d $(localstatedir); then \
                echo "mkdir $(localstatedir)"; \
                mkdir $(localstatedir); \
        fi
-       @if test ! -d $(localstatedir)/logs; then \
+       -@if test ! -d $(localstatedir)/logs; then \
                echo "mkdir $(localstatedir)/logs"; \
                mkdir $(localstatedir)/logs; \
        fi
 
 install: all install-mkdirs
        @for f in $(PROGS); do \
+               if test -f $(bindir)/$$f; then \
+                       echo $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+                       $(MV) $(bindir)/$$f $(bindir)/-$$f; \
+               fi; \
                echo $(INSTALL_BIN) $$f $(bindir); \
                $(INSTALL_BIN) $$f $(bindir); \
+               if test -f $(bindir)/-$$f; then \
+                       echo $(RM) -f $(bindir)/-$$f; \
+                       $(RM) $(bindir)/-$$f; \
+               fi; \
        done
        @for f in $(UTILS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
                echo $(INSTALL_BIN) $$f $(libexecdir); \
                $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) $(libexecdir)/-$$f; \
+               fi; \
        done
        @for f in $(CGIPROGS); do \
+               if test -f $(libexecdir)/$$f; then \
+                       echo $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+                       $(MV) $(libexecdir)/$$f $(libexecdir)/-$$f; \
+               fi; \
                echo $(INSTALL_BIN) $$f $(libexecdir); \
                $(INSTALL_BIN) $$f $(libexecdir); \
+               if test -f $(libexecdir)/-$$f; then \
+                       echo $(RM) -f $(libexecdir)/-$$f; \
+                       $(RM) $(libexecdir)/-$$f; \
+               fi; \
        done
        $(INSTALL_FILE) squid.conf $(sysconfdir)/squid.conf.default
        @if test -f $(sysconfdir)/squid.conf ; then \
@@ -158,3 +182,6 @@ clean:
 
 realclean:     clean
        -rm -f Makefile squid.conf squid.conf.pre
+
+tags:
+       ctags *.[ch] ../include/*.h ../lib/*.[ch]
index 4beeeea2cc865182b8eebdcd9bea7c613f920d97..16ef16088203404f398cb39f39313df423727c4d 100644 (file)
@@ -1,7 +1,31 @@
-/* "$Id: acl.cc,v 1.14 1996/05/03 22:56:21 wessels Exp $" */
-
 /*
- * DEBUG: Section 28          acl
+ * $Id: acl.cc,v 1.15 1996/07/09 03:41:17 wessels Exp $
+ *
+ * DEBUG: section 28    Access Control
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
 
 #include "squid.h"
@@ -13,14 +37,32 @@ struct _acl_access *ICPAccessList = NULL;
 static struct _acl *AclList = NULL;
 static struct _acl **AclListTail = &AclList;
 
-static int aclMatchAcl _PARAMS((struct _acl *, struct in_addr, method_t, protocol_t, char *host, int port, char *request));
+static void aclDestroyAclList _PARAMS((struct _acl_list * list));
+static void aclDestroyIpList _PARAMS((struct _acl_ip_data * data));
+static void aclDestroyRegexList _PARAMS((struct _relist * data));
+static void aclDestroyTimeList _PARAMS((struct _acl_time_data * data));
 static int aclMatchAclList _PARAMS((struct _acl_list *, struct in_addr, method_t, protocol_t, char *host, int port, char *request));
-
-static acl_t aclType(s)
+static int aclMatchInteger _PARAMS((intlist * data, int i));
+static int aclMatchIp _PARAMS((struct _acl_ip_data * data, struct in_addr c));
+static int aclMatchRegex _PARAMS((relist * data, char *word));
+static int aclMatchTime _PARAMS((struct _acl_time_data * data, time_t when));
+static int aclMatchEndOfWord _PARAMS((wordlist * data, char *word));
+static intlist *aclParseIntlist _PARAMS((void));
+static struct _acl_ip_data *aclParseIpList _PARAMS((void));
+static intlist *aclParseMethodList _PARAMS((void));
+static intlist *aclParseProtoList _PARAMS((void));
+static struct _relist *aclParseRegexList _PARAMS((void));
+static struct _acl_time_data *aclParseTimeSpec _PARAMS((void));
+static wordlist *aclParseWordList _PARAMS((void));
+static squid_acl aclType _PARAMS((char *s));
+
+static squid_acl aclType(s)
      char *s;
 {
     if (!strcmp(s, "src"))
        return ACL_SRC_IP;
+    if (!strcmp(s, "dst"))
+       return ACL_DST_IP;
     if (!strcmp(s, "domain"))
        return ACL_DST_DOMAIN;
     if (!strcmp(s, "time"))
@@ -31,7 +73,7 @@ static acl_t aclType(s)
        return ACL_URL_PORT;
     if (!strcmp(s, "user"))
        return ACL_USER;
-    if (!strcmp(s, "proto"))
+    if (!strncmp(s, "proto", 5))
        return ACL_PROTO;
     if (!strcmp(s, "method"))
        return ACL_METHOD;
@@ -49,14 +91,14 @@ struct _acl *aclFindByName(name)
 }
 
 
-intlist *aclParseIntlist()
+static intlist *aclParseIntlist()
 {
     intlist *head = NULL;
     intlist **Tail = &head;
     intlist *q = NULL;
     char *t = NULL;
     while ((t = strtok(NULL, w_space))) {
-       q = (intlist *) xcalloc(1, sizeof(intlist));
+       q = xcalloc(1, sizeof(intlist));
        q->i = atoi(t);
        *(Tail) = q;
        Tail = &q->next;
@@ -64,14 +106,14 @@ intlist *aclParseIntlist()
     return head;
 }
 
-intlist *aclParseProtoList()
+static intlist *aclParseProtoList()
 {
     intlist *head = NULL;
     intlist **Tail = &head;
     intlist *q = NULL;
     char *t = NULL;
     while ((t = strtok(NULL, w_space))) {
-       q = (intlist *) xcalloc(1, sizeof(intlist));
+       q = xcalloc(1, sizeof(intlist));
        q->i = (int) urlParseProtocol(t);
        *(Tail) = q;
        Tail = &q->next;
@@ -79,14 +121,14 @@ intlist *aclParseProtoList()
     return head;
 }
 
-intlist *aclParseMethodList()
+static intlist *aclParseMethodList()
 {
     intlist *head = NULL;
     intlist **Tail = &head;
     intlist *q = NULL;
     char *t = NULL;
     while ((t = strtok(NULL, w_space))) {
-       q = (intlist *) xcalloc(1, sizeof(intlist));
+       q = xcalloc(1, sizeof(intlist));
        q->i = (int) urlParseMethod(t);
        *(Tail) = q;
        Tail = &q->next;
@@ -94,75 +136,131 @@ intlist *aclParseMethodList()
     return head;
 }
 
-struct _acl_ip_data *aclParseIpList()
+/* Decode a ascii representation (asc) of a IP adress, and place
+ * adress and netmask information in addr and mask.
+ */
+static int decode_addr(asc, addr, mask)
+     char *asc;
+     struct in_addr *addr, *mask;
 {
-    char *t = NULL;
+    struct hostent *hp = NULL;
+    u_num32 a;
+    int a1, a2, a3, a4;
+
+    switch (sscanf(asc, "%d.%d.%d.%d", &a1, &a2, &a3, &a4)) {
+    case 4:                    /* a dotted quad */
+       if ((a = inet_addr(asc)) != INADDR_NONE ||
+           !strcmp(asc, "255.255.255.255")) {
+           addr->s_addr = a;
+           /* inet_addr() outputs in network byte order */
+       }
+       break;
+    case 1:                    /* a significant bits value for a mask */
+       if (a1 >= 0 && a1 < 33) {
+           addr->s_addr = htonl(0xffffffff << (32 - a1));
+           break;
+       }
+    default:
+       if ((hp = gethostbyname(asc)) != NULL) {
+           /* We got a host name */
+           xmemcpy(addr, hp->h_addr, hp->h_length);
+       } else {
+           /* XXX: Here we could use getnetbyname */
+           debug(28, 0, "decode_addr: Invalid IP address or hostname  '%s'\n", asc);
+           return 0;           /* This is not valid address */
+       }
+       break;
+    }
+
+    if (mask != NULL) {                /* mask == NULL if called to decode a netmask */
+
+       /* Guess netmask */
+       a = ntohl(addr->s_addr);
+       if (!(a & 0xFFFFFFFF))
+           mask->s_addr = htonl(0x00000000);
+       else if (!(a & 0x00FFFFFF))
+           mask->s_addr = htonl(0xFF000000);
+       else if (!(a & 0x0000FFFF))
+           mask->s_addr = htonl(0xFFFF0000);
+       else if (!(a & 0x000000FF))
+           mask->s_addr = htonl(0xFFFFFF00);
+       else
+           mask->s_addr = htonl(0xFFFFFFFF);
+    }
+    return 1;
+}
+
+
+static struct _acl_ip_data *aclParseIpList()
+{
+    char *t = NULL, *p = NULL;
     struct _acl_ip_data *head = NULL;
     struct _acl_ip_data **Tail = &head;
     struct _acl_ip_data *q = NULL;
-    int a1, a2, a3, a4;
-    int m1, m2, m3, m4;
-    struct in_addr lmask;
-    int c;
+    static char addr1[256], addr2[256], mask[256];
 
     while ((t = strtok(NULL, w_space))) {
-       q = (struct _acl_ip_data *) xcalloc(1, sizeof(struct _acl_ip_data));
-       a1 = a2 = a3 = a4 = 0;
+       q = xcalloc(1, sizeof(struct _acl_ip_data));
        if (!strcasecmp(t, "all")) {
-           lmask.s_addr = 0;
+           q->addr1.s_addr = 0;
+           q->addr2.s_addr = 0;
+           q->mask.s_addr = 0;
        } else {
-           c = sscanf(t, "%d.%d.%d.%d/%d.%d.%d.%d",
-               &a1, &a2, &a3, &a4,
-               &m1, &m2, &m3, &m4);
-           switch (c) {
-           case 4:
-               if (a1 == 0 && a2 == 0 && a3 == 0 && a4 == 0)   /* world   */
-                   lmask.s_addr = 0x00000000;
-               else if (a2 == 0 && a3 == 0 && a4 == 0)         /* class A */
-                   lmask.s_addr = htonl(0xff000000);
-               else if (a3 == 0 && a4 == 0)    /* class B */
-                   lmask.s_addr = htonl(0xffff0000);
-               else if (a4 == 0)       /* class C */
-                   lmask.s_addr = htonl(0xffffff00);
-               else
-                   lmask.s_addr = 0xffffffff;
-               break;
-           case 5:
-               if (m1 < 0 || m1 > 32) {
-                   debug(28, 0, "%s line %d: %s\n",
-                       cfg_filename, config_lineno, config_input_line);
-                   debug(28, 0, "aclParseIpList: Ignoring invalid IP acl entry '%s'\n", t);
-                   safe_free(q);
-                   continue;
-               }
-               lmask.s_addr = htonl(0xffffffff << (32 - m1));
-               break;
-           case 8:
-               lmask.s_addr = htonl(m1 * 0x1000000 + m2 * 0x10000 + m3 * 0x100 + m4);
-               break;
-           default:
+           p = t;
+           memset(addr1, 0, sizeof(addr1));
+           memset(addr2, 0, sizeof(addr2));
+           memset(mask, 0, sizeof(mask));
+
+           /* Split the adress in addr1-addr2/mask */
+           strncpy(addr1, p, strcspn(t, "-/"));
+           p += strcspn(t, "-/");
+           if (*p == '-') {
+               p++;
+               strncpy(addr2, p, strcspn(t, "/"));
+               p += strcspn(p, "/");
+           }
+           if (*p == '/') {
+               p++;
+               strcpy(mask, p);
+           }
+           /* Decode addr1 */
+           if (!decode_addr(addr1, &q->addr1, &q->mask)) {
                debug(28, 0, "%s line %d: %s\n",
                    cfg_filename, config_lineno, config_input_line);
-               debug(28, 0, "aclParseIpList: Ignoring invalid IP acl entry '%s'\n", t);
+               debug(28, 0, "aclParseIpList: Ignoring invalid IP acl entry: unknown first address '%s'\n", addr1);
+               safe_free(q);
+               continue;
+           }
+           /* Decode addr2 */
+           if (*addr2 && !decode_addr(addr2, &q->addr2, &q->mask)) {
+               debug(28, 0, "%s line %d: %s\n",
+                   cfg_filename, config_lineno, config_input_line);
+               debug(28, 0, "aclParseIpList: Ignoring invalid IP acl entry: unknown second address '%s'\n", addr1);
+               safe_free(q);
+               continue;
+           }
+           /* Decode mask */
+           if (*mask && !decode_addr(mask, &q->mask, NULL)) {
+               debug(28, 0, "%s line %d: %s\n",
+                   cfg_filename, config_lineno, config_input_line);
+               debug(28, 0, "aclParseIpList: Ignoring invalid IP acl entry: unknown netmask '%s'\n", mask);
                safe_free(q);
                continue;
            }
        }
-       q->addr1.s_addr = htonl(a1 * 0x1000000 + a2 * 0x10000 + a3 * 0x100 + a4);
-       q->mask1.s_addr = lmask.s_addr;
        *(Tail) = q;
        Tail = &q->next;
     }
     return head;
 }
 
-struct _acl_time_data *aclParseTimeSpec()
+static struct _acl_time_data *aclParseTimeSpec()
 {
     struct _acl_time_data *data = NULL;
     int h1, m1, h2, m2;
     char *t = NULL;
 
-    data = (struct _acl_time_data *) xcalloc(1, sizeof(struct _acl_time_data));
+    data = xcalloc(1, sizeof(struct _acl_time_data));
     while ((t = strtok(NULL, w_space))) {
        if (*t < '0' || *t > '9') {
            /* assume its day-of-week spec */
@@ -189,6 +287,9 @@ struct _acl_time_data *aclParseTimeSpec()
                case 'A':
                    data->weekbits |= ACL_SATURDAY;
                    break;
+               case 'D':
+                   data->weekbits |= ACL_WEEKDAYS;
+                   break;
                default:
                    debug(28, 0, "%s line %d: %s\n",
                        cfg_filename, config_lineno, config_input_line);
@@ -226,7 +327,7 @@ struct _acl_time_data *aclParseTimeSpec()
     return data;
 }
 
-struct _relist *aclParseRegexList()
+static struct _relist *aclParseRegexList()
 {
     relist *head = NULL;
     relist **Tail = &head;
@@ -240,7 +341,7 @@ struct _relist *aclParseRegexList()
            debug(28, 0, "aclParseRegexList: Invalid regular expression: '%s'\n", t);
            continue;
        }
-       q = (relist *) xcalloc(1, sizeof(relist));
+       q = xcalloc(1, sizeof(relist));
        q->pattern = xstrdup(t);
        q->regex = comp;
        *(Tail) = q;
@@ -249,14 +350,14 @@ struct _relist *aclParseRegexList()
     return head;
 }
 
-wordlist *aclParseWordList()
+static wordlist *aclParseWordList()
 {
     wordlist *head = NULL;
     wordlist **Tail = &head;
     wordlist *q = NULL;
     char *t = NULL;
     while ((t = strtok(NULL, w_space))) {
-       q = (wordlist *) xcalloc(1, sizeof(wordlist));
+       q = xcalloc(1, sizeof(wordlist));
        q->key = xstrdup(t);
        *(Tail) = q;
        Tail = &q->next;
@@ -272,7 +373,7 @@ void aclParseAclLine()
     char *t = NULL;
     struct _acl *A = NULL;
 
-    A = (struct _acl *) xcalloc(1, sizeof(struct _acl));
+    A = xcalloc(1, sizeof(struct _acl));
     /* snarf the ACL name */
     if ((t = strtok(NULL, w_space)) == NULL) {
        debug(28, 0, "%s line %d: %s\n",
@@ -299,6 +400,7 @@ void aclParseAclLine()
     }
     switch (A->type = aclType(t)) {
     case ACL_SRC_IP:
+    case ACL_DST_IP:
        A->data = (void *) aclParseIpList();
        break;
     case ACL_DST_DOMAIN:
@@ -330,7 +432,6 @@ void aclParseAclLine()
        xfree(A);
        return;
        /* NOTREACHED */
-       break;
     }
     A->cfgline = xstrdup(config_input_line);
     *AclListTail = A;
@@ -355,7 +456,7 @@ void aclParseAccessLine(head)
        debug(28, 0, "aclParseAccessLine: missing 'allow' or 'deny'.\n");
        return;
     }
-    A = (struct _acl_access *) xcalloc(1, sizeof(struct _acl_access));
+    A = xcalloc(1, sizeof(struct _acl_access));
     if (!strcmp(t, "allow"))
        A->allow = 1;
     else if (!strcmp(t, "deny"))
@@ -372,7 +473,7 @@ void aclParseAccessLine(head)
      * by '!' for negation */
     Tail = &A->acl_list;
     while ((t = strtok(NULL, w_space))) {
-       L = (struct _acl_list *) xcalloc(1, sizeof(struct _acl_list));
+       L = xcalloc(1, sizeof(struct _acl_list));
        L->op = 1;              /* defaults to non-negated */
        if (*t == '!') {
            /* negated ACL */
@@ -404,18 +505,32 @@ void aclParseAccessLine(head)
     *T = A;
 }
 
-int aclMatchIp(data, c)
+static int aclMatchIp(data, c)
      struct _acl_ip_data *data;
      struct in_addr c;
 {
     struct in_addr h;
+    unsigned long lh, la1, la2;
+
     while (data) {
-       h.s_addr = c.s_addr & data->mask1.s_addr;
+       h.s_addr = c.s_addr & data->mask.s_addr;
        debug(28, 3, "aclMatchIp: h     = %s\n", inet_ntoa(h));
        debug(28, 3, "aclMatchIp: addr1 = %s\n", inet_ntoa(data->addr1));
-       if (h.s_addr == data->addr1.s_addr) {
-           debug(28, 3, "aclMatchIp: returning 1\n");
-           return 1;
+       debug(28, 3, "aclMatchIp: addr2 = %s\n", inet_ntoa(data->addr2));
+       if (!data->addr2.s_addr) {
+           if (h.s_addr == data->addr1.s_addr) {
+               debug(28, 3, "aclMatchIp: returning 1\n");
+               return 1;
+           }
+       } else {
+           /* This is a range check */
+           lh = ntohl(h.s_addr);
+           la1 = ntohl(data->addr1.s_addr);
+           la2 = ntohl(data->addr2.s_addr);
+           if (lh >= la1 && lh <= la2) {
+               debug(28, 3, "aclMatchIp: returning 1\n");
+               return 1;
+           }
        }
        data = data->next;
     }
@@ -423,7 +538,8 @@ int aclMatchIp(data, c)
     return 0;
 }
 
-int aclMatchWord(data, word)
+#ifdef UNUSED_CODE
+static int aclMatchWord(data, word)
      wordlist *data;
      char *word;
 {
@@ -438,7 +554,27 @@ int aclMatchWord(data, word)
     }
     return 0;
 }
-int aclMatchRegex(data, word)
+#endif
+
+static int aclMatchEndOfWord(data, word)
+     wordlist *data;
+     char *word;
+{
+    int offset;
+    if (word == NULL)
+       return 0;
+    debug(28, 3, "aclMatchEndOfWord: checking '%s'\n", word);
+    for (; data; data = data->next) {
+       debug(28, 3, "aclMatchEndOfWord: looking for '%s'\n", data->key);
+       if ((offset = strlen(word) - strlen(data->key)) < 0)
+           continue;
+       if (strcmp(word + offset, data->key) == 0)
+           return 1;
+    }
+    return 0;
+}
+
+static int aclMatchRegex(data, word)
      relist *data;
      char *word;
 {
@@ -453,7 +589,8 @@ int aclMatchRegex(data, word)
     }
     return 0;
 }
-int aclMatchInteger(data, i)
+
+static int aclMatchInteger(data, i)
      intlist *data;
      int i;
 {
@@ -465,7 +602,7 @@ int aclMatchInteger(data, i)
     return 0;
 }
 
-int aclMatchTime(data, when)
+static int aclMatchTime(data, when)
      struct _acl_time_data *data;
      time_t when;
 {
@@ -475,7 +612,7 @@ int aclMatchTime(data, when)
 
     if (when != last_when) {
        last_when = when;
-       memcpy(&tm, localtime(&when), sizeof(struct tm));
+       xmemcpy(&tm, localtime(&when), sizeof(struct tm));
     }
     debug(28, 3, "aclMatchTime: checking %d-%d, weekbits=%x\n",
        data->start, data->stop, data->weekbits);
@@ -486,7 +623,7 @@ int aclMatchTime(data, when)
     return data->weekbits & (1 << tm.tm_wday) ? 1 : 0;
 }
 
-static int aclMatchAcl(acl, c, m, pr, h, po, r)
+int aclMatchAcl(acl, c, m, pr, h, po, r)
      struct _acl *acl;
      struct in_addr c;
      method_t m;
@@ -495,6 +632,9 @@ static int aclMatchAcl(acl, c, m, pr, h, po, r)
      int po;
      char *r;
 {
+    struct hostent *hp = NULL;
+    struct in_addr dst;
+    int k;
     if (!acl)
        return 0;
     debug(28, 3, "aclMatchAcl: checking '%s'\n", acl->cfgline);
@@ -502,44 +642,49 @@ static int aclMatchAcl(acl, c, m, pr, h, po, r)
     case ACL_SRC_IP:
        return aclMatchIp(acl->data, c);
        /* NOTREACHED */
-       break;
+    case ACL_DST_IP:
+       if ((hp = ipcache_gethostbyname(h, IP_LOOKUP_IF_MISS)) == NULL) {
+           debug(28, 3, "aclMatchAcl: Can't yet compare '%s' ACL for '%s'\n",
+               acl->name, h);
+           return 0;           /* cant check, return no match */
+       }
+       for (k = 0; hp->h_addr_list[k]; k++) {
+           xmemcpy(&dst.s_addr, hp->h_addr_list[k], hp->h_length);
+           if (aclMatchIp(acl->data, dst))
+               return 1;
+       }
+       return 0;
+       /* NOTREACHED */
     case ACL_DST_DOMAIN:
-       return aclMatchWord(acl->data, h);
+       /* XXX This probably needs to use matchDomainName() */
+       return aclMatchEndOfWord(acl->data, h);
        /* NOTREACHED */
-       break;
     case ACL_TIME:
        return aclMatchTime(acl->data, squid_curtime);
        /* NOTREACHED */
-       break;
     case ACL_URL_REGEX:
        return aclMatchRegex(acl->data, r);
        /* NOTREACHED */
-       break;
     case ACL_URL_PORT:
        return aclMatchInteger(acl->data, po);
        /* NOTREACHED */
-       break;
     case ACL_USER:
        debug(28, 0, "aclMatchAcl: ACL_USER unimplemented\n");
        return 0;
        /* NOTREACHED */
-       break;
     case ACL_PROTO:
        return aclMatchInteger(acl->data, pr);
        /* NOTREACHED */
-       break;
     case ACL_METHOD:
        return aclMatchInteger(acl->data, m);
        /* NOTREACHED */
-       break;
     case ACL_NONE:
     default:
        debug(28, 0, "aclMatchAcl: '%s' has bad type %d\n",
            acl->name, acl->type);
        return 0;
     }
-    fatal_dump("aclMatchAcl: This should never happen.");
-    return 0;
+    /* NOTREACHED */
 }
 
 static int aclMatchAclList(list, c, m, pr, h, po, r)
@@ -634,6 +779,7 @@ void aclDestroyAcls()
        debug(28, 3, "aclDestroyAcls: '%s'\n", a->cfgline);
        switch (a->type) {
        case ACL_SRC_IP:
+       case ACL_DST_IP:
            aclDestroyIpList(a->data);
            break;
        case ACL_DST_DOMAIN:
index bfd63bc4a113ccada00bab078602f16f49ae5b3d..d1fd9ba395d70014de6e60a2a16926a4acb0db38 100644 (file)
@@ -1,6 +1,107 @@
-/* $Id: cache_cf.cc,v 1.55 1996/05/03 22:56:21 wessels Exp $ */
+/*
+ * $Id: cache_cf.cc,v 1.56 1996/07/09 03:41:19 wessels Exp $
+ *
+ * DEBUG: section 3     Configuration File Parsing
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
-/* DEBUG: Section 3             cache_cf: Configuration file parsing */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
@@ -18,7 +119,7 @@ static struct {
        int maxObjSize;
        int defaultTtl;
        char *relayHost;
-       int relayPort;
+       u_short relayPort;
     } Wais;
     int negativeTtl;
     int negativeDnsTtl;
@@ -33,8 +134,8 @@ static struct {
     int maxRequestSize;
     double hotVmFactor;
     struct {
-       int ascii;
-       int udp;
+       u_short http;
+       u_short icp;
     } Port;
     struct {
        char *log;
@@ -60,7 +161,7 @@ static struct {
     struct {
        char *host;
        char *prefix;
-       int port;
+       u_short port;
        int withProxy;
     } Accel;
     char *appendDomain;
@@ -70,15 +171,21 @@ static struct {
     char *ftpUser;
     struct {
        char *host;
-       int port;
+       u_short port;
        char *file;
        int rate;
     } Announce;
+    struct {
+       struct in_addr tcp_incoming;
+       struct in_addr tcp_outgoing;
+       struct in_addr udp_incoming;
+       struct in_addr udp_outgoing;
+    } Addrs;
     wordlist *cache_dirs;
     wordlist *http_stoplist;
     wordlist *gopher_stoplist;
     wordlist *ftp_stoplist;
-    wordlist *bind_addr_list;
+    wordlist *hierarchy_stoplist;
     wordlist *local_domain_list;
     wordlist *inside_firewall_list;
     wordlist *dns_testname_list;
@@ -91,16 +198,16 @@ static struct {
 #define DefaultSwapHighWaterMark 90    /* 90% */
 #define DefaultSwapLowWaterMark  75    /* 75% */
 
-#define DefaultFtpDefaultTtl   (7 * 24 * 60 * 60)      /* 1 week */
+#define DefaultFtpDefaultTtl   (3 * 24 * 60 * 60)      /* 3 days */
 #define DefaultFtpMaxObjSize   (4 << 20)       /* 4 MB */
-#define DefaultGopherDefaultTtl        (7 * 24 * 60 * 60)      /* 1 week */
+#define DefaultGopherDefaultTtl        (3 * 24 * 60 * 60)      /* 3 days */
 #define DefaultGopherMaxObjSize        (4 << 20)       /* 4 MB */
-#define DefaultHttpDefaultTtl  (7 * 24 * 60 * 60)      /* 1 week */
+#define DefaultHttpDefaultTtl  (3 * 24 * 60 * 60)      /* 3 days */
 #define DefaultHttpMaxObjSize  (4 << 20)       /* 4 MB */
-#define DefaultWaisDefaultTtl  (7 * 24 * 60 * 60)      /* 1 week */
+#define DefaultWaisDefaultTtl  (3 * 24 * 60 * 60)      /* 3 days */
 #define DefaultWaisMaxObjSize  (4 << 20)       /* 4 MB */
 #define DefaultWaisRelayHost   (char *)NULL
-#define DefaultWaisRelayPort   -1
+#define DefaultWaisRelayPort   0
 
 #define DefaultNegativeTtl     (5 * 60)        /* 5 min */
 #define DefaultNegativeDnsTtl  (2 * 60)        /* 2 min */
@@ -112,12 +219,11 @@ static struct {
 #define DefaultDefaultAgeMax   (3600 * 24 * 30)        /* 30 days */
 #define DefaultCleanRate       -1      /* disabled */
 #define DefaultDnsChildren     5       /* 3 processes */
-#define DefaultDnsChildrenMax  32      /* 32 processes */
 #define DefaultMaxRequestSize  (100 << 10)     /* 100Kb */
 #define DefaultHotVmFactor     0.0     /* disabled */
 
-#define DefaultAsciiPortNum    CACHE_HTTP_PORT
-#define DefaultUdpPortNum      CACHE_ICP_PORT
+#define DefaultHttpPortNum     CACHE_HTTP_PORT
+#define DefaultIcpPortNum      CACHE_ICP_PORT
 
 #define DefaultCacheLogFile    DEFAULT_CACHE_LOG
 #define DefaultAccessLogFile   DEFAULT_ACCESS_LOG
@@ -149,9 +255,14 @@ static struct {
 #define DefaultAnnounceHost    "sd.cache.nlanr.net"
 #define DefaultAnnouncePort    3131
 #define DefaultAnnounceFile    (char *)NULL    /* default NONE */
-#define DefaultAnnounceRate    86400   /* every 24 hours */
+#define DefaultAnnounceRate    0       /* Default off */
+#define DefaultTcpIncomingAddr INADDR_ANY
+#define DefaultTcpOutgoingAddr INADDR_NONE
+#define DefaultUdpIncomingAddr INADDR_ANY
+#define DefaultUdpOutgoingAddr INADDR_NONE
 
 ip_acl *local_ip_list = NULL;
+ip_acl *firewall_ip_list = NULL;
 
 int zap_disk_store = 0;                /* off, try to rebuild from disk */
 int httpd_accel_mode = 0;      /* for fast access */
@@ -163,6 +274,7 @@ char *DefaultSwapDir = DEFAULT_SWAP_DIR;
 char *DefaultConfigFile = DEFAULT_CONFIG_FILE;
 char *ConfigFile = NULL;       /* the whole thing */
 char *cfg_filename = NULL;     /* just the last part */
+char ForwardedBy[256];
 
 char w_space[] = " \t\n";
 char config_input_line[BUFSIZ];
@@ -171,6 +283,7 @@ int config_lineno = 0;
 static void configSetFactoryDefaults _PARAMS((void));
 static void configFreeMemory _PARAMS((void));
 static void configDoConfigure _PARAMS((void));
+static char *safe_xstrdup _PARAMS((char *p));
 static char fatal_str[BUFSIZ];
 
 void self_destruct()
@@ -245,7 +358,7 @@ void addToIPACL(list, ip_str, access)
     }
     if (!(*list)) {
        /* empty list */
-       *list = (ip_acl *) xcalloc(1, sizeof(ip_acl));
+       *list = xcalloc(1, sizeof(ip_acl));
        (*list)->next = NULL;
        q = *list;
     } else {
@@ -253,7 +366,7 @@ void addToIPACL(list, ip_str, access)
        p = *list;
        while (p->next)
            p = p->next;
-       q = (ip_acl *) xcalloc(1, sizeof(ip_acl));
+       q = xcalloc(1, sizeof(ip_acl));
        q->next = NULL;
        p->next = q;
     }
@@ -330,14 +443,14 @@ void wordlistAdd(list, key)
 
     if (!(*list)) {
        /* empty list */
-       *list = (wordlist *) xcalloc(1, sizeof(wordlist));
+       *list = xcalloc(1, sizeof(wordlist));
        (*list)->key = xstrdup(key);
        (*list)->next = NULL;
     } else {
        p = *list;
        while (p->next)
            p = p->next;
-       q = (wordlist *) xcalloc(1, sizeof(wordlist));
+       q = xcalloc(1, sizeof(wordlist));
        q->key = xstrdup(key);
        q->next = NULL;
        p->next = q;
@@ -364,7 +477,7 @@ void intlistDestroy(list)
 
 #define GetInteger(var) \
        token = strtok(NULL, w_space); \
-       if( token == (char *) NULL) \
+       if( token == NULL) \
                self_destruct(); \
        if (sscanf(token, "%d", &var) != 1) \
                self_destruct();
@@ -375,10 +488,11 @@ static void parseCacheHostLine()
     char *type = NULL;
     char *hostname = NULL;
     char *token = NULL;
-    int ascii_port = CACHE_HTTP_PORT;
-    int udp_port = CACHE_ICP_PORT;
-    int proxy_only = 0;
+    u_short http_port = CACHE_HTTP_PORT;
+    u_short icp_port = CACHE_ICP_PORT;
+    int options = 0;
     int weight = 1;
+    int i;
 
     /* Parse a cache_host line */
     if (!(hostname = strtok(NULL, w_space)))
@@ -386,11 +500,15 @@ static void parseCacheHostLine()
     if (!(type = strtok(NULL, w_space)))
        self_destruct();
 
-    GetInteger(ascii_port);
-    GetInteger(udp_port);
+    GetInteger(i);
+    http_port = (u_short) i;
+    GetInteger(i);
+    icp_port = (u_short) i;
     while ((token = strtok(NULL, w_space))) {
        if (!strcasecmp(token, "proxy-only")) {
-           proxy_only = 1;
+           options |= NEIGHBOR_PROXY_ONLY;
+       } else if (!strcasecmp(token, "no-query")) {
+           options |= NEIGHBOR_NO_QUERY;
        } else if (!strncasecmp(token, "weight=", 7)) {
            weight = atoi(token + 7);
        } else {
@@ -400,20 +518,27 @@ static void parseCacheHostLine()
     }
     if (weight < 1)
        weight = 1;
-    neighbors_cf_add(hostname, type, ascii_port, udp_port, proxy_only, weight);
+    neighbors_cf_add(hostname, type, http_port, icp_port, options, weight);
 }
 
 static void parseHostDomainLine()
 {
     char *host = NULL;
     char *domain = NULL;
+    if (!(host = strtok(NULL, w_space)))
+       self_destruct();
+    while ((domain = strtok(NULL, ", \t\n")))
+       neighbors_cf_domain(host, domain);
+}
 
+static void parseHostAclLine()
+{
+    char *host = NULL;
+    char *aclname = NULL;
     if (!(host = strtok(NULL, w_space)))
        self_destruct();
-    while ((domain = strtok(NULL, ", \t\n"))) {
-       if (neighbors_cf_domain(host, domain) == 0)
-           self_destruct();
-    }
+    while ((aclname = strtok(NULL, ", \t\n")))
+       neighbors_cf_acl(host, aclname);
 }
 
 
@@ -422,7 +547,7 @@ static void parseSourcePingLine()
     char *srcping;
 
     srcping = strtok(NULL, w_space);
-    if (srcping == (char *) NULL)
+    if (srcping == NULL)
        self_destruct();
 
     /* set source_ping, default is off. */
@@ -440,7 +565,7 @@ static void parseQuickAbortLine()
     char *abort;
 
     abort = strtok(NULL, w_space);
-    if (abort == (char *) NULL)
+    if (abort == NULL)
        self_destruct();
 
     if (!strcasecmp(abort, "on") || !strcasecmp(abort, "quick"))
@@ -482,7 +607,7 @@ static void parseHotVmFactorLine()
     double d;
 
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     if (sscanf(token, "%lf", &d) != 1)
        self_destruct();
@@ -555,7 +680,7 @@ static void parseTTLPattern()
     int i;
 
     token = strtok(NULL, w_space);     /* token: regex pattern */
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     pattern = xstrdup(token);
 
@@ -662,7 +787,7 @@ static void parseMgrLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.adminEmail);
     Config.adminEmail = xstrdup(token);
@@ -673,7 +798,7 @@ static void parseDirLine()
     char *token;
 
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     wordlistAdd(&Config.cache_dirs, token);
 }
@@ -681,11 +806,11 @@ static void parseDirLine()
 static void parseHttpdAccelLine()
 {
     char *token;
-    char buf[1024];
+    static char buf[BUFSIZ];
     int i;
 
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Accel.host);
     Config.Accel.host = xstrdup(token);
@@ -702,7 +827,7 @@ static void parseHttpdAccelWithProxyLine()
     char *proxy;
 
     proxy = strtok(NULL, w_space);
-    if (proxy == (char *) NULL)
+    if (proxy == NULL)
        self_destruct();
 
     /* set httpd_accel_with_proxy, default is off. */
@@ -719,14 +844,14 @@ static void parseEffectiveUserLine()
     char *token;
 
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.effectiveUser);
     safe_free(Config.effectiveGroup);
     Config.effectiveUser = xstrdup(token);
 
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        return;                 /* group is optional */
     Config.effectiveGroup = xstrdup(token);
 }
@@ -735,7 +860,7 @@ static void parseLogLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Log.log);
     Config.Log.log = xstrdup(token);
@@ -745,7 +870,7 @@ static void parseAccessLogLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Log.access);
     Config.Log.access = xstrdup(token);
@@ -755,7 +880,7 @@ static void parseHierachyLogLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Log.hierarchy);
     Config.Log.hierarchy = xstrdup(token);
@@ -765,7 +890,7 @@ static void parseStoreLogLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Log.store);
     Config.Log.store = xstrdup(token);
@@ -783,7 +908,7 @@ static void parseFtpProgramLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Program.ftpget);
     Config.Program.ftpget = xstrdup(token);
@@ -793,7 +918,7 @@ static void parseFtpOptionsLine()
 {
     char *token;
     token = strtok(NULL, "");  /* Note "", don't separate these */
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Program.ftpget_opts);
     Config.Program.ftpget_opts = xstrdup(token);
@@ -803,7 +928,7 @@ static void parseDnsProgramLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Program.dnsserver);
     Config.Program.dnsserver = xstrdup(token);
@@ -813,7 +938,7 @@ static void parseEmulateLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
        Config.commonLogFormat = 1;
@@ -826,21 +951,22 @@ static void parseWAISRelayLine()
     char *token;
     int i;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Wais.relayHost);
     Config.Wais.relayHost = xstrdup(token);
     GetInteger(i);
-    Config.Wais.relayPort = i;
+    Config.Wais.relayPort = (u_short) i;
     GetInteger(i);
     Config.Wais.maxObjSize = i << 20;
 }
 
-static void parseLocalIPLine()
+static void parseIPLine(list)
+     ip_acl **list;
 {
     char *token;
     while ((token = strtok(NULL, w_space))) {
-       addToIPACL(&local_ip_list, token, IP_DENY);
+       addToIPACL(list, token, IP_DENY);
     }
 }
 
@@ -848,7 +974,7 @@ static void parseHttpStopLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        return;
     wordlistAdd(&Config.http_stoplist, token);
 }
@@ -857,7 +983,7 @@ static void parseGopherStopLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        return;
     wordlistAdd(&Config.gopher_stoplist, token);
 }
@@ -865,16 +991,22 @@ static void parseFtpStopLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        return;
     wordlistAdd(&Config.ftp_stoplist, token);
 }
+static void parseHierarchyStoplistLine()
+{
+    char *token;
+    while ((token = strtok(NULL, w_space)))
+       wordlistAdd(&Config.hierarchy_stoplist, token);
+}
 
 static void parseAppendDomainLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     if (*token != '.')
        self_destruct();
@@ -882,20 +1014,26 @@ static void parseAppendDomainLine()
     Config.appendDomain = xstrdup(token);
 }
 
-static void parseBindAddressLine()
+static void parseAddressLine(addr)
+     struct in_addr *addr;
 {
     char *token;
+    struct hostent *hp = NULL;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
+       self_destruct();
+    if (inet_addr(token) != INADDR_NONE)
+       (*addr).s_addr = inet_addr(token);
+    else if ((hp = gethostbyname(token)))
+       xmemcpy(addr, hp->h_addr, hp->h_length);
+    else
        self_destruct();
-    debug(3, 1, "parseBindAddressLine: adding %s\n", token);
-    wordlistAdd(&Config.bind_addr_list, token);
 }
 
 static void parseLocalDomainFile(fname)
      char *fname;
 {
-    char tmp_line[BUFSIZ];
+    static char tmp_line[BUFSIZ];
     FILE *fp = NULL;
     char *t = NULL;
 
@@ -949,20 +1087,24 @@ static void parseDnsTestnameLine()
     }
 }
 
-static void parseAsciiPortLine()
+static void parseHttpPortLine()
 {
     char *token;
     int i;
     GetInteger(i);
-    Config.Port.ascii = i;
+    if (i < 0)
+       i = 0;
+    Config.Port.http = (u_short) i;
 }
 
-static void parseUdpPortLine()
+static void parseIcpPortLine()
 {
     char *token;
     int i;
     GetInteger(i);
-    Config.Port.udp = i;
+    if (i < 0)
+       i = 0;
+    Config.Port.icp = (u_short) i;
 }
 
 static void parseNeighborTimeout()
@@ -977,7 +1119,7 @@ static void parseSingleParentBypassLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     if (!strcasecmp(token, "on"))
        Config.singleParentBypass = 1;
@@ -988,7 +1130,7 @@ static void parseDebugOptionsLine()
     char *token;
     token = strtok(NULL, "");  /* Note "", don't separate these */
     safe_free(Config.debugOptions);
-    if (token == (char *) NULL) {
+    if (token == NULL) {
        Config.debugOptions = NULL;
        return;
     }
@@ -1000,7 +1142,7 @@ static void parsePidFilenameLine()
     char *token;
     token = strtok(NULL, w_space);
     safe_free(Config.pidFilename);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     Config.pidFilename = xstrdup(token);
 }
@@ -1010,7 +1152,7 @@ static void parseVisibleHostnameLine()
     char *token;
     token = strtok(NULL, w_space);
     safe_free(Config.visibleHostname);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     Config.visibleHostname = xstrdup(token);
 }
@@ -1019,7 +1161,7 @@ static void parseFtpUserLine()
 {
     char *token;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.ftpUser);
     Config.ftpUser = xstrdup(token);
@@ -1038,7 +1180,7 @@ static void parseAnnounceToLine()
     char *token;
     int i;
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        self_destruct();
     safe_free(Config.Announce.host);
     Config.Announce.host = xstrdup(token);
@@ -1048,7 +1190,7 @@ static void parseAnnounceToLine()
            Config.Announce.port = i;
     }
     token = strtok(NULL, w_space);
-    if (token == (char *) NULL)
+    if (token == NULL)
        return;
     safe_free(Config.Announce.file);
     Config.Announce.file = xstrdup(token);
@@ -1098,6 +1240,8 @@ int parseConfigFile(file_name)
        /* Parse a cache_host_domain line */
        else if (!strcmp(token, "cache_host_domain"))
            parseHostDomainLine();
+       else if (!strcmp(token, "cache_host_acl"))
+           parseHostAclLine();
 
        /* Parse a neighbor_timeout line */
        else if (!strcmp(token, "neighbor_timeout"))
@@ -1195,18 +1339,19 @@ int parseConfigFile(file_name)
        else if (!strcmp(token, "ftp_stop"))
            parseFtpStopLine();
 
+       /* Parse a hierarchy_stoplist line */
+       else if (!strcmp(token, "hierarchy_stoplist"))
+           parseHierarchyStoplistLine();
+
        /* Parse a gopher protocol line */
-       /* XXX: Must go after any gopher* token */
        else if (!strcmp(token, "gopher"))
            parseGopherLine();
 
        /* Parse a http protocol line */
-       /* XXX: Must go after any http* token */
        else if (!strcmp(token, "http"))
            parseHttpLine();
 
        /* Parse a ftp protocol line */
-       /* XXX: Must go after any ftp* token */
        else if (!strcmp(token, "ftp"))
            parseFtpLine();
 
@@ -1283,25 +1428,41 @@ int parseConfigFile(file_name)
        else if (!strcmp(token, "wais_relay"))
            parseWAISRelayLine();
 
-       /* Parse a local_ip line */
        else if (!strcmp(token, "local_ip"))
-           parseLocalIPLine();
+           parseIPLine(&local_ip_list);
+
+       else if (!strcmp(token, "firewall_ip"))
+           parseIPLine(&firewall_ip_list);
 
        /* Parse a local_domain line */
        else if (!strcmp(token, "local_domain"))
            parseLocalDomainLine();
 
-       /* Parse a bind_address line */
+       else if (!strcmp(token, "tcp_incoming_address"))
+           parseAddressLine(&Config.Addrs.tcp_incoming);
+
+       else if (!strcmp(token, "tcp_outgoing_address"))
+           parseAddressLine(&Config.Addrs.tcp_outgoing);
+
+       else if (!strcmp(token, "udp_incoming_address"))
+           parseAddressLine(&Config.Addrs.udp_incoming);
+
+       else if (!strcmp(token, "udp_outgoing_address"))
+           parseAddressLine(&Config.Addrs.udp_outgoing);
+
        else if (!strcmp(token, "bind_address"))
-           parseBindAddressLine();
+           parseAddressLine(&Config.Addrs.tcp_incoming);
+
+       else if (!strcmp(token, "outbound_address"))
+           parseAddressLine(&Config.Addrs.tcp_outgoing);
 
-       /* Parse a ascii_port line */
-       else if (!strcmp(token, "ascii_port"))
-           parseAsciiPortLine();
+       /* Parse a http_port line */
+       else if (!strcmp(token, "http_port") || !strcmp(token, "ascii_port"))
+           parseHttpPortLine();
 
-       /* Parse a udp_port line */
-       else if (!strcmp(token, "udp_port"))
-           parseUdpPortLine();
+       /* Parse a icp_port line */
+       else if (!strcmp(token, "icp_port") || !strcmp(token, "udp_port"))
+           parseIcpPortLine();
 
        else if (!strcmp(token, "inside_firewall"))
            parseInsideFirewallLine();
@@ -1338,9 +1499,6 @@ int parseConfigFile(file_name)
        }
     }
 
-    /* Add INADDR_ANY to end of bind_addr_list as last chance */
-    wordlistAdd(&Config.bind_addr_list, "0.0.0.0");
-
     /* Sanity checks */
     if (getClientLifetime() < getReadTimeout()) {
        printf("WARNING: client_lifetime (%d seconds) is less than read_timeout (%d seconds).\n",
@@ -1408,7 +1566,7 @@ char *getWaisRelayHost()
 {
     return Config.Wais.relayHost;
 }
-int getWaisRelayPort()
+u_short getWaisRelayPort()
 {
     return Config.Wais.relayPort;
 }
@@ -1502,6 +1660,10 @@ char *getAccelPrefix()
 {
     return Config.Accel.prefix;
 }
+u_short getAccelPort()
+{
+    return Config.Accel.port;
+}
 int getAccelWithProxy()
 {
     return Config.Accel.withProxy;
@@ -1526,13 +1688,13 @@ char *getCacheLogFile()
 {
     return Config.Log.log;
 }
-int getAsciiPortNum()
+u_short getHttpPortNum()
 {
-    return Config.Port.ascii;
+    return Config.Port.http;
 }
-int getUdpPortNum()
+u_short getIcpPortNum()
 {
-    return Config.Port.udp;
+    return Config.Port.icp;
 }
 char *getDnsProgram()
 {
@@ -1586,7 +1748,7 @@ char *getAnnounceHost()
 {
     return Config.Announce.host;
 }
-int getAnnouncePort()
+u_short getAnnouncePort()
 {
     return Config.Announce.port;
 }
@@ -1606,6 +1768,10 @@ wordlist *getFtpStoplist()
 {
     return Config.ftp_stoplist;
 }
+wordlist *getHierarchyStoplist()
+{
+    return Config.hierarchy_stoplist;
+}
 wordlist *getGopherStoplist()
 {
     return Config.gopher_stoplist;
@@ -1626,33 +1792,39 @@ wordlist *getDnsTestnameList()
 {
     return Config.dns_testname_list;
 }
-wordlist *getBindAddrList()
+struct in_addr getTcpIncomingAddr()
 {
-    return Config.bind_addr_list;
+    return Config.Addrs.tcp_incoming;
 }
-
-int setAsciiPortNum(p)
-     int p;
+struct in_addr getTcpOutgoingAddr()
 {
-    return (Config.Port.ascii = p);
+    return Config.Addrs.tcp_outgoing;
 }
-int setUdpPortNum(p)
-     int p;
+struct in_addr getUdpIncomingAddr()
 {
-    return (Config.Port.udp = p);
+    return Config.Addrs.udp_incoming;
+}
+struct in_addr getUdpOutgoingAddr()
+{
+    return Config.Addrs.udp_outgoing;
 }
 
-
-char *safe_xstrdup(p)
-     char *p;
+u_short setHttpPortNum(port)
+     u_short port;
 {
-    return p ? xstrdup(p) : p;
+    return (Config.Port.http = port);
 }
+u_short setIcpPortNum(port)
+     u_short port;
+{
+    return (Config.Port.icp = port);
+}
+
 
-int safe_strlen(p)
+static char *safe_xstrdup(p)
      char *p;
 {
-    return p ? strlen(p) : -1;
+    return p ? xstrdup(p) : p;
 }
 
 static void configFreeMemory()
@@ -1681,7 +1853,7 @@ static void configFreeMemory()
     wordlistDestroy(&Config.http_stoplist);
     wordlistDestroy(&Config.gopher_stoplist);
     wordlistDestroy(&Config.ftp_stoplist);
-    wordlistDestroy(&Config.bind_addr_list);
+    wordlistDestroy(&Config.hierarchy_stoplist);
     wordlistDestroy(&Config.local_domain_list);
     wordlistDestroy(&Config.inside_firewall_list);
     wordlistDestroy(&Config.dns_testname_list);
@@ -1732,8 +1904,8 @@ static void configSetFactoryDefaults()
     Config.effectiveGroup = safe_xstrdup(DefaultEffectiveGroup);
     Config.appendDomain = safe_xstrdup(DefaultAppendDomain);
 
-    Config.Port.ascii = DefaultAsciiPortNum;
-    Config.Port.udp = DefaultUdpPortNum;
+    Config.Port.http = DefaultHttpPortNum;
+    Config.Port.icp = DefaultIcpPortNum;
     Config.Log.log = safe_xstrdup(DefaultCacheLogFile);
     Config.Log.access = safe_xstrdup(DefaultAccessLogFile);
     Config.Log.hierarchy = safe_xstrdup(DefaultHierarchyLogFile);
@@ -1753,6 +1925,10 @@ static void configSetFactoryDefaults()
     Config.Announce.port = DefaultAnnouncePort;
     Config.Announce.file = safe_xstrdup(DefaultAnnounceFile);
     Config.Announce.rate = DefaultAnnounceRate;
+    Config.Addrs.tcp_outgoing.s_addr = DefaultTcpOutgoingAddr;
+    Config.Addrs.tcp_incoming.s_addr = DefaultTcpIncomingAddr;
+    Config.Addrs.udp_outgoing.s_addr = DefaultUdpOutgoingAddr;
+    Config.Addrs.udp_incoming.s_addr = DefaultUdpIncomingAddr;
 }
 
 static void configDoConfigure()
@@ -1762,6 +1938,9 @@ static void configDoConfigure()
     neighbor_timeout = (time_t) Config.neighborTimeout;
     single_parent_bypass = Config.singleParentBypass;
     DnsPositiveTtl = Config.positiveDnsTtl;
+    sprintf(ForwardedBy, "Forwarded: by http://%s:%d/",
+       getMyHostname(), getHttpPortNum());
+
 
 #if !ALLOW_HOT_CACHE
     if (!httpd_accel_mode || Config.Accel.withProxy) {
index 68b8533e4eba5f3db644ece231138e595059d0a4..3cdb6bca7703f714245063614362bd2888b6ca0b 100644 (file)
-/* $Id: cachemgr.cc,v 1.9 1996/05/03 22:56:22 wessels Exp $ */
+/*
+ * $Id: cachemgr.cc,v 1.10 1996/07/09 03:41:19 wessels Exp $
+ *
+ * DEBUG: Section 0     CGI Cache Manager
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "config.h"
-#include "autoconf.h"
-#include "version.h"
 
+#if HAVE_UNISTD_H
 #include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
 #include <stdlib.h>
+#endif
+#if HAVE_STDIO_H
 #include <stdio.h>
+#endif
+#if HAVE_SYS_TYPES_H
 #include <sys/types.h>
+#endif
+#if HAVE_CTYPE_H
 #include <ctype.h>
+#endif
+#if HAVE_ERRNO_H
 #include <errno.h>
+#endif
+#if HAVE_FCNTL_H
 #include <fcntl.h>
+#endif
+#if HAVE_GRP_H
 #include <grp.h>
-#ifndef _SQUID_FREEBSD_                /* "Obsolete" Markus Stumpf <maex@Space.NET> */
+#endif
+#if HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
 #include <malloc.h>
 #endif
+#if HAVE_MEMORY_H
 #include <memory.h>
+#endif
+#if HAVE_NETDB_H && !defined(_SQUID_NETDB_H_)  /* protect NEXTSTEP */
+#define _SQUID_NETDB_H_
 #include <netdb.h>
+#endif
+#if HAVE_PWD_H
 #include <pwd.h>
+#endif
+#if HAVE_SIGNAL_H
 #include <signal.h>
+#endif
+#if HAVE_TIME_H
 #include <time.h>
+#endif
+#if HAVE_SYS_PARAM_H
 #include <sys/param.h>
+#endif
+#if HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
+#if HAVE_SYS_RESOURCE_H
 #include <sys/resource.h>      /* needs sys/time.h above it */
+#endif
+#if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
 #include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
 #include <arpa/inet.h>
+#endif
+#if HAVE_SYS_STAT_H
 #include <sys/stat.h>
+#endif
+#if HAVE_SYS_UN_H
 #include <sys/un.h>
+#endif
+#if HAVE_SYS_WAIT_H
 #include <sys/wait.h>
-
-#ifdef HAVE_STRING_H
+#endif
+#if HAVE_LIBC_H
+#include <libc.h>
+#endif
+#if HAVE_STRING_H
 #include <string.h>
 #endif
-
-#ifdef HAVE_STRINGS_H
+#if HAVE_STRINGS_H
 #include <strings.h>
 #endif
-
 #if HAVE_BSTRING_H
 #include <bstring.h>
 #endif
-
-#ifdef HAVE_CRYPT_H
+#if HAVE_CRYPT_H
 #include <crypt.h>
 #endif
-
 #if HAVE_SYS_SELECT_H
 #include <sys/select.h>
 #endif
@@ -74,6 +218,7 @@ typedef enum {
     STATS_O,
     STATS_VM,
     STATS_U,
+    STATS_IO,
     SHUTDOWN,
     REFRESH,
 #ifdef REMOVE_OBJECT
@@ -93,6 +238,7 @@ static char *op_cmds[] =
     "stats/objects",
     "stats/vm_objects",
     "stats/utilization",
+    "stats/io",
     "shutdown",
     "<refresh>",
 #ifdef REMOVE_OBJECT
@@ -158,6 +304,7 @@ void noargs_html()
     printf("<OPTION VALUE=\"log\">Cache Log\n");
 #endif
     printf("<OPTION VALUE=\"stats/utilization\">Utilization\n");
+    printf("<OPTION VALUE=\"stats/io\">I/O\n");
     printf("<OPTION VALUE=\"stats/objects\">Objects\n");
     printf("<OPTION VALUE=\"stats/vm_objects\">VM_Objects\n");
     printf("<OPTION VALUE=\"server_list\">Cache Server List\n");
@@ -179,7 +326,7 @@ void noargs_html()
 char *makeword(char *line, char stop)
 {
     int x = 0, y;
-    char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));
+    char *word = xmalloc(sizeof(char) * (strlen(line) + 1));
 
     for (x = 0; ((line[x]) && (line[x] != stop)); x++)
        word[x] = line[x];
@@ -196,20 +343,17 @@ char *makeword(char *line, char stop)
 /* A utility function from the NCSA httpd cgi-src utils.c */
 char *fmakeword(FILE * f, char stop, int *cl)
 {
-    int wsize;
-    char *word;
-    int ll;
-
-    wsize = 102400;
-    ll = 0;
-    word = (char *) malloc(sizeof(char) * (wsize + 1));
+    int wsize = 102400;
+    char *word = NULL;
+    int ll = 0;
 
+    word = xmalloc(sizeof(char) * (wsize + 1));
     for (;;) {
        word[ll] = (char) fgetc(f);
        if (ll == wsize) {
            word[ll + 1] = '\0';
            wsize += 102400;
-           word = (char *) realloc(word, sizeof(char) * (wsize + 1));
+           word = realloc(word, sizeof(char) * (wsize + 1));
        }
        --(*cl);
        if ((word[ll] == stop) || (feof(f)) || (!(*cl))) {
@@ -226,7 +370,7 @@ char *fmakeword(FILE * f, char stop, int *cl)
 /* A utility function from the NCSA httpd cgi-src utils.c */
 char x2c(char *what)
 {
-    register char digit;
+    char digit;
 
     digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
     digit *= 16;
@@ -237,7 +381,7 @@ char x2c(char *what)
 /* A utility function from the NCSA httpd cgi-src utils.c */
 void unescape_url(char *url)
 {
-    register int x, y;
+    int x, y;
 
     for (x = 0, y = 0; url[y]; ++x, ++y) {
        if ((url[x] = url[y]) == '%') {
@@ -251,7 +395,7 @@ void unescape_url(char *url)
 /* A utility function from the NCSA httpd cgi-src utils.c */
 void plustospace(char *str)
 {
-    register int x;
+    int x;
 
     for (x = 0; str[x]; x++)
        if (str[x] == '+')
@@ -379,6 +523,7 @@ int main(int argc, char *argv[])
     printf("Content-type: text/html\r\n\r\n");
     if ((agent = getenv("HTTP_USER_AGENT")) != NULL) {
        if (!strncasecmp(agent, "Mozilla", 7) ||
+           !strncasecmp(agent, "OmniWeb/2", 9) ||
            !strncasecmp(agent, "Netscape", 8)) {
            hasTables = TRUE;
        }
@@ -454,6 +599,9 @@ int main(int argc, char *argv[])
     } else if (!strcmp(operation, "stats/utilization") ||
        !strcmp(operation, "Utilization")) {
        op = STATS_U;
+    } else if (!strcmp(operation, "stats/io") ||
+       !strcmp(operation, "I/O")) {
+       op = STATS_IO;
     } else if (!strcmp(operation, "shutdown")) {
        op = SHUTDOWN;
     } else if (!strcmp(operation, "refresh")) {
@@ -477,6 +625,7 @@ int main(int argc, char *argv[])
     case STATS_O:
     case STATS_VM:
     case STATS_U:
+    case STATS_IO:
        sprintf(msg, "GET cache_object://%s/%s HTTP/1.0\r\n\r\n",
            hostname, op_cmds[op]);
        break;
@@ -515,6 +664,7 @@ int main(int argc, char *argv[])
     printf("<OPTION VALUE=\"log\">Cache Log\n");
 #endif
     printf("<OPTION VALUE=\"stats/utilization\">Utilization\n");
+    printf("<OPTION VALUE=\"stats/io\">I/O\n");
     printf("<OPTION VALUE=\"stats/objects\">Objects\n");
     printf("<OPTION VALUE=\"stats/vm_objects\">VM_Objects\n");
     printf("<OPTION VALUE=\"server_list\">Cache Server List\n");
@@ -559,6 +709,7 @@ int main(int argc, char *argv[])
     case STATS_G:
     case STATS_O:
     case STATS_VM:
+    case STATS_IO:
     case SHUTDOWN:
     case REFRESH:
        break;
@@ -621,6 +772,7 @@ int main(int argc, char *argv[])
                case SERVER:
                case LOG:
                case STATS_G:
+               case STATS_IO:
                case SHUTDOWN:
                    p_state = 1;
                    printf("%s", reserve);
@@ -684,7 +836,7 @@ int main(int argc, char *argv[])
 static int client_comm_connect(sock, dest_host, dest_port)
      int sock;                 /* Type of communication to use. */
      char *dest_host;          /* Server's host name. */
-     int dest_port;            /* Server's port. */
+     u_short dest_port;                /* Server's port. */
 {
     struct hostent *hp;
     static struct sockaddr_in to_addr;
@@ -695,7 +847,7 @@ static int client_comm_connect(sock, dest_host, dest_port)
     if ((hp = gethostbyname(dest_host)) == 0) {
        return (-1);
     }
-    memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
+    xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
     to_addr.sin_port = htons(dest_port);
     return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in));
 }
index 6e772e86be6f6a5bb53a046121cc2235ffd20a23..913a9f370b5e11d19ed89f6fac6a4e74176a2238 100644 (file)
@@ -1,5 +1,108 @@
 
-/* $Id: client.cc,v 1.6 1996/05/03 22:56:22 wessels Exp $ */
+/*
+ * $Id: client.cc,v 1.7 1996/07/09 03:41:20 wessels Exp $
+ *
+ * DEBUG: section 0     WWW Client
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
@@ -15,13 +118,14 @@ static void usage(progname)
      char *progname;
 {
     fprintf(stderr, "\
-Usage: %s [-rs] [-h host] [-p port] url\n\
+Usage: %s [-rs] [-i IMS_time] [-h host] [-p port] [-m method] url\n\
 Options:\n\
     -r         Force cache to reload URL.\n\
     -s         Silent.  Do not print data to stdout.\n\
+    -i IMS     If-Modified-Since time (in Epoch seconds).\n\
     -h host    Retrieve URL from cache on hostname.  Default is localhost.\n\
     -p port    Port number of cache.  Default is %d.\n\
-    -m method  Request method, default is GET\n\
+    -m method  Request method, default is GET.\n\
 ", progname, CACHE_HTTP_PORT);
     exit(1);
 }
@@ -134,7 +238,7 @@ int main(argc, argv)
 static int client_comm_connect(sock, dest_host, dest_port)
      int sock;                 /* Type of communication to use. */
      char *dest_host;          /* Server's host name. */
-     int dest_port;            /* Server's port. */
+     u_short dest_port;                /* Server's port. */
 {
     struct hostent *hp;
     static struct sockaddr_in to_addr;
@@ -145,7 +249,7 @@ static int client_comm_connect(sock, dest_host, dest_port)
     if ((hp = gethostbyname(dest_host)) == 0) {
        return (-1);
     }
-    memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
+    xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
     to_addr.sin_port = htons(dest_port);
     return connect(sock, (struct sockaddr *) &to_addr, sizeof(struct sockaddr_in));
 }
index 32aa7389559705df40440378e3869fcfb354b213..8bdf4aea65e829643cadc865cacf136135e5249d 100644 (file)
 
-/* $Id: comm.cc,v 1.32 1996/05/03 22:56:23 wessels Exp $ */
+/*
+ * $Id: comm.cc,v 1.33 1996/07/09 03:41:20 wessels Exp $
+ *
+ * DEBUG: section 5     Socket Functions
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
-/* DEBUG: Section 5             comm: socket level functions */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
 
 /* Block processing new client requests (accepts on ascii port) when we start
  * running shy of free file descriptors.  For example, under SunOS, we'll keep
  * 64 file descriptors free for disk-i/o and connections to remote servers */
 
 int RESERVED_FD = 64;
+struct in_addr any_addr;
 
 #define min(x,y) ((x)<(y)? (x) : (y))
 #define max(a,b) ((a)>(b)? (a) : (b))
 
+struct _RWStateData {
+    char *buf;
+    long size;
+    long offset;
+    int timeout;               /* XXX Not used at present. */
+    time_t time;               /* XXX Not used at present. */
+    rw_complete_handler *handler;
+    void *handler_data;
+    int handle_immed;
+};
 
 /* GLOBAL */
 FD_ENTRY *fd_table = NULL;     /* also used in disk.c */
 
 /* STATIC */
-static int *fd_lifetime = NULL;
 static void checkTimeouts _PARAMS((void));
 static void checkLifetimes _PARAMS((void));
 static void Reserve_More_FDs _PARAMS((void));
-static int commSetReuseAddr _PARAMS((int));
+static void commSetReuseAddr _PARAMS((int));
 static int examine_select _PARAMS((fd_set *, fd_set *, fd_set *));
-static int commSetNoLinger _PARAMS((int));
-static struct timeval zero_tv;
+static void commSetNoLinger _PARAMS((int));
 static void comm_select_incoming _PARAMS((void));
+static int commBind _PARAMS((int s, struct in_addr, u_short port));
+#ifdef TCP_NODELAY
+static void commSetTcpNoDelay _PARAMS((int));
+#endif
+
+static int *fd_lifetime = NULL;
+static struct timeval zero_tv;
 
 /* Return the local port associated with fd. */
-int comm_port(fd)
+u_short comm_local_port(fd)
      int fd;
 {
     struct sockaddr_in addr;
     int addr_len = 0;
 
-    if (fd_table[fd].port)
-       return fd_table[fd].port;
-
     /* If the fd is closed already, just return */
     if (!fd_table[fd].openned) {
-       debug(5, 0, "comm_port: FD %d has been closed.\n", fd);
-       return (COMM_ERROR);
+       debug(5, 0, "comm_local_port: FD %d has been closed.\n", fd);
+       return 0;
     }
+    if (fd_table[fd].local_port)
+       return fd_table[fd].local_port;
     addr_len = sizeof(addr);
     if (getsockname(fd, (struct sockaddr *) &addr, &addr_len)) {
-       debug(5, 1, "comm_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
-       return (COMM_ERROR);
+       debug(5, 1, "comm_local_port: Failed to retrieve TCP/UDP port number for socket: FD %d: %s\n", fd, xstrerror());
+       return 0;
     }
-    debug(5, 6, "comm_port: FD %d: sockaddr %u.\n", fd, addr.sin_addr.s_addr);
-    fd_table[fd].port = ntohs(addr.sin_port);
-
-    return fd_table[fd].port;
+    debug(5, 6, "comm_local_port: FD %d: sockaddr %u.\n", fd, addr.sin_addr.s_addr);
+    fd_table[fd].local_port = ntohs(addr.sin_port);
+    return fd_table[fd].local_port;
 }
 
-static int do_bind(s, host, port)
+static int commBind(s, in_addr, port)
      int s;
-     char *host;
-     int port;
+     struct in_addr in_addr;
+     u_short port;
 {
     struct sockaddr_in S;
-    struct in_addr *addr = NULL;
 
-    addr = getAddress(host);
-    if (addr == (struct in_addr *) NULL) {
-       debug(5, 0, "do_bind: Unknown host: %s\n", host);
-       return COMM_ERROR;
-    }
     memset(&S, '\0', sizeof(S));
     S.sin_family = AF_INET;
     S.sin_port = htons(port);
-    S.sin_addr = *addr;
-
+    S.sin_addr = in_addr;
     if (bind(s, (struct sockaddr *) &S, sizeof(S)) == 0)
        return COMM_OK;
-
-    debug(5, 0, "do_bind: Cannot bind socket FD %d to %s:%d: %s\n",
+    debug(5, 0, "commBind: Cannot bind socket FD %d to %s:%d: %s\n",
        s,
-       S.sin_addr.s_addr == htonl(INADDR_ANY) ? "*" : inet_ntoa(S.sin_addr),
+       S.sin_addr.s_addr == INADDR_ANY ? "*" : inet_ntoa(S.sin_addr),
        port, xstrerror());
     return COMM_ERROR;
 }
 
 /* Create a socket. Default is blocking, stream (TCP) socket.  IO_TYPE
  * is OR of flags specified in comm.h. */
-int comm_open(io_type, port, handler, note)
+int comm_open(io_type, addr, port, note)
      unsigned int io_type;
-     int port;
-     int (*handler) ();                /* Interrupt handler. */
+     struct in_addr addr;
+     u_short port;
      char *note;
 {
     int new_socket;
     FD_ENTRY *conn = NULL;
     int sock_type = io_type & COMM_DGRAM ? SOCK_DGRAM : SOCK_STREAM;
-    wordlist *p = NULL;
 
     /* Create socket for accepting new connections. */
     if ((new_socket = socket(AF_INET, sock_type, 0)) < 0) {
@@ -114,61 +223,43 @@ int comm_open(io_type, port, handler, note)
        return (COMM_ERROR);
     }
     /* update fdstat */
-    fdstat_open(new_socket, Socket);
+    fdstat_open(new_socket, FD_SOCKET);
 
     conn = &fd_table[new_socket];
     memset(conn, '\0', sizeof(FD_ENTRY));
-    fd_note(new_socket, note);
+    if (note)
+       fd_note(new_socket, note);
     conn->openned = 1;
 
-    if (fcntl(new_socket, F_SETFD, 1) < 0) {
-       debug(5, 0, "comm_open: FD %d: failed to set close-on-exec flag: %s\n",
-           new_socket, xstrerror());
+    if (!(io_type & COMM_NOCLOEXEC)) {
+       if (fcntl(new_socket, F_SETFD, 1) < 0) {
+           debug(5, 0, "comm_open: FD %d: set close-on-exec failed: %s\n",
+               new_socket, xstrerror());
+       }
     }
     if (port > 0) {
-       if (commSetNoLinger(new_socket) < 0) {
-           debug(5, 0, "comm_open: failed to turn off SO_LINGER: %s\n",
-               xstrerror());
-       }
-       if (do_reuse) {
+       commSetNoLinger(new_socket);
+       if (do_reuse)
            commSetReuseAddr(new_socket);
-       }
-    }
-    if (port) {
-       for (p = getBindAddrList(); p; p = p->next) {
-           if (do_bind(new_socket, p->key, port) == COMM_OK)
-               break;
-           if (p->next == (wordlist *) NULL)
-               return COMM_ERROR;
-       }
     }
-    conn->port = port;
+    if (addr.s_addr != INADDR_NONE)
+       if (commBind(new_socket, addr, port) != COMM_OK)
+           return COMM_ERROR;
+    conn->local_port = port;
 
-    if (io_type & COMM_NONBLOCKING) {
-       /*
-        * Set up the flag NOT to have the socket to wait for message from
-        * network forever, but to return -1 when no message is coming in.
-        */
-#if defined(O_NONBLOCK) && !defined(_SQUID_SUNOS_) && !defined(_SQUID_SOLARIS_)
-       if (fcntl(new_socket, F_SETFL, O_NONBLOCK)) {
-           debug(5, 0, "comm_open: FD %d: Failure to set O_NONBLOCK: %s\n",
-               new_socket, xstrerror());
-           return (COMM_ERROR);
-       }
-#else
-       if (fcntl(new_socket, F_SETFL, O_NDELAY)) {
-           debug(5, 0, "comm_open: FD %d: Failure to set O_NDELAY: %s\n",
-               new_socket, xstrerror());
-           return (COMM_ERROR);
-       }
-#endif /* O_NONBLOCK */
-    }
+    if (io_type & COMM_NONBLOCKING)
+       if (commSetNonBlocking(new_socket) == COMM_ERROR)
+           return COMM_ERROR;
+#ifdef TCP_NODELAY
+    if (sock_type == SOCK_STREAM)
+       commSetTcpNoDelay(new_socket);
+#endif
     conn->comm_type = io_type;
     return new_socket;
 }
 
    /*
-    * NOTE: set the listen queue to getMaxFD()/4 and rely on the kernel to      
+    * NOTE: set the listen queue to FD_SETSIZE/4 and rely on the kernel to      
     * impose an upper limit.  Solaris' listen(3n) page says it has   
     * no limit on this parameter, but sys/socket.h sets SOMAXCONN 
     * to 5.  HP-UX currently has a limit of 20.  SunOS is 5 and
@@ -178,21 +269,20 @@ int comm_listen(sock)
      int sock;
 {
     int x;
-    if ((x = listen(sock, getMaxFD() >> 2)) < 0) {
+    if ((x = listen(sock, FD_SETSIZE >> 2)) < 0) {
        debug(5, 0, "comm_listen: listen(%d, %d): %s\n",
-           getMaxFD() >> 2,
+           FD_SETSIZE >> 2,
            sock, xstrerror());
        return x;
     }
     return sock;
 }
 
-
 /* Connect SOCK to specified DEST_PORT at DEST_HOST. */
 int comm_connect(sock, dest_host, dest_port)
      int sock;                 /* Type of communication to use. */
      char *dest_host;          /* Server's host name. */
-     int dest_port;            /* Server's port. */
+     u_short dest_port;                /* Server's port. */
 {
     struct hostent *hp = NULL;
     static struct sockaddr_in to_addr;
@@ -200,11 +290,11 @@ int comm_connect(sock, dest_host, dest_port)
     /* Set up the destination socket address for message to send to. */
     to_addr.sin_family = AF_INET;
 
-    if ((hp = ipcache_gethostbyname(dest_host)) == 0) {
+    if ((hp = ipcache_gethostbyname(dest_host, IP_BLOCKING_LOOKUP)) == 0) {
        debug(5, 1, "comm_connect: Failure to lookup host: %s.\n", dest_host);
        return (COMM_ERROR);
     }
-    memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
+    xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
     to_addr.sin_port = htons(dest_port);
     return comm_connect_addr(sock, &to_addr);
 }
@@ -213,10 +303,16 @@ int comm_set_fd_lifetime(fd, lifetime)
      int fd;
      int lifetime;
 {
-    if (fd < 0 || fd > getMaxFD())
+    debug(5, 3, "comm_set_fd_lifetime: FD %d lft %d\n", fd, lifetime);
+    if (fd < 0 || fd > FD_SETSIZE)
        return 0;
     if (lifetime < 0)
        return fd_lifetime[fd] = -1;
+    if (shutdown_pending || reread_pending) {
+       /* don't increase the lifetime if something pending */
+       if (fd_lifetime[fd] > -1 && (fd_lifetime[fd] - squid_curtime) < lifetime)
+           return fd_lifetime[fd];
+    }
     return fd_lifetime[fd] = (int) squid_curtime + lifetime;
 }
 
@@ -259,6 +355,10 @@ int comm_connect_addr(sock, address)
        case EALREADY:
            return COMM_ERROR;
            /* NOTREACHED */
+#if EAGAIN != EWOULDBLOCK
+       case EAGAIN:
+#endif
+       case EWOULDBLOCK:
        case EINPROGRESS:
            status = EINPROGRESS;
            break;
@@ -270,7 +370,7 @@ int comm_connect_addr(sock, address)
            if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *) &x, &len) >= 0)
                errno = x;
        default:
-           debug(5, 1, "comm_connect_addr: %s:%d: socket failure: %s.\n",
+           debug(5, 1, "connect: %s:%d: %s.\n",
                inet_ntoa(address->sin_addr),
                ntohs(address->sin_port),
                xstrerror());
@@ -280,9 +380,9 @@ int comm_connect_addr(sock, address)
     if (status == COMM_OK) {
        lft = comm_set_fd_lifetime(sock, getClientLifetime());
        strcpy(conn->ipaddr, inet_ntoa(address->sin_addr));
-       conn->port = ntohs(address->sin_port);
+       conn->remote_port = ntohs(address->sin_port);
        debug(5, 10, "comm_connect_addr: FD %d (lifetime %d): connected to %s:%d.\n",
-           sock, lft, conn->ipaddr, conn->port);
+           sock, lft, conn->ipaddr, conn->remote_port);
     } else if (status == EINPROGRESS) {
        lft = comm_set_fd_lifetime(sock, getConnectTimeout());
        debug(5, 10, "comm_connect_addr: FD %d connection pending, lifetime %d\n",
@@ -338,15 +438,15 @@ int comm_accept(fd, peer, me)
        *me = M;
     }
     /* fdstat update */
-    fdstat_open(sock, Socket);
+    fdstat_open(sock, FD_SOCKET);
     conn = &fd_table[sock];
     conn->openned = 1;
     conn->sender = 0;          /* This is an accept, therefore receiver. */
     conn->comm_type = listener->comm_type;
     strcpy(conn->ipaddr, inet_ntoa(P.sin_addr));
-
+    conn->remote_port = htons(P.sin_port);
+    conn->local_port = htons(M.sin_port);
     commSetNonBlocking(sock);
-
     return sock;
 }
 
@@ -354,22 +454,30 @@ int comm_close(fd)
      int fd;
 {
     FD_ENTRY *conn = NULL;
+    struct close_handler *ch = NULL;
 
     if (fd < 0)
        return -1;
 
-    if (fdstat_type(fd) == File) {
+    if (fdstat_type(fd) == FD_FILE) {
        debug(5, 0, "FD %d: Someone called comm_close() on a File\n", fd);
        fatal_dump(NULL);
     }
     conn = &fd_table[fd];
 
+    safe_free(conn->rstate);
+    safe_free(conn->wstate);
+
     comm_set_fd_lifetime(fd, -1);      /* invalidate the lifetime */
     debug(5, 5, "comm_close: FD %d\n", fd);
     /* update fdstat */
     fdstat_close(fd);
-    if (conn->close_handler)
-       conn->close_handler(fd, conn->close_data);
+    /* Call close handlers */
+    while ((ch = conn->close_handler)) {
+       conn->close_handler = ch->next;
+       ch->handler(fd, ch->data);
+       safe_free(ch);
+    }
     memset(conn, '\0', sizeof(FD_ENTRY));
     return close(fd);
 }
@@ -380,7 +488,8 @@ int comm_cleanup_fd_entry(fd)
      int fd;
 {
     FD_ENTRY *conn = &fd_table[fd];
-
+    safe_free(conn->rstate);
+    safe_free(conn->wstate);
     memset(conn, 0, sizeof(FD_ENTRY));
     return 0;
 }
@@ -390,7 +499,7 @@ int comm_cleanup_fd_entry(fd)
 int comm_udp_send(fd, host, port, buf, len)
      int fd;
      char *host;
-     int port;
+     u_short port;
      char *buf;
      int len;
 {
@@ -401,12 +510,12 @@ int comm_udp_send(fd, host, port, buf, len)
     /* Set up the destination socket address for message to send to. */
     to_addr.sin_family = AF_INET;
 
-    if ((hp = ipcache_gethostbyname(host)) == 0) {
+    if ((hp = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP)) == 0) {
        debug(5, 1, "comm_udp_send: gethostbyname failure: %s: %s\n",
            host, xstrerror());
        return (COMM_ERROR);
     }
-    memcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
+    xmemcpy(&to_addr.sin_addr, hp->h_addr, hp->h_length);
     to_addr.sin_port = htons(port);
     if ((bytes_sent = sendto(fd, buf, len, 0, (struct sockaddr *) &to_addr,
                sizeof(to_addr))) < 0) {
@@ -432,6 +541,7 @@ int comm_udp_sendto(fd, to_addr, addr_len, buf, len)
        debug(5, 1, "comm_udp_sendto: --> sin_family = %d\n", to_addr->sin_family);
        debug(5, 1, "comm_udp_sendto: --> sin_port   = %d\n", htons(to_addr->sin_port));
        debug(5, 1, "comm_udp_sendto: --> sin_addr   = %s\n", inet_ntoa(to_addr->sin_addr));
+       debug(5, 1, "comm_udp_sendto: --> length     = %d\n", len);
        return COMM_ERROR;
     }
     return bytes_sent;
@@ -477,10 +587,10 @@ static void comm_select_incoming()
     FD_ZERO(&read_mask);
     FD_ZERO(&write_mask);
 
-    if (theAsciiConnection >= 0 && fdstat_are_n_free_fd(RESERVED_FD))
-       fds[N++] = theAsciiConnection;
-    if (theUdpConnection >= 0)
-       fds[N++] = theUdpConnection;
+    if (theHttpConnection >= 0 && fdstat_are_n_free_fd(RESERVED_FD))
+       fds[N++] = theHttpConnection;
+    if (theInIcpConnection >= 0)
+       fds[N++] = theInIcpConnection;
     fds[N++] = 0;
 
     for (i = 0; i < N; i++) {
@@ -549,6 +659,12 @@ int comm_select(sec, failtime)
        FD_ZERO(&writefds);
        FD_ZERO(&exceptfds);
 
+       if (shutdown_pending || reread_pending) {
+           serverConnectionsClose();
+           ftpServerClose();
+           ipcacheShutdownServers();
+           setSocketShutdownLifetimes();
+       }
        nfds = 0;
        maxfd = fdstat_biggest_fd() + 1;
        for (i = 0; i < maxfd; i++) {
@@ -567,31 +683,32 @@ int comm_select(sec, failtime)
            }
        }
        if (!fdstat_are_n_free_fd(RESERVED_FD)) {
-           FD_CLR(theAsciiConnection, &readfds);
+           FD_CLR(theHttpConnection, &readfds);
        }
        if (shutdown_pending || reread_pending)
            debug(5, 2, "comm_select: Still waiting on %d FDs\n", nfds);
        if (nfds == 0)
            return COMM_SHUTDOWN;
+       if (shutdown_pending || reread_pending)
+           debug(5, 2, "comm_select: Still waiting on %d FDs\n", nfds);
        while (1) {
-           poll_time.tv_sec = 1;
+           poll_time.tv_sec = sec > 1 ? 1 : 0;
            poll_time.tv_usec = 0;
            num = select(maxfd, &readfds, &writefds, &exceptfds, &poll_time);
            if (num >= 0)
                break;
-           /* break on interrupt so outer loop will reset FD_SET's */
            if (errno == EINTR)
                break;
-           debug(5, 0, "comm_select: select failure: %s (errno %d).\n",
-               xstrerror(), errno);
+           debug(5, 0, "comm_select: select failure: %s\n",
+               xstrerror());
            examine_select(&readfds, &writefds, &exceptfds);
            return COMM_ERROR;
+           /* NOTREACHED */
        }
        if (num < 0)
            continue;
-
        debug(5, num ? 5 : 8, "comm_select: %d sockets ready at %d\n",
-           num, squid_curtime);
+           num, (int) squid_curtime);
 
        /* Check lifetime and timeout handlers ONCE each second.
         * Replaces brain-dead check every time through the loop! */
@@ -622,7 +739,7 @@ int comm_select(sec, failtime)
             */
            comm_select_incoming();
 
-           if ((fd == theUdpConnection) || (fd == theAsciiConnection))
+           if ((fd == theInIcpConnection) || (fd == theHttpConnection))
                continue;
 
            if (FD_ISSET(fd, &readfds)) {
@@ -663,55 +780,12 @@ int comm_select(sec, failtime)
     return COMM_TIMEOUT;
 }
 
-
-/* Select on fd to see if any io pending. */
-int comm_pending(fd, sec, usec)
-     int fd;
-     long sec, usec;
-{
-    fd_set readfds;
-    int num;
-    struct timeval timeout;
-
-    /* Find a fd ready for reading. */
-    FD_ZERO(&readfds);
-    FD_SET(fd, &readfds);
-
-    while (1) {
-       timeout.tv_sec = (time_t) sec;
-       timeout.tv_usec = (time_t) usec;
-       num = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);
-       if (num >= 0)
-           break;
-       switch (errno) {
-#if EAGAIN != EWOULDBLOCK
-       case EAGAIN:
-#endif
-       case EWOULDBLOCK:
-           return COMM_NOMESSAGE;
-       case EINTR:
-           break;              /* if select interrupted, try again */
-       default:
-           debug(5, 1, "comm_pending: select failure: %s\n", xstrerror());
-           return COMM_ERROR;
-       }
-    }
-
-    debug(5, 5, "comm_pending: %d sockets ready for reading\n", num);
-
-    if (num && FD_ISSET(fd, &readfds)) {
-       return COMM_OK;
-    }
-    return COMM_TIMEOUT;
-}
-
 void comm_set_select_handler(fd, type, handler, client_data)
      int fd;
      unsigned int type;
      int (*handler) ();
      void *client_data;
 {
-
     comm_set_select_handler_plus_timeout(fd, type, handler, client_data, 0);
 }
 
@@ -747,10 +821,6 @@ void comm_set_select_handler_plus_timeout(fd, type, handler, client_data, timeou
        fd_table[fd].lifetime_handler = handler;
        fd_table[fd].lifetime_data = client_data;
     }
-    if (type & COMM_SELECT_CLOSE) {
-       fd_table[fd].close_handler = handler;
-       fd_table[fd].close_data = client_data;
-    }
 }
 
 int comm_get_select_handler(fd, type, handler_ptr, client_data_ptr)
@@ -782,55 +852,89 @@ int comm_get_select_handler(fd, type, handler_ptr, client_data_ptr)
     return 0;                  /* XXX What is meaningful? */
 }
 
+void comm_add_close_handler(fd, handler, data)
+     int fd;
+     int (*handler) ();
+     void *data;
+{
+    struct close_handler *new = xmalloc(sizeof(*new));
+
+    debug(5, 5, "comm_add_close_handler: fd=%d handler=0x%p data=0x%p\n", fd, handler, data);
 
-static int commSetNoLinger(fd)
+    new->handler = handler;
+    new->data = data;
+    new->next = fd_table[fd].close_handler;
+    fd_table[fd].close_handler = new;
+}
+
+void comm_remove_close_handler(fd, handler, data)
      int fd;
+     int (*handler) ();
+     void *data;
 {
-    struct linger L;
+    struct close_handler *p, *last = NULL;
+
+    /* Find handler in list */
+    for (p = fd_table[fd].close_handler; p != NULL; last = p, p = p->next)
+       if (p->handler == handler && p->data == data)
+           break;              /* This is our handler */
+    if (!p)
+       fatal_dump("comm_remove_close_handler: Handler not found!\n");
+
+    /* Remove list entry */
+    if (last)
+       last->next = p->next;
+    else
+       fd_table[fd].close_handler = p->next;
+    safe_free(p);
+}
 
+static void commSetNoLinger(fd)
+     int fd;
+{
+    struct linger L;
     L.l_onoff = 0;             /* off */
     L.l_linger = 0;
-
     debug(5, 10, "commSetNoLinger: turning off SO_LINGER on FD %d\n", fd);
-    return setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L));
+    if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *) &L, sizeof(L)) < 0)
+       debug(5, 0, "commSetNoLinger: FD %d: %s\n", fd, xstrerror());
 }
 
-static int commSetReuseAddr(fd)
+static void commSetReuseAddr(fd)
      int fd;
 {
     int on = 1;
-    int rc;
-
     debug(5, 10, "commSetReuseAddr: turning on SO_REUSEADDR on FD %d\n", fd);
-    rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
-    if (rc < 0)
-       debug(5, 1, "commSetReuseAddr: FD=%d: %s\n", fd, xstrerror());
-    return rc;
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0)
+       debug(5, 1, "commSetReuseAddr: FD %d: %s\n", fd, xstrerror());
 }
 
-int commSetNonBlocking(fd)
+#ifdef TCP_NODELAY
+static void commSetTcpNoDelay(fd)
      int fd;
 {
-    debug(5, 10, "commSetNonBlocking: setting FD %d to non-blocking i/o.\n",
-       fd);
-    /*
-     * Set up the flag NOT to have the socket to wait for message from
-     * network forever, but to return -1 when no message is coming in.
-     */
+    int on = 1;
+    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0)
+       debug(5, 1, "commSetTcpNoDelay: FD %d: %s\n", fd, xstrerror());
+}
+#endif
 
+int commSetNonBlocking(fd)
+     int fd;
+{
 #if defined(O_NONBLOCK) && !defined(_SQUID_SUNOS_) && !defined(_SQUID_SOLARIS_)
     if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
        debug(5, 0, "comm_open: FD %d: error setting O_NONBLOCK: %s\n",
            fd, xstrerror());
-       return (COMM_ERROR);
+       return COMM_ERROR;
     }
 #else
     if (fcntl(fd, F_SETFL, O_NDELAY)) {
        debug(5, 0, "comm_open: FD %d: error setting O_NDELAY: %s\n",
            fd, xstrerror());
-       return (COMM_ERROR);
+       return COMM_ERROR;
     }
-#endif /* HPUX */
+#endif
     return 0;
 }
 
@@ -840,7 +944,7 @@ char **getAddressList(name)
     struct hostent *hp = NULL;
     if (name == NULL)
        return NULL;
-    if ((hp = ipcache_gethostbyname(name)))
+    if ((hp = ipcache_gethostbyname(name, IP_BLOCKING_LOOKUP)))
        return hp->h_addr_list;
     debug(5, 0, "getAddress: gethostbyname failure: %s: %s\n",
        name, xstrerror());
@@ -855,7 +959,7 @@ struct in_addr *getAddress(name)
     if (name == NULL)
        return NULL;
     if ((list = getAddressList(name))) {
-       memcpy(&first.s_addr, *list, 4);
+       xmemcpy(&first.s_addr, *list, 4);
        return (&first);
     }
     debug(5, 0, "getAddress: gethostbyname failure: %s: %s\n",
@@ -872,19 +976,22 @@ struct in_addr *getAddress(name)
  */
 int comm_init()
 {
-    int i, max_fd = getMaxFD();
+    int i;
 
-    fd_table = (FD_ENTRY *) xcalloc(max_fd, sizeof(FD_ENTRY));
+    fd_table = xcalloc(FD_SETSIZE, sizeof(FD_ENTRY));
+    meta_data.misc += FD_SETSIZE * sizeof(FD_ENTRY);
     /* Keep a few file descriptors free so that we don't run out of FD's
      * after accepting a client but before it opens a socket or a file.
-     * Since getMaxFD can be as high as several thousand, don't waste them */
-    RESERVED_FD = min(100, getMaxFD() / 4);
+     * Since FD_SETSIZE can be as high as several thousand, don't waste them */
+    RESERVED_FD = min(100, FD_SETSIZE / 4);
     /* hardwired lifetimes */
-    fd_lifetime = (int *) xmalloc(sizeof(int) * max_fd);
-    for (i = 0; i < max_fd; i++)
+    fd_lifetime = xmalloc(sizeof(int) * FD_SETSIZE);
+    for (i = 0; i < FD_SETSIZE; i++)
        comm_set_fd_lifetime(i, -1);    /* denotes invalid */
+    meta_data.misc += FD_SETSIZE * sizeof(int);
     zero_tv.tv_sec = 0;
     zero_tv.tv_usec = 0;
+    any_addr.s_addr = inet_addr("0.0.0.0");
     return 0;
 }
 
@@ -907,12 +1014,13 @@ static int examine_select(readfds, writefds, exceptfds)
     fd_set write_x;
     fd_set except_x;
     int num;
-    int maxfd = getMaxFD();
     struct timeval tv;
+    struct close_handler *ch = NULL;
+    struct close_handler *next = NULL;
     FD_ENTRY *f = NULL;
 
     debug(5, 0, "examine_select: Examining open file descriptors...\n");
-    for (fd = 0; fd < maxfd; fd++) {
+    for (fd = 0; fd < FD_SETSIZE; fd++) {
        FD_ZERO(&read_x);
        FD_ZERO(&write_x);
        FD_ZERO(&except_x);
@@ -931,9 +1039,14 @@ static int examine_select(readfds, writefds, exceptfds)
                    f->read_handler,
                    f->write_handler,
                    f->except_handler);
+               for (ch = f->close_handler; ch; ch = ch->next)
+                   debug(5, 0, " close handler: %p\n", ch->handler);
                if (f->close_handler) {
-                   debug(5, 0, "examine_select: Calling Close Handler\n");
-                   f->close_handler(fd, f->close_data);
+                   for (ch = f->close_handler; ch; ch = next) {
+                       next = ch->next;
+                       ch->handler(fd, ch->data);
+                       safe_free(ch);
+                   }
                } else if (f->lifetime_handler) {
                    debug(5, 0, "examine_select: Calling Lifetime Handler\n");
                    f->lifetime_handler(fd, f->lifetime_data);
@@ -953,7 +1066,6 @@ static int examine_select(readfds, writefds, exceptfds)
            }
        }
     }
-    debug(5, 0, "examine_select: Finished examining open file descriptors.\n");
     return 0;
 }
 
@@ -972,10 +1084,9 @@ static void checkTimeouts()
     int fd;
     int (*tmp) () = NULL;
     FD_ENTRY *f = NULL;
-    int maxfd = fdstat_biggest_fd() + 1;
 
     /* scan for timeout */
-    for (fd = 0; fd < maxfd; ++fd) {
+    for (fd = 0; fd < FD_SETSIZE; ++fd) {
        f = &fd_table[fd];
        if ((f->timeout_handler) &&
            (f->timeout_time <= squid_curtime)) {
@@ -991,78 +1102,42 @@ static void checkTimeouts()
 static void checkLifetimes()
 {
     int fd;
-    int max_fd = getMaxFD();
     time_t lft;
-    int (*tmp_local) () = NULL;
-    int use_lifetime_handler = 0;
-    int use_read = 0;
-
-    /* scan for hardwired lifetime expires, do the timeouts first though */
-    for (fd = 0; fd < max_fd; fd++) {
-       lft = comm_get_fd_lifetime(fd);
-       if ((lft != -1) && (lft < squid_curtime)) {
-           if (fd_table[fd].lifetime_handler != NULL) {
-               use_lifetime_handler = 1;
-               tmp_local = fd_table[fd].lifetime_handler;
-               fd_table[fd].lifetime_handler = 0;      /* reset it */
-           } else if (fd_table[fd].read_handler != NULL) {
-               use_read = 1;
-               tmp_local = fd_table[fd].read_handler;
-               fd_table[fd].read_handler = 0;  /* reset it */
-           } else if (fd_table[fd].write_handler != NULL) {
-               use_read = 0;
-               tmp_local = fd_table[fd].write_handler;
-               fd_table[fd].write_handler = 0;         /* reset it */
-           } else {
-               use_read = 0;
-               tmp_local = NULL;
-           }
-           if (tmp_local) {
-               if (use_lifetime_handler) {
-                   debug(5, 2, "checkLifetimes: FD %d lifetime expire: %d < %d (Lifetime handler %p)\n",
-                       fd, lft, squid_curtime, tmp_local);
-               } else {
-                   debug(5, 2, "checkLifetimes: FD %d lifetime expire: %d < %d (%s handler %p)\n",
-                       fd, lft, squid_curtime,
-                       use_read ? "read" : "write", tmp_local);
-               }
-           } else {
-               debug(5, 1, "checkLifetimes: FD %d lifetime expire: %d < %d (handler not available.)\n",
-                   fd, lft, squid_curtime);
-           }
 
-           if (tmp_local != NULL) {
-               if (use_lifetime_handler) {
-                   tmp_local(fd, fd_table[fd].lifetime_data);
-               } else {
-                   /* 
-                    *  we close(2) first so that the handler fails and 
-                    *  deallocates the structure.
-                    */
-                   (void) close(fd);
-                   debug(5, 0, "checkLifetimes: Forcing close on FD %d\n", fd);
-                   tmp_local(fd, use_read ? fd_table[fd].read_data :
-                       fd_table[fd].write_data);
-               }
-               if (fd_table[fd].openned) {
-                   /* hmm.. still openned. do full comm_close */
-                   debug(5, 5, "checkLifetimes: FD %d lifetime expire: %d < %d : Handler did not close the socket.\n comm_select will do.\n",
-                       fd, lft, squid_curtime);
-                   comm_close(fd);
-               } else {
-                   /* seems like handle closed it. 
-                    * clean up fd_table just to make sure */
-                   debug(5, 5, "checkLifetimes: FD %d lifetime expire: %d : Handler closed the socket.\n",
-                       fd, lft);
-                   /* just to make sure here */
-                   comm_cleanup_fd_entry(fd);
-               }
-           } else {
-               /* no handle. do full comm_close */
-               debug(5, 5, "checkLifetimes: FD %d lifetime expire: %d < %d : No handler to close the socket.\n comm_select will do.\n",
-                   fd, lft, squid_curtime);
-               comm_close(fd);
-           }
+    int (*func) () = NULL;
+
+    for (fd = 0; fd < FD_SETSIZE; fd++) {
+       if ((lft = comm_get_fd_lifetime(fd)) == -1)
+           continue;
+       if (lft > squid_curtime)
+           continue;
+       debug(5, 5, "checkLifetimes: FD %d Expired\n", fd);
+       if ((func = fd_table[fd].lifetime_handler)) {
+           debug(5, 5, "checkLifetimes: FD %d: Calling lifetime handler\n", fd);
+           func(fd, fd_table[fd].lifetime_data);
+           fd_table[fd].lifetime_handler = NULL;
+       } else if ((func = fd_table[fd].read_handler)) {
+           debug(5, 5, "checkLifetimes: FD %d: Calling read handler\n", fd);
+           func(fd, fd_table[fd].read_data);
+           fd_table[fd].read_handler = NULL;
+       } else if ((func = fd_table[fd].read_handler)) {
+           debug(5, 5, "checkLifetimes: FD %d: Calling read handler\n", fd);
+           func(fd, fd_table[fd].read_data);
+           fd_table[fd].read_handler = NULL;
+       } else if ((func = fd_table[fd].write_handler)) {
+           debug(5, 5, "checkLifetimes: FD %d: Calling write handler\n", fd);
+           func(fd, fd_table[fd].write_data);
+           fd_table[fd].write_handler = NULL;
+       } else {
+           debug(5, 5, "checkLifetimes: FD %d: No handlers, calling comm_close()\n", fd);
+           comm_close(fd);
+           comm_cleanup_fd_entry(fd);
+       }
+       if (fd_table[fd].openned) {
+           /* still opened */
+           debug(5, 5, "checkLifetimes: FD %d: Forcing comm_close()\n", fd);
+           comm_close(fd);
+           comm_cleanup_fd_entry(fd);
        }
     }
 }
@@ -1072,12 +1147,12 @@ static void checkLifetimes()
  */
 static void Reserve_More_FDs()
 {
-    if (RESERVED_FD < getMaxFD() - 64) {
+    if (RESERVED_FD < FD_SETSIZE - 64) {
        RESERVED_FD = RESERVED_FD + 1;
-    } else if (RESERVED_FD == getMaxFD() - 64) {
+    } else if (RESERVED_FD == FD_SETSIZE - 64) {
        RESERVED_FD = RESERVED_FD + 1;
        debug(5, 0, "Don't you have a tiny open-file table size of %d\n",
-           getMaxFD() - RESERVED_FD);
+           FD_SETSIZE - RESERVED_FD);
     }
 }
 
@@ -1095,3 +1170,217 @@ int fd_of_first_client(e)
     }
     return (-1);
 }
+
+/* Read from FD. */
+static int commHandleRead(fd, state)
+     int fd;
+     RWStateData *state;
+{
+    int len;
+
+    len = read(fd, state->buf + state->offset, state->size - state->offset);
+    debug(5, 5, "commHandleRead: FD %d: read %d bytes\n", fd, len);
+
+    if (len <= 0) {
+       switch (errno) {
+#if EAGAIN != EWOULDBLOCK
+       case EAGAIN:
+#endif
+       case EWOULDBLOCK:
+           /* reschedule self */
+           comm_set_select_handler(fd,
+               COMM_SELECT_READ,
+               (PF) commHandleRead,
+               state);
+           return COMM_OK;
+       default:
+           /* Len == 0 means connection closed; otherwise would not have been
+            * called by comm_select(). */
+           debug(5, len == 0 ? 2 : 1, "commHandleRead: FD %d: read failure: %s\n",
+               fd, len == 0 ? "connection closed" : xstrerror());
+           fd_table[fd].rstate = NULL;         /* The handler may issue a new read */
+           /* Notify caller that we failed */
+           state->handler(fd,
+               state->buf,
+               state->offset,
+               COMM_ERROR,
+               state->handler_data);
+           safe_free(state);
+           return COMM_ERROR;
+       }
+    }
+    state->offset += len;
+
+    /* Call handler if we have read enough */
+    if (state->offset >= state->size || state->handle_immed) {
+       fd_table[fd].rstate = NULL;     /* The handler may issue a new read */
+       state->handler(fd,
+           state->buf,
+           state->offset,
+           COMM_OK,
+           state->handler_data);
+       safe_free(state);
+    } else {
+       /* Reschedule until we are done */
+       comm_set_select_handler(fd,
+           COMM_SELECT_READ,
+           (PF) commHandleRead,
+           state);
+    }
+    return COMM_OK;
+}
+
+/* Select for reading on FD, until SIZE bytes are received.  Call
+ * HANDLER when complete. */
+void comm_read(fd, buf, size, timeout, immed, handler, handler_data)
+     int fd;
+     char *buf;
+     int size;
+     int timeout;
+     int immed;                        /* Call handler immediately when data available */
+     rw_complete_handler *handler;
+     void *handler_data;
+{
+    RWStateData *state = NULL;
+
+    debug(5, 5, "comm_read: FD %d: sz %d: tout %d: hndl %p: data %p.\n",
+       fd, size, timeout, handler, handler_data);
+
+    if (fd_table[fd].rstate) {
+       debug(5, 1, "comm_read: WARNING! FD %d: A comm_read is already active.\n", fd);
+       safe_free(fd_table[fd].rstate);
+    }
+    state = xcalloc(1, sizeof(RWStateData));
+    fd_table[fd].rstate = state;
+    state->buf = buf;
+    state->size = size;
+    state->offset = 0;
+    state->handler = handler;
+    state->timeout = timeout;
+    state->handle_immed = immed;
+    state->time = squid_curtime;
+    state->handler_data = handler_data;
+    comm_set_select_handler(fd,
+       COMM_SELECT_READ,
+       (PF) commHandleRead,
+       state);
+}
+
+/* Write to FD. */
+static void commHandleWrite(fd, state)
+     int fd;
+     RWStateData *state;
+{
+    int len = 0;
+    int nleft;
+
+    debug(5, 5, "commHandleWrite: FD %d: state=%p, off %d, sz %d.\n",
+       fd, state, state->offset, state->size);
+
+    nleft = state->size - state->offset;
+    len = write(fd, state->buf + state->offset, nleft);
+
+    if (len == 0) {
+       /* Note we even call write if nleft == 0 */
+       /* We're done */
+       if (nleft != 0)
+           debug(5, 2, "commHandleWrite: FD %d: write failure: connection closed with %d bytes remaining.\n", fd, nleft);
+       fd_table[fd].wstate = NULL;
+       if (state->handler)
+           state->handler(fd,
+               state->buf,
+               state->offset,
+               nleft ? COMM_ERROR : COMM_OK,
+               state->handler_data);
+       else
+           xfree(state->buf);
+       safe_free(state);
+       return;
+    } else if (len < 0) {
+       /* An error */
+       if (errno == EWOULDBLOCK || errno == EAGAIN) {
+           /* XXX: Re-install the handler rather than giving up. I hope
+            * this doesn't freeze this socket due to some random OS bug
+            * returning EWOULDBLOCK indefinitely.  Ought to maintain a
+            * retry count in state? */
+           debug(5, 10, "commHandleWrite: FD %d: write failure: %s.\n",
+               fd, xstrerror());
+           comm_set_select_handler(fd,
+               COMM_SELECT_WRITE,
+               (PF) commHandleWrite,
+               state);
+           return;
+       }
+       debug(5, 2, "commHandleWrite: FD %d: write failure: %s.\n",
+           fd, xstrerror());
+       /* Notify caller that we failed */
+       fd_table[fd].wstate = NULL;
+       if (state->handler)
+           state->handler(fd,
+               state->buf,
+               state->offset,
+               COMM_ERROR,
+               state->handler_data);
+       else
+           xfree(state->buf);
+       safe_free(state);
+       return;
+    } else {
+       /* A successful write, continue */
+       state->offset += len;
+       if (state->offset < state->size) {
+           /* Not done, reinstall the write handler and write some more */
+           comm_set_select_handler(fd,
+               COMM_SELECT_WRITE,
+               (PF) commHandleWrite,
+               state);
+           return;
+       }
+       fd_table[fd].wstate = NULL;
+       /* Notify caller that the write is complete */
+       if (state->handler)
+           state->handler(fd,
+               state->buf,
+               state->offset,
+               COMM_OK,
+               state->handler_data);
+       else
+           xfree(state->buf);
+       safe_free(state);
+    }
+}
+
+
+
+/* Select for Writing on FD, until SIZE bytes are sent.  Call
+ * * HANDLER when complete. */
+void comm_write(fd, buf, size, timeout, handler, handler_data)
+     int fd;
+     char *buf;
+     int size;
+     int timeout;
+     rw_complete_handler *handler;
+     void *handler_data;
+{
+    RWStateData *state = NULL;
+
+    debug(5, 5, "comm_write: FD %d: sz %d: tout %d: hndl %p: data %p.\n",
+       fd, size, timeout, handler, handler_data);
+
+    if (fd_table[fd].wstate) {
+       debug(5, 1, "comm_write: WARNING! FD %d: A comm_write is already active.\n", fd);
+       safe_free(fd_table[fd].wstate);
+    }
+    state = xcalloc(1, sizeof(RWStateData));
+    state->buf = buf;
+    state->size = size;
+    state->offset = 0;
+    state->handler = handler;
+    state->timeout = timeout;
+    state->time = squid_curtime;
+    state->handler_data = handler_data;
+    comm_set_select_handler(fd,
+       COMM_SELECT_WRITE,
+       (PF) commHandleWrite,
+       fd_table[fd].wstate = state);
+}
index ca96c4c7a39e77ec9eb0070959b576df82d6f803..a2b045fa0517a363c815e06284265a2fac6a2301 100644 (file)
@@ -1,5 +1,107 @@
+/*
+ * $Id: debug.cc,v 1.18 1996/07/09 03:41:21 wessels Exp $
+ *
+ * DEBUG: section 0     Debug Routines
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
-/* $Id: debug.cc,v 1.17 1996/04/17 17:14:43 wessels Exp $ */
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
@@ -124,8 +226,9 @@ static void debugOpenLog(logfile)
     }
 }
 
-void _db_init(logfile)
+void _db_init(logfile, options)
      char *logfile;
+     char *options;
 {
     int i;
     char *p = NULL;
@@ -134,16 +237,15 @@ void _db_init(logfile)
     for (i = 0; i < MAX_DEBUG_SECTIONS; i++)
        debugLevels[i] = -1;
 
-    if ((p = getDebugOptions())) {
-       p = xstrdup(p);
-       for (s = strtok(p, w_space); s; s = strtok(NULL, w_space)) {
+    if (options) {
+       p = xstrdup(options);
+       for (s = strtok(p, w_space); s; s = strtok(NULL, w_space))
            debugArg(s);
-       }
        xfree(p);
     }
     debugOpenLog(logfile);
 
-#if HAVE_SYSLOG
+#if HAVE_SYSLOG && defined(LOG_LOCAL4)
     if (syslog_enable)
        openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
 #endif /* HAVE_SYSLOG */
@@ -174,5 +276,5 @@ void _db_rotate_log()
     /* Close and reopen the log.  It may have been renamed "manually"
      * before HUP'ing us. */
     if (debug_log != stderr)
-       debugOpenLog(debug_log_file);
+       debugOpenLog(getCacheLogFile());
 }
index 2d8a79cc90fb78499e66c1f875451c0e30d28b1a..08b4db484ecca684582e475fb6c71b5a7e74b29b 100644 (file)
@@ -1,6 +1,107 @@
-/* $Id: disk.cc,v 1.12 1996/05/01 22:36:27 wessels Exp $ */
-
-/* DEBUG: Section 6             disk: disk I/O routines */
+/*
+ * $Id: disk.cc,v 1.13 1996/07/09 03:41:22 wessels Exp $
+ *
+ * DEBUG: section 6     Disk I/O Routines
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
@@ -64,22 +165,17 @@ typedef struct _FileEntry {
     dwrite_q *write_q_tail;
 } FileEntry;
 
-
 /* table for FILE variable, write lock and queue. Indexed by fd. */
 FileEntry *file_table;
 
-extern int getMaxFD();
-extern void fatal_dump _PARAMS((char *));
-
 /* initialize table */
 int disk_init()
 {
-    int fd, max_fd = getMaxFD();
-
-    file_table = (FileEntry *) xmalloc(sizeof(FileEntry) * max_fd);
-    memset(file_table, '\0', sizeof(FileEntry) * max_fd);
+    int fd;
 
-    for (fd = 0; fd < max_fd; fd++) {
+    file_table = xcalloc(FD_SETSIZE, sizeof(FileEntry));
+    meta_data.misc += FD_SETSIZE * sizeof(FileEntry);
+    for (fd = 0; fd < FD_SETSIZE; fd++) {
        file_table[fd].filename[0] = '\0';
        file_table[fd].at_eof = NO;
        file_table[fd].open_stat = NOT_OPEN;
@@ -109,7 +205,7 @@ int file_open(path, handler, mode)
        return (DISK_ERROR);
     }
     /* update fdstat */
-    fdstat_open(fd, File);
+    fdstat_open(fd, FD_FILE);
 
     /* init table */
     strncpy(file_table[fd].filename, path, MAX_FILE_NAME_LEN);
@@ -123,27 +219,10 @@ int file_open(path, handler, mode)
     file_table[fd].write_q = NULL;
 
     conn = &fd_table[fd];
-    memset(conn, 0, sizeof(FD_ENTRY));
-
-    conn->port = 0;
-    conn->handler = NULL;
-
-    /* set non-blocking mode */
-#if defined(O_NONBLOCK) && !defined(_SQUID_SUNOS_) && !defined(_SQUID_SOLARIS_)
-    if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
-       debug(6, 0, "file_open: FD %d: Failure to set O_NONBLOCK: %s\n",
-           fd, xstrerror());
-       return DISK_ERROR;
-    }
-#else
-    if (fcntl(fd, F_SETFL, O_NDELAY) < 0) {
-       debug(6, 0, "file_open: FD %d: Failure to set O_NDELAY: %s\n",
-           fd, xstrerror());
+    memset(conn, '\0', sizeof(FD_ENTRY));
+    if (commSetNonBlocking(fd) == COMM_ERROR)
        return DISK_ERROR;
-    }
-#endif /* O_NONBLOCK */
     conn->comm_type = COMM_NONBLOCKING;
-
     return fd;
 }
 
@@ -154,7 +233,7 @@ int file_update_open(fd, path)
     FD_ENTRY *conn;
 
     /* update fdstat */
-    fdstat_open(fd, File);
+    fdstat_open(fd, FD_FILE);
 
     /* init table */
     strncpy(file_table[fd].filename, path, MAX_FILE_NAME_LEN);
@@ -168,13 +247,8 @@ int file_update_open(fd, path)
     file_table[fd].write_q = NULL;
 
     conn = &fd_table[fd];
-    memset(conn, 0, sizeof(FD_ENTRY));
-
-    conn->port = 0;
-    conn->handler = NULL;
-
+    memset(conn, '\0', sizeof(FD_ENTRY));
     conn->comm_type = COMM_NONBLOCKING;
-
     return fd;
 }
 
@@ -201,7 +275,7 @@ int file_close(fd)
        file_table[fd].write_daemon = NOT_PRESENT;
        file_table[fd].filename[0] = '\0';
 
-       if (fdstat_type(fd) == Socket) {
+       if (fdstat_type(fd) == FD_SOCKET) {
            debug(6, 0, "FD %d: Someone called file_close() on a socket\n", fd);
            fatal_dump(NULL);
        }
@@ -220,23 +294,6 @@ int file_close(fd)
     return DISK_ERROR;
 }
 
-
-/* return a opened fd associate with given path name. */
-/* return DISK_FILE_NOT_FOUND if not found. */
-int file_get_fd(filename)
-     char *filename;
-{
-    int fd, max_fd = getMaxFD();
-    for (fd = 1; fd < max_fd; fd++) {
-       if (file_table[fd].open_stat == OPEN) {
-           if (strncmp(file_table[fd].filename, filename, MAX_FILE_NAME_LEN) == 0) {
-               return fd;
-           }
-       }
-    }
-    return DISK_FILE_NOT_FOUND;
-}
-
 /* grab a writing lock for file */
 int file_write_lock(fd)
      int fd;
@@ -301,8 +358,8 @@ int diskHandleWrite(fd, entry)
                return DISK_OK;
            default:
                /* disk i/o failure--flushing all outstanding writes  */
-               debug(6, 1, "diskHandleWrite: disk write error %s\n",
-                   xstrerror());
+               debug(6, 1, "diskHandleWrite: FD %d: disk write error: %s\n",
+                   fd, xstrerror());
                entry->write_daemon = NOT_PRESENT;
                entry->write_pending = NO_WRT_PENDING;
                /* call finish handler */
@@ -401,7 +458,7 @@ int file_write(fd, ptr_to_buf, len, access_code, handle, handle_data)
        return DISK_WRT_WRONG_CODE;
     }
     /* if we got here. Caller is eligible to write. */
-    wq = (dwrite_q *) xcalloc(1, sizeof(dwrite_q));
+    wq = xcalloc(1, sizeof(dwrite_q));
 
     wq->buf = ptr_to_buf;
 
@@ -504,8 +561,7 @@ int file_read(fd, buf, req_len, offset, handler, client_data)
 {
     dread_ctrl *ctrl_dat;
 
-    ctrl_dat = (dread_ctrl *) xmalloc(sizeof(dread_ctrl));
-    memset(ctrl_dat, '\0', sizeof(dread_ctrl));
+    ctrl_dat = xcalloc(1, sizeof(dread_ctrl));
     ctrl_dat->fd = fd;
     ctrl_dat->offset = offset;
     ctrl_dat->req_len = req_len;
@@ -533,7 +589,7 @@ int diskHandleWalk(fd, walk_dat)
     int end_pos;
     int st_pos;
     int used_bytes;
-    char temp_line[DISK_LINE_LEN];
+    static char temp_line[DISK_LINE_LEN];
 
     lseek(fd, walk_dat->offset, SEEK_SET);
     file_table[fd].at_eof = NO;
@@ -604,11 +660,10 @@ int file_walk(fd, handler, client_data, line_handler, line_data)
 {
     dwalk_ctrl *walk_dat;
 
-    walk_dat = (dwalk_ctrl *) xmalloc(sizeof(dwalk_ctrl));
-    memset(walk_dat, '\0', sizeof(dwalk_ctrl));
+    walk_dat = xcalloc(1, sizeof(dwalk_ctrl));
     walk_dat->fd = fd;
     walk_dat->offset = 0;
-    walk_dat->buf = (void *) xcalloc(1, DISK_LINE_LEN);
+    walk_dat->buf = xcalloc(1, DISK_LINE_LEN);
     walk_dat->cur_len = 0;
     walk_dat->handler = handler;
     walk_dat->client_data = client_data;
index 0a64eca38a89185e726a909cbe77d0470ee3b4db..d2a71874ee0a66c8ee72f91cc9a2c7b8a7041581 100644 (file)
@@ -1,6 +1,115 @@
-/* $Id: dnsserver.cc,v 1.6 1996/05/03 22:56:24 wessels Exp $ */
+/*
+ * $Id: dnsserver.cc,v 1.7 1996/07/09 03:41:22 wessels Exp $
+ *
+ * DEBUG: section 0     DNS Resolver
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
+#if HAVE_ARPA_NAMESER_H
+#include <arpa/nameser.h>
+#endif
+#if HAVE_RESOLV_H
+#include <resolv.h>
+#endif
 
 extern int h_errno;
 
@@ -57,15 +166,25 @@ int main(argc, argv)
     char *t = NULL;
     char buf[256];
     int socket_from_cache, fd;
-    int a1, a2, a3, a4;
     int addr_count = 0;
     int alias_count = 0;
     int i;
     char *dnsServerPathname = NULL;
+    int dnsServerTCP = 0;
     int c;
     extern char *optarg;
 
-    while ((c = getopt(argc, argv, "vhdp:")) != -1)
+#if HAVE_RES_INIT
+    res_init();
+#ifdef RES_DEFNAMES
+    _res.options &= ~RES_DEFNAMES;
+#endif
+#ifdef RES_DNSRCH
+    _res.options &= ~RES_DNSRCH;
+#endif
+#endif
+
+    while ((c = getopt(argc, argv, "vhdtp:")) != -1) {
        switch (c) {
        case 'v':
        case 'h':
@@ -82,18 +201,23 @@ int main(argc, argv)
        case 'p':
            dnsServerPathname = xstrdup(optarg);
            break;
+       case 't':
+           dnsServerTCP = 1;
+           break;
        default:
            fprintf(stderr, "usage: dnsserver -h -d -p socket-filename\n");
            exit(1);
            break;
        }
+    }
 
     socket_from_cache = 3;
 
     /* accept DNS look up from ipcache */
-    if (dnsServerPathname) {
-       fd = accept(socket_from_cache, (struct sockaddr *) 0, (int *) 0);
-       unlink(dnsServerPathname);
+    if (dnsServerPathname || dnsServerTCP) {
+       fd = accept(socket_from_cache, NULL, NULL);
+       if (dnsServerPathname)
+           unlink(dnsServerPathname);
        if (fd < 0) {
            fprintf(stderr, "dnsserver: accept: %s\n", xstrerror());
            exit(1);
@@ -109,7 +233,7 @@ int main(argc, argv)
        memset(request, '\0', 256);
 
        /* read from ipcache */
-       if (fgets(request, 255, stdin) == (char *) NULL)
+       if (fgets(request, 255, stdin) == NULL)
            exit(1);
        if ((t = strrchr(request, '\n')) != NULL)
            *t = '\0';          /* strip NL */
@@ -125,7 +249,7 @@ int main(argc, argv)
            continue;
        }
        /* check if it's already an IP address in text form. */
-       if (sscanf(request, "%d.%d.%d.%d", &a1, &a2, &a3, &a4) == 4) {
+       if (inet_addr(request) != INADDR_NONE) {
            printf("$name %s\n", request);
            printf("$h_name %s\n", request);
            printf("$h_len %d\n", 4);
@@ -162,7 +286,7 @@ int main(argc, argv)
                fflush(logfile);
            }
            printf("$fail %s\n", request);
-           printf("$message %s\n", msg[0] ? msg : "Unknown Error");
+           printf("$message %s", msg[0] ? msg : "Unknown Error\n");
            printf("$end\n");
            fflush(stdout);
            continue;
@@ -178,7 +302,7 @@ int main(argc, argv)
            printf("$ipcount %d\n", addr_count);
            for (i = 0; i < addr_count; i++) {
                struct in_addr addr;
-               memcpy((char *) &addr, result->h_addr_list[i], result->h_length);
+               xmemcpy((char *) &addr, result->h_addr_list[i], result->h_length);
                printf("%s\n", inet_ntoa(addr));
            }
 
index a6a20a03bc1dda33d2dc11cfc83d2d9390934041..674b884c7a7921591ed26e5d407bd04587b96200 100644 (file)
@@ -1,11 +1,35 @@
-/* $Id: errorpage.cc,v 1.21 1996/05/01 22:36:28 wessels Exp $ */
-
-/* DEBUG: Section 4             errorpage: Error printing routines */
+/*
+ * $Id: errorpage.cc,v 1.22 1996/07/09 03:41:23 wessels Exp $
+ *
+ * DEBUG: section 4     Error Generation
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 #include "squid.h"
 
-
-
 #define SQUID_ERROR_MSG_P1 "\
 <TITLE>ERROR: The requested URL could not be retrieved</TITLE>\n\
 <H2>The requested URL could not be retrieved</H2>\n\
@@ -95,17 +119,15 @@ error_data ErrorData[] =
 char *tmp_error_buf;
 
 /* LOCAL */
-static char *tbuf;
-
-int log_errors = 1;
+static char *tbuf = NULL;
 
 void errorInitialize()
 {
-    tmp_error_buf = (char *) xmalloc(MAX_URL * 4);
-    tbuf = (char *) xmalloc(MAX_URL * 3);
+    tmp_error_buf = xmalloc(MAX_URL * 4);
+    tbuf = xmalloc(MAX_URL * 3);
+    meta_data.misc += MAX_URL * 7;
 }
 
-
 void squid_error_entry(entry, type, msg)
      StoreEntry *entry;
      int type;
@@ -166,8 +188,7 @@ char *squid_error_url(url, method, type, address, code, msg)
        appname,
        version_string,
        getMyHostname());
-    if (!log_errors)
-       return tmp_error_buf;
+    strcat(tmp_error_buf, tbuf);
     return tmp_error_buf;
 }
 
@@ -191,12 +212,9 @@ char *squid_error_request(request, type, address, code)
      char *address;
      int code;
 {
-    int index;
-
     *tmp_error_buf = '\0';
     if (type < ERR_MIN || type > ERR_MAX)
-       fatal_dump("squid_error_url: type out of range.");
-    index = (int) (type - ERR_MIN);
+       fatal_dump("squid_error_request: type out of range.");
 
     sprintf(tmp_error_buf, "HTTP/1.0 %d Cache Detected Error\r\nContent-type: text/html\r\n\r\n", code);
     sprintf(tbuf, SQUID_REQUEST_ERROR_MSG,
@@ -205,8 +223,6 @@ char *squid_error_request(request, type, address, code)
        version_string,
        getMyHostname());
     strcat(tmp_error_buf, tbuf);
-    if (!log_errors)
-       return tmp_error_buf;
     return tmp_error_buf;
 }
 
index 58feda3fea37b40988fb094b385fca3a1a748f12..fdf8dba35f8686b6ddc23e26292ee242cfad2fe7 100644 (file)
@@ -1,6 +1,107 @@
-/* $Id: filemap.cc,v 1.7 1996/03/29 21:19:19 wessels Exp $ */
-
-/* DEBUG: Section 8             filemap: swap file bitmap functions */
+/*
+ * $Id: filemap.cc,v 1.8 1996/07/09 03:41:24 wessels Exp $
+ *
+ * DEBUG: section 8     Swap File Bitmap
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
@@ -31,13 +132,13 @@ fileMap *file_map_create(n)
      int n;                    /* Number of files */
 {
     fm = xcalloc(1, sizeof(fileMap));
-
     fm->max_n_files = n;
     fm->nwords = n >> LONG_BIT_SHIFT;
     debug(8, 1, "file_map_create: creating space for %d files\n", n);
     debug(8, 5, "--> %d words of %d bytes each\n",
        fm->nwords, sizeof(unsigned long));
-    fm->file_map = (unsigned long *) xcalloc(fm->nwords, sizeof(unsigned long));
+    fm->file_map = xcalloc(fm->nwords, sizeof(unsigned long));
+    meta_data.misc += fm->nwords * sizeof(unsigned long);
     return (fm);
 }
 
index 49e272921b9cd38799d723f4f977592c93001dac..1f3729e91dcd33616f763d3713bb54022b7e45fe 100644 (file)
-/* $Id: ftp.cc,v 1.39 1996/05/03 22:56:25 wessels Exp $ */
+/*
+ * $Id: ftp.cc,v 1.40 1996/07/09 03:41:25 wessels Exp $
+ *
+ * DEBUG: section 9     File Transfer Protocol (FTP)
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 9           ftp: FTP
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
-#define FTP_DELETE_GAP  (64*1024)
-#define READBUFSIZ     4096
+#define FTP_DELETE_GAP  (1<<18)
 #define MAGIC_MARKER    "\004\004\004" /* No doubt this should be more configurable */
 #define MAGIC_MARKER_SZ 3
 
 static char ftpASCII[] = "A";
 static char ftpBinary[] = "I";
-static char localhost[] = "127.0.0.1";
-static int ftpget_server_pipe = -1;
+static int ftpget_server_read = -1;
+static int ftpget_server_write = -1;
+static u_short ftpget_port = 0;
 
 typedef struct _Ftpdata {
     StoreEntry *entry;
@@ -26,14 +125,10 @@ typedef struct _Ftpdata {
     char *icp_page_ptr;                /* Used to send proxy-http request: 
                                 * put_free_8k_page(me) if the lifetime
                                 * expires */
-    char *icp_rwd_ptr;         /* When a lifetime expires during the
-                                * middle of an icpwrite, don't lose the
-                                * icpReadWriteData */
     int got_marker;            /* denotes end of successful request */
     int reply_hdr_state;
 } FtpData;
 
-
 /* Local functions */
 static int ftpStateFree _PARAMS((int fd, FtpData * ftpState));
 static void ftpProcessReplyHeader _PARAMS((FtpData * data, char *buf, int size));
@@ -43,7 +138,7 @@ static void ftp_login_parser _PARAMS((char *login, FtpData * data));
 /* Global functions not declared in ftp.h */
 void ftpLifetimeExpire _PARAMS((int fd, FtpData * data));
 int ftpReadReply _PARAMS((int fd, FtpData * data));
-void ftpSendComplete _PARAMS((int fd, char *buf, int size, int errflag, FtpData * data));
+void ftpSendComplete _PARAMS((int fd, char *buf, int size, int errflag, void *ftpData));
 void ftpSendRequest _PARAMS((int fd, FtpData * data));
 void ftpConnInProgress _PARAMS((int fd, FtpData * data));
 void ftpServerClose _PARAMS((void));
@@ -54,6 +149,7 @@ static int ftpStateFree(fd, ftpState)
 {
     if (ftpState == NULL)
        return 1;
+    storeUnlockObject(ftpState->entry);
     if (ftpState->reply_hdr) {
        put_free_8k_page(ftpState->reply_hdr);
        ftpState->reply_hdr = NULL;
@@ -62,8 +158,7 @@ static int ftpStateFree(fd, ftpState)
        put_free_8k_page(ftpState->icp_page_ptr);
        ftpState->icp_page_ptr = NULL;
     }
-    if (ftpState->icp_rwd_ptr)
-       safe_free(ftpState->icp_rwd_ptr);
+    requestUnlink(ftpState->request);
     xfree(ftpState);
     return 0;
 }
@@ -126,12 +221,8 @@ static void ftpProcessReplyHeader(data, buf, size)
      char *buf;                        /* chunk just read by ftpReadReply() */
      int size;
 {
-    char *s = NULL;
     char *t = NULL;
-    char *t1 = NULL;
-    char *t2 = NULL;
     StoreEntry *entry = data->entry;
-    char *headers = NULL;
     int room;
     int hdr_len;
     struct _http_reply *reply = NULL;
@@ -152,18 +243,11 @@ static void ftpProcessReplyHeader(data, buf, size)
            data->reply_hdr_state += 2;
            return;
        }
-       /* need to take the lowest, non-zero pointer to the end of the headers.
-        * some objects have \n\n separating header and body, but \r\n\r\n in
-        * body text. */
-       t1 = strstr(data->reply_hdr, "\r\n\r\n");
-       t2 = strstr(data->reply_hdr, "\n\n");
-       if (t1 && t2)
-           t = t2 < t1 ? t2 : t1;
-       else
-           t = t2 ? t2 : t1;
+       /* Find the end of the headers */
+       t = mime_headers_end(data->reply_hdr);
        if (!t)
            return;             /* headers not complete */
-       t += (t == t1 ? 4 : 2);
+       /* Cut after end of headers */
        *t = '\0';
        reply = entry->mem_obj->reply;
        reply->hdr_sz = t - data->reply_hdr;
@@ -171,50 +255,12 @@ static void ftpProcessReplyHeader(data, buf, size)
        data->reply_hdr_state++;
     }
     if (data->reply_hdr_state == 1) {
-       headers = xstrdup(data->reply_hdr);
        data->reply_hdr_state++;
        debug(11, 9, "GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
            data->reply_hdr);
-       t = strtok(headers, "\n");
-       while (t) {
-           s = t + strlen(t);
-           while (*s == '\r')
-               *s-- = '\0';
-           if (!strncasecmp(t, "HTTP", 4)) {
-               sscanf(t + 1, "%lf", &reply->version);
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   reply->code = atoi(t);
-               }
-           } else if (!strncasecmp(t, "Content-type:", 13)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->content_type, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Content-length:", 15)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   reply->content_length = atoi(t);
-               }
-           } else if (!strncasecmp(t, "Date:", 5)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->date, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Expires:", 8)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->expires, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Last-Modified:", 14)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->last_modified, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           }
-           t = strtok(NULL, "\n");
-       }
-       safe_free(headers);
+       /* Parse headers into reply structure */
+       httpParseHeaders(data->reply_hdr, reply);
+       /* Check if object is cacheable or not based on reply code */
        if (reply->code)
            debug(11, 3, "ftpProcessReplyHeader: HTTP CODE: %d\n", reply->code);
        switch (reply->code) {
@@ -228,6 +274,7 @@ static void ftpProcessReplyHeader(data, buf, size)
            if (BIT_TEST(entry->flag, CACHABLE))
                storeSetPublicKey(entry);
            break;
+       case 302:               /* Moved Temporarily */
        case 304:               /* Not Modified */
        case 401:               /* Unauthorized */
        case 407:               /* Proxy Authentication Required */
@@ -254,43 +301,52 @@ int ftpReadReply(fd, data)
      int fd;
      FtpData *data;
 {
-    static char buf[READBUFSIZ];
+    static char buf[SQUID_TCP_SO_RCVBUF];
     int len;
     int clen;
     int off;
+    int bin;
     StoreEntry *entry = NULL;
 
     entry = data->entry;
-    if (entry->flag & DELETE_BEHIND) {
-       if (storeClientWaiting(entry)) {
-           /* check if we want to defer reading */
-           clen = entry->mem_obj->e_current_len;
-           off = entry->mem_obj->e_lowest_offset;
-           if ((clen - off) > FTP_DELETE_GAP) {
-               debug(9, 3, "ftpReadReply: Read deferred for Object: %s\n",
-                   entry->url);
-               debug(9, 3, "--> Current Gap: %d bytes\n", clen - off);
-               /* reschedule, so it will automatically be reactivated when
-                * Gap is big enough. */
-               comm_set_select_handler(fd,
-                   COMM_SELECT_READ,
-                   (PF) ftpReadReply,
-                   (void *) data);
-               /* dont try reading again for a while */
-               comm_set_stall(fd, getStallDelay());
-               return 0;
-           }
-       } else {
-           /* we can terminate connection right now */
-           squid_error_entry(entry, ERR_NO_CLIENTS_BIG_OBJ, NULL);
+    if (entry->flag & DELETE_BEHIND && !storeClientWaiting(entry)) {
+       /* we can terminate connection right now */
+       squid_error_entry(entry, ERR_NO_CLIENTS_BIG_OBJ, NULL);
+       comm_close(fd);
+       return 0;
+    }
+    /* check if we want to defer reading */
+    clen = entry->mem_obj->e_current_len;
+    off = storeGetLowestReaderOffset(entry);
+    if ((clen - off) > FTP_DELETE_GAP) {
+       if (entry->flag & CLIENT_ABORT_REQUEST) {
+           squid_error_entry(entry, ERR_CLIENT_ABORT, NULL);
            comm_close(fd);
-           return 0;
        }
+       IOStats.Ftp.reads_deferred++;
+       debug(11, 3, "ftpReadReply: Read deferred for Object: %s\n",
+           entry->url);
+       debug(11, 3, "                Current Gap: %d bytes\n", clen - off);
+       /* reschedule, so it will be automatically reactivated
+        * when Gap is big enough. */
+       comm_set_select_handler(fd,
+           COMM_SELECT_READ,
+           (PF) ftpReadReply,
+           (void *) data);
+       /* NOTE there is no read timeout handler to disable */
+       /* dont try reading again for a while */
+       comm_set_stall(fd, getStallDelay());
+       return 0;
     }
     errno = 0;
-    len = read(fd, buf, READBUFSIZ);
+    IOStats.Ftp.reads++;
+    len = read(fd, buf, SQUID_TCP_SO_RCVBUF);
     debug(9, 5, "ftpReadReply: FD %d, Read %d bytes\n", fd, len);
-
+    if (len > 0) {
+       for (clen = len - 1, bin = 0; clen; bin++)
+           clen >>= 1;
+       IOStats.Ftp.read_hist[bin]++;
+    }
     if (len < 0) {
        debug(9, 1, "ftpReadReply: read error: %s\n", xstrerror());
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
@@ -317,7 +373,7 @@ int ftpReadReply(fd, data)
            /* If we didn't see the magic marker, assume the transfer
             * failed and arrange so the object gets ejected and
             * never gets to disk. */
-           debug(9, 1, "ftpReadReply: Didn't see magic marker, purging <URL:%s>.\n", entry->url);
+           debug(9, 1, "ftpReadReply: Purging '%s'\n", entry->url);
            entry->expires = squid_curtime + getNegativeTTL();
            BIT_RESET(entry->flag, CACHABLE);
            storeReleaseRequest(entry);
@@ -371,11 +427,12 @@ void ftpSendComplete(fd, buf, size, errflag, data)
      char *buf;
      int size;
      int errflag;
-     FtpData *data;
+     void *data;
 {
+    FtpData *ftpState = (FtpData *) data;
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = ftpState->entry;
     debug(9, 5, "ftpSendComplete: FD %d: size %d: errflag %d.\n",
        fd, size, errflag);
 
@@ -383,22 +440,21 @@ void ftpSendComplete(fd, buf, size, errflag, data)
        put_free_8k_page(buf);  /* Allocated by ftpSendRequest. */
        buf = NULL;
     }
-    data->icp_page_ptr = NULL; /* So lifetime expire doesn't re-free */
-    data->icp_rwd_ptr = NULL;  /* Don't double free in lifetimeexpire */
+    ftpState->icp_page_ptr = NULL;     /* So lifetime expire doesn't re-free */
 
     if (errflag) {
        squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
        comm_close(fd);
        return;
     } else {
-       comm_set_select_handler(data->ftp_fd,
+       comm_set_select_handler(ftpState->ftp_fd,
            COMM_SELECT_READ,
            (PF) ftpReadReply,
-           (void *) data);
-       comm_set_select_handler_plus_timeout(data->ftp_fd,
+           (void *) ftpState);
+       comm_set_select_handler_plus_timeout(ftpState->ftp_fd,
            COMM_SELECT_TIMEOUT,
            (PF) ftpLifetimeExpire,
-           (void *) data, getReadTimeout());
+           (void *) ftpState, getReadTimeout());
     }
 }
 
@@ -441,18 +497,7 @@ void ftpSendRequest(fd, data)
            mode = ftpBinary;
     }
 
-#ifdef NO_NEED_TO_DO_THIS
-    /* Remove leading slash from FTP url-path so that we can
-     *  handle ftp://user:pw@host/path objects where path and /path
-     *  are quite different.         -DW */
-    if (!strcmp(path, "/"))
-       *path = '.';
-    if (*path == '/')
-       path++;
-#endif
-
     /* Start building the buffer ... */
-
     strcat(buf, getFtpProgram());
     strcat(buf, space);
 
@@ -477,6 +522,10 @@ void ftpSendRequest(fd, data)
        sprintf(tbuf, "-P %d ", data->request->port);
        strcat(buf, tbuf);
     }
+    if ((s = getVisibleHostname())) {
+       sprintf(tbuf, "-H %s ", s);
+       strcat(buf, tbuf);
+    }
     strcat(buf, "-h ");                /* httpify */
     strcat(buf, "- ");         /* stdout */
     strcat(buf, data->request->host);
@@ -490,7 +539,7 @@ void ftpSendRequest(fd, data)
     strcat(buf, *data->password ? data->password : "\"\"");
     strcat(buf, "\n");
     debug(9, 5, "ftpSendRequest: FD %d: buf '%s'\n", fd, buf);
-    data->icp_rwd_ptr = icpWrite(fd,
+    comm_write(fd,
        buf,
        strlen(buf),
        30,
@@ -506,7 +555,7 @@ void ftpConnInProgress(fd, data)
 
     debug(9, 5, "ftpConnInProgress: FD %d\n", fd);
 
-    if (comm_connect(fd, localhost, CACHE_FTP_PORT) != COMM_OK) {
+    if (comm_connect(fd, localhost, ftpget_port) != COMM_OK) {
        switch (errno) {
        case EINPROGRESS:
        case EALREADY:
@@ -541,9 +590,9 @@ int ftpStart(unusedfd, url, request, entry)
 
     debug(9, 3, "FtpStart: FD %d <URL:%s>\n", unusedfd, url);
 
-    data = (FtpData *) xcalloc(1, sizeof(FtpData));
-    data->entry = entry;
-    data->request = request;
+    data = xcalloc(1, sizeof(FtpData));
+    storeLockObject(data->entry = entry, NULL, NULL);
+    data->request = requestLink(request);
 
     /* Parse login info. */
     ftp_login_parser(request->login, data);
@@ -552,22 +601,24 @@ int ftpStart(unusedfd, url, request, entry)
        unusedfd, data->request->host, data->request->urlpath,
        data->user, data->password);
 
-    data->ftp_fd = comm_open(COMM_NONBLOCKING, 0, 0, url);
+    data->ftp_fd = comm_open(COMM_NONBLOCKING,
+       local_addr,
+       0,
+       url);
     if (data->ftp_fd == COMM_ERROR) {
        squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
-       safe_free(data);
+       ftpStateFree(-1, data);
        return COMM_ERROR;
     }
     /* Pipe/socket created ok */
 
     /* register close handler */
-    comm_set_select_handler(data->ftp_fd,
-       COMM_SELECT_CLOSE,
+    comm_add_close_handler(data->ftp_fd,
        (PF) ftpStateFree,
        (void *) data);
 
     /* Now connect ... */
-    if ((status = comm_connect(data->ftp_fd, localhost, CACHE_FTP_PORT))) {
+    if ((status = comm_connect(data->ftp_fd, localhost, ftpget_port))) {
        if (status != EINPROGRESS) {
            squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
            comm_close(data->ftp_fd);
@@ -581,7 +632,7 @@ int ftpStart(unusedfd, url, request, entry)
            return COMM_OK;
        }
     }
-    fdstat_open(data->ftp_fd, Socket);
+    fdstat_open(data->ftp_fd, FD_SOCKET);
     commSetNonBlocking(data->ftp_fd);
     (void) fd_note(data->ftp_fd, entry->url);
 
@@ -618,60 +669,99 @@ static void ftpServerClosed(fd, nodata)
 
 void ftpServerClose()
 {
-    if (ftpget_server_pipe < 0)
+    /* NOTE: this function will be called repeatedly while shutdown is
+     * pending */
+    if (ftpget_server_read < 0)
        return;
-
-    comm_set_select_handler(ftpget_server_pipe,
-       COMM_SELECT_EXCEPT,
+    comm_set_select_handler(ftpget_server_read,
+       COMM_SELECT_READ,
        (PF) NULL,
        (void *) NULL);
-    fdstat_close(ftpget_server_pipe);
-    close(ftpget_server_pipe);
-    ftpget_server_pipe = -1;
+    fdstat_close(ftpget_server_read);
+    close(ftpget_server_read);
+    fdstat_close(ftpget_server_write);
+    close(ftpget_server_write);
+    ftpget_server_read = -1;
+    ftpget_server_write = -1;
 }
 
 
 int ftpInitialize()
 {
     int pid;
-    int fd;
-    int p[2];
-    char pbuf[128];
+    int cfd;
+    int squid_to_ftpget[2];
+    int ftpget_to_squid[2];
+    static char pbuf[128];
     char *ftpget = getFtpProgram();
+    struct sockaddr_in S;
+    int len;
 
-    if (pipe(p) < 0) {
+    if (pipe(squid_to_ftpget) < 0) {
        debug(9, 0, "ftpInitialize: pipe: %s\n", xstrerror());
        return -1;
     }
+    if (pipe(ftpget_to_squid) < 0) {
+       debug(9, 0, "ftpInitialize: pipe: %s\n", xstrerror());
+       return -1;
+    }
+    cfd = comm_open(COMM_NOCLOEXEC,
+       local_addr,
+       0,
+       "ftpget -S socket");
+    if (cfd == COMM_ERROR) {
+       debug(9, 0, "ftpInitialize: Failed to create socket\n");
+       return -1;
+    }
+    len = sizeof(S);
+    memset(&S, '\0', len);
+    if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) {
+       debug(9, 0, "ftpInitialize: getsockname: %s\n", xstrerror());
+       comm_close(cfd);
+       return -1;
+    }
+    ftpget_port = ntohs(S.sin_port);
+    listen(cfd, FD_SETSIZE >> 2);
     if ((pid = fork()) < 0) {
        debug(9, 0, "ftpInitialize: fork: %s\n", xstrerror());
+       comm_close(cfd);
        return -1;
     }
     if (pid != 0) {            /* parent */
-       close(p[0]);
-       fdstat_open(p[1], Pipe);
-       fd_note(p[1], "ftpget -S");
-       fcntl(p[1], F_SETFD, 1);        /* set close-on-exec */
+       comm_close(cfd);
+       close(squid_to_ftpget[0]);
+       close(ftpget_to_squid[1]);
+       fdstat_open(squid_to_ftpget[1], FD_PIPE);
+       fdstat_open(ftpget_to_squid[0], FD_PIPE);
+       fd_note(squid_to_ftpget[1], "ftpget -S");
+       fd_note(ftpget_to_squid[0], "ftpget -S");
+       fcntl(squid_to_ftpget[1], F_SETFD, 1);  /* set close-on-exec */
+       fcntl(ftpget_to_squid[0], F_SETFD, 1);  /* set close-on-exec */
        /* if ftpget -S goes away, this handler should get called */
-       comm_set_select_handler(p[1],
-           COMM_SELECT_EXCEPT,
+       comm_set_select_handler(ftpget_to_squid[0],
+           COMM_SELECT_READ,
            (PF) ftpServerClosed,
            (void *) NULL);
-       ftpget_server_pipe = p[1];
+       ftpget_server_write = squid_to_ftpget[1];
+       ftpget_server_read = ftpget_to_squid[0];
        return 0;
     }
     /* child */
     /* give up all extra priviligies */
     no_suid();
     /* set up stdin,stdout */
-    dup2(p[0], 0);
+    dup2(squid_to_ftpget[0], 0);
+    dup2(ftpget_to_squid[1], 1);
     dup2(fileno(debug_log), 2);
-    close(p[0]);
-    close(p[1]);
+    close(squid_to_ftpget[0]);
+    close(squid_to_ftpget[1]);
+    close(ftpget_to_squid[0]);
+    close(ftpget_to_squid[1]);
+    dup2(cfd, 3);              /* pass listening socket to ftpget */
     /* inherit stdin,stdout,stderr */
-    for (fd = 3; fd < fdstat_biggest_fd(); fd++)
-       (void) close(fd);
-    sprintf(pbuf, "%d", CACHE_FTP_PORT);
+    for (cfd = 4; cfd <= fdstat_biggest_fd(); cfd++)
+       (void) close(cfd);
+    sprintf(pbuf, "%d", ftpget_port);
     execlp(ftpget, ftpget, "-S", pbuf, NULL);
     debug(9, 0, "ftpInitialize: %s: %s\n", ftpget, xstrerror());
     _exit(1);
index 8bb70b80d5093dc30aacad89675e2abce2d1e0e7..b6687afc06fe6140ed0539ce47fa23bff0c1a746 100644 (file)
@@ -1,7 +1,106 @@
-/* $Id: gopher.cc,v 1.30 1996/05/03 22:56:27 wessels Exp $ */
+/*
+ * $Id: gopher.cc,v 1.31 1996/07/09 03:41:26 wessels Exp $
+ *
+ * DEBUG: section 10    Gopher
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 10          gopher: GOPHER
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
@@ -58,7 +157,6 @@ typedef struct gopher_ds {
     int len;
     char *buf;                 /* pts to a 4k page */
     char *icp_page_ptr;                /* Pts to gopherStart buffer that needs to be freed */
-    char *icp_rwd_ptr;         /* Pts to icp rw structure that needs to be freed */
 } GopherData;
 
 GopherData *CreateGopherData();
@@ -72,6 +170,8 @@ static int gopherStateFree(fd, gopherState)
 {
     if (gopherState == NULL)
        return 1;
+    if (gopherState->entry)
+       storeUnlockObject(gopherState->entry);
     put_free_4k_page(gopherState->buf);
     xfree(gopherState);
     return 0;
@@ -339,7 +439,7 @@ void gopherToHTML(data, inbuf, len)
                        entry->url);
                    len = TEMP_BUF_SIZE - data->len;
                }
-               memcpy(data->buf + data->len, inbuf, len);
+               xmemcpy(data->buf + data->len, inbuf, len);
                data->len += len;
                return;
            }
@@ -366,7 +466,7 @@ void gopherToHTML(data, inbuf, len)
                    len = TEMP_BUF_SIZE;
                }
                if (len > (pos - inbuf)) {
-                   memcpy(data->buf, pos, len - (pos - inbuf));
+                   xmemcpy(data->buf, pos, len - (pos - inbuf));
                    data->len = len - (pos - inbuf);
                }
                break;
@@ -493,7 +593,7 @@ void gopherToHTML(data, inbuf, len)
                int t;
                int code;
                int recno;
-               char result[MAX_CSO_RESULT];
+               static char result[MAX_CSO_RESULT];
 
                tline = line;
 
@@ -571,8 +671,6 @@ int gopherReadReplyTimeout(fd, data)
     squid_error_entry(entry, ERR_READ_TIMEOUT, NULL);
     if (data->icp_page_ptr)
        put_free_4k_page(data->icp_page_ptr);
-    if (data->icp_rwd_ptr)
-       safe_free(data->icp_rwd_ptr);
     comm_close(fd);
     return 0;
 }
@@ -588,8 +686,6 @@ void gopherLifetimeExpire(fd, data)
     squid_error_entry(entry, ERR_LIFETIME_EXP, NULL);
     if (data->icp_page_ptr)
        put_free_4k_page(data->icp_page_ptr);
-    if (data->icp_rwd_ptr)
-       safe_free(data->icp_rwd_ptr);
     comm_set_select_handler(fd,
        COMM_SELECT_READ | COMM_SELECT_WRITE,
        0,
@@ -738,10 +834,11 @@ void gopherSendComplete(fd, buf, size, errflag, data)
      char *buf;
      int size;
      int errflag;
-     GopherData *data;
+     void *data;
 {
+    GopherData *gopherState = (GopherData *) data;
     StoreEntry *entry = NULL;
-    entry = data->entry;
+    entry = gopherState->entry;
     debug(10, 5, "gopherSendComplete: FD %d size: %d errflag: %d\n",
        fd, size, errflag);
     if (errflag) {
@@ -755,55 +852,54 @@ void gopherSendComplete(fd, buf, size, errflag, data)
      * OK. We successfully reach remote site.  Start MIME typing
      * stuff.  Do it anyway even though request is not HTML type.
      */
-    gopherMimeCreate(data);
+    gopherMimeCreate(gopherState);
 
     if (!BIT_TEST(entry->flag, ENTRY_HTML))
-       data->conversion = NORMAL;
+       gopherState->conversion = NORMAL;
     else
-       switch (data->type_id) {
+       switch (gopherState->type_id) {
 
        case GOPHER_DIRECTORY:
            /* we got to convert it first */
            BIT_SET(entry->flag, DELAY_SENDING);
-           data->conversion = HTML_DIR;
-           data->HTML_header_added = 0;
+           gopherState->conversion = HTML_DIR;
+           gopherState->HTML_header_added = 0;
            break;
 
        case GOPHER_INDEX:
            /* we got to convert it first */
            BIT_SET(entry->flag, DELAY_SENDING);
-           data->conversion = HTML_INDEX_RESULT;
-           data->HTML_header_added = 0;
+           gopherState->conversion = HTML_INDEX_RESULT;
+           gopherState->HTML_header_added = 0;
            break;
 
        case GOPHER_CSO:
            /* we got to convert it first */
            BIT_SET(entry->flag, DELAY_SENDING);
-           data->conversion = HTML_CSO_RESULT;
-           data->cso_recno = 0;
-           data->HTML_header_added = 0;
+           gopherState->conversion = HTML_CSO_RESULT;
+           gopherState->cso_recno = 0;
+           gopherState->HTML_header_added = 0;
            break;
 
        default:
-           data->conversion = NORMAL;
+           gopherState->conversion = NORMAL;
 
        }
     /* Schedule read reply. */
     comm_set_select_handler(fd,
        COMM_SELECT_READ,
        (PF) gopherReadReply,
-       (void *) data);
+       (void *) gopherState);
     comm_set_select_handler_plus_timeout(fd,
        COMM_SELECT_TIMEOUT,
        (PF) gopherReadReplyTimeout,
-       (void *) data,
+       (void *) gopherState,
        getReadTimeout());
-    comm_set_fd_lifetime(fd, -1);      /* disable */
+    comm_set_fd_lifetime(fd, 86400);   /* extend lifetime */
 
     if (buf)
        put_free_4k_page(buf);  /* Allocated by gopherSendRequest. */
-    data->icp_page_ptr = NULL;
-    data->icp_rwd_ptr = NULL;
+    gopherState->icp_page_ptr = NULL;
 }
 
 /* This will be called when connect completes. Write request. */
@@ -834,7 +930,7 @@ void gopherSendRequest(fd, data)
     }
 
     debug(10, 5, "gopherSendRequest: FD %d\n", fd);
-    data->icp_rwd_ptr = icpWrite(fd,
+    comm_write(fd,
        buf,
        len,
        30,
@@ -853,7 +949,7 @@ int gopherStart(unusedfd, url, entry)
     int sock, status;
     GopherData *data = CreateGopherData();
 
-    data->entry = entry;
+    storeLockObject(data->entry = entry, NULL, NULL);
 
     debug(10, 3, "gopherStart: url: %s\n", url);
 
@@ -865,22 +961,21 @@ int gopherStart(unusedfd, url, entry)
        return COMM_ERROR;
     }
     /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
+    sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
     if (sock == COMM_ERROR) {
        debug(10, 4, "gopherStart: Failed because we're out of sockets.\n");
        squid_error_entry(entry, ERR_NO_FDS, xstrerror());
        gopherStateFree(-1, data);
        return COMM_ERROR;
     }
-    comm_set_select_handler(sock,
-       COMM_SELECT_CLOSE,
+    comm_add_close_handler(sock,
        (PF) gopherStateFree,
        (void *) data);
 
     /* check if IP is already in cache. It must be. 
      * It should be done before this route is called. 
      * Otherwise, we cannot check return code for connect. */
-    if (!ipcache_gethostbyname(data->host)) {
+    if (!ipcache_gethostbyname(data->host, 0)) {
        debug(10, 4, "gopherStart: Called without IP entry in ipcache. OR lookup failed.\n");
        squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
        comm_close(sock);
@@ -932,7 +1027,7 @@ int gopherStart(unusedfd, url, entry)
 
 GopherData *CreateGopherData()
 {
-    GopherData *gd = (GopherData *) xcalloc(1, sizeof(GopherData));
+    GopherData *gd = xcalloc(1, sizeof(GopherData));
     gd->buf = get_free_4k_page();
     return (gd);
 }
index 57d0d1311433557df24f8b27e7a2be3198e93ff5..64c566e84f9ce0ae8f63c823daa2fd5be7eaa148 100644 (file)
-/* $Id: http.cc,v 1.58 1996/05/03 22:56:27 wessels Exp $ */
+/*
+ * $Id: http.cc,v 1.59 1996/07/09 03:41:28 wessels Exp $
+ *
+ * DEBUG: section 11    Hypertext Transfer Protocol (HTTP)
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 11          http: HTTP
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
-#define READBUFSIZ     (1<<14)
 #define HTTP_DELETE_GAP   (1<<18)
 
-typedef struct _httpdata {
-    StoreEntry *entry;
-    request_t *request;
-    char *req_hdr;
-    char *icp_page_ptr;                /* Used to send proxy-http request: 
-                                * put_free_8k_page(me) if the lifetime
-                                * expires */
-    char *icp_rwd_ptr;         /* When a lifetime expires during the
-                                * middle of an icpwrite, don't lose the
-                                * icpReadWriteData */
-    char *reply_hdr;
-    int reply_hdr_state;
-    int free_request;
-} HttpData;
+struct {
+    int parsed;
+    int date;
+    int lm;
+    int exp;
+    int clen;
+    int ctype;
+} ReplyHeaderStats;
 
 static int httpStateFree(fd, httpState)
      int fd;
-     HttpData *httpState;
+     HttpStateData *httpState;
 {
     if (httpState == NULL)
        return 1;
+    storeUnlockObject(httpState->entry);
     if (httpState->reply_hdr) {
        put_free_8k_page(httpState->reply_hdr);
        httpState->reply_hdr = NULL;
     }
-    if (httpState->icp_page_ptr) {
-       put_free_8k_page(httpState->icp_page_ptr);
-       httpState->icp_page_ptr = NULL;
+    if (httpState->reqbuf && httpState->buf_type == BUF_TYPE_8K) {
+       put_free_8k_page(httpState->reqbuf);
+       httpState->reqbuf = NULL;
+    } else {
+       safe_free(httpState->reqbuf)
     }
-    if (httpState->icp_rwd_ptr)
-       safe_free(httpState->icp_rwd_ptr);
-    if (httpState->free_request)
-       safe_free(httpState->request);
+    requestUnlink(httpState->request);
     xfree(httpState);
     return 0;
 }
@@ -67,13 +159,13 @@ int httpCachable(url, method)
 }
 
 /* This will be called when timeout on read. */
-static void httpReadReplyTimeout(fd, data)
+static void httpReadReplyTimeout(fd, httpState)
      int fd;
-     HttpData *data;
+     HttpStateData *httpState;
 {
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = httpState->entry;
     debug(11, 4, "httpReadReplyTimeout: FD %d: <URL:%s>\n", fd, entry->url);
     squid_error_entry(entry, ERR_READ_TIMEOUT, NULL);
     comm_set_select_handler(fd, COMM_SELECT_READ, 0, 0);
@@ -81,13 +173,13 @@ static void httpReadReplyTimeout(fd, data)
 }
 
 /* This will be called when socket lifetime is expired. */
-static void httpLifetimeExpire(fd, data)
+static void httpLifetimeExpire(fd, httpState)
      int fd;
-     HttpData *data;
+     HttpStateData *httpState;
 {
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = httpState->entry;
     debug(11, 4, "httpLifeTimeExpire: FD %d: <URL:%s>\n", fd, entry->url);
 
     squid_error_entry(entry, ERR_LIFETIME_EXP, NULL);
@@ -95,128 +187,194 @@ static void httpLifetimeExpire(fd, data)
     comm_close(fd);
 }
 
+/* This object can be cached for a long time */
+static void httpMakePublic(entry)
+     StoreEntry *entry;
+{
+    entry->expires = squid_curtime + ttlSet(entry);
+    if (BIT_TEST(entry->flag, CACHABLE))
+       storeSetPublicKey(entry);
+}
+
+/* This object should never be cached at all */
+static void httpMakePrivate(entry)
+     StoreEntry *entry;
+{
+    storeSetPrivateKey(entry);
+    storeExpireNow(entry);
+    BIT_RESET(entry->flag, CACHABLE);
+    storeReleaseRequest(entry);        /* delete object when not used */
+}
+
+/* This object may be negatively cached */
+static void httpCacheNegatively(entry)
+     StoreEntry *entry;
+{
+    entry->expires = squid_curtime + getNegativeTTL();
+    if (BIT_TEST(entry->flag, CACHABLE))
+       storeSetPublicKey(entry);
+    /* XXX: mark object "not to store on disk"? */
+}
+
+
+/* Build a reply structure from HTTP reply headers */
+void httpParseHeaders(buf, reply)
+     char *buf;
+     struct _http_reply *reply;
+{
+    char *headers = NULL;
+    char *t = NULL;
+    char *s = NULL;
+
+    ReplyHeaderStats.parsed++;
+    headers = xstrdup(buf);
+    t = strtok(headers, "\n");
+    while (t) {
+       s = t + strlen(t);
+       while (*s == '\r')
+           *s-- = '\0';
+       if (!strncasecmp(t, "HTTP", 4)) {
+           sscanf(t + 1, "%lf", &reply->version);
+           if ((t = strchr(t, ' '))) {
+               t++;
+               reply->code = atoi(t);
+           }
+       } else if (!strncasecmp(t, "Content-type:", 13)) {
+           if ((t = strchr(t, ' '))) {
+               t++;
+               strncpy(reply->content_type, t, HTTP_REPLY_FIELD_SZ - 1);
+               ReplyHeaderStats.ctype++;
+           }
+       } else if (!strncasecmp(t, "Content-length:", 15)) {
+           if ((t = strchr(t, ' '))) {
+               t++;
+               reply->content_length = atoi(t);
+               ReplyHeaderStats.clen++;
+           }
+       } else if (!strncasecmp(t, "Date:", 5)) {
+           if ((t = strchr(t, ' '))) {
+               t++;
+               strncpy(reply->date, t, HTTP_REPLY_FIELD_SZ - 1);
+               ReplyHeaderStats.date++;
+           }
+       } else if (!strncasecmp(t, "Expires:", 8)) {
+           if ((t = strchr(t, ' '))) {
+               t++;
+               strncpy(reply->expires, t, HTTP_REPLY_FIELD_SZ - 1);
+               ReplyHeaderStats.exp++;
+           }
+       } else if (!strncasecmp(t, "Last-Modified:", 14)) {
+           if ((t = strchr(t, ' '))) {
+               t++;
+               strncpy(reply->last_modified, t, HTTP_REPLY_FIELD_SZ - 1);
+               ReplyHeaderStats.lm++;
+           }
+       }
+       t = strtok(NULL, "\n");
+    }
+    safe_free(headers);
+}
+
 
-static void httpProcessReplyHeader(data, buf, size)
-     HttpData *data;
+void httpProcessReplyHeader(httpState, buf, size)
+     HttpStateData *httpState;
      char *buf;                        /* chunk just read by httpReadReply() */
      int size;
 {
-    char *s = NULL;
     char *t = NULL;
-    char *t1 = NULL;
-    char *t2 = NULL;
-    StoreEntry *entry = data->entry;
-    char *headers = NULL;
+    StoreEntry *entry = httpState->entry;
     int room;
     int hdr_len;
     struct _http_reply *reply = NULL;
 
     debug(11, 3, "httpProcessReplyHeader: key '%s'\n", entry->key);
 
-    if (data->reply_hdr == NULL) {
-       data->reply_hdr = get_free_8k_page();
-       memset(data->reply_hdr, '\0', 8192);
+    if (httpState->reply_hdr == NULL) {
+       httpState->reply_hdr = get_free_8k_page();
+       memset(httpState->reply_hdr, '\0', 8192);
     }
-    if (data->reply_hdr_state == 0) {
-       hdr_len = strlen(data->reply_hdr);
+    if (httpState->reply_hdr_state == 0) {
+       hdr_len = strlen(httpState->reply_hdr);
        room = 8191 - hdr_len;
-       strncat(data->reply_hdr, buf, room < size ? room : size);
+       strncat(httpState->reply_hdr, buf, room < size ? room : size);
        hdr_len += room < size ? room : size;
-       if (hdr_len > 4 && strncmp(data->reply_hdr, "HTTP/", 5)) {
+       if (hdr_len > 4 && strncmp(httpState->reply_hdr, "HTTP/", 5)) {
            debug(11, 3, "httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", entry->key);
-           data->reply_hdr_state += 2;
+           httpState->reply_hdr_state += 2;
            return;
        }
-       /* need to take the lowest, non-zero pointer to the end of the headers.
-        * some objects have \n\n separating header and body, but \r\n\r\n in
-        * body text. */
-       t1 = strstr(data->reply_hdr, "\r\n\r\n");
-       t2 = strstr(data->reply_hdr, "\n\n");
-       if (t1 && t2)
-           t = t2 < t1 ? t2 : t1;
-       else
-           t = t2 ? t2 : t1;
+       /* Find the end of the headers */
+       t = mime_headers_end(httpState->reply_hdr);
        if (!t)
+           /* XXX: Here we could check for buffer overflow... */
            return;             /* headers not complete */
-       t += (t == t1 ? 4 : 2);
+       /* Cut after end of headers */
        *t = '\0';
        reply = entry->mem_obj->reply;
-       reply->hdr_sz = t - data->reply_hdr;
+       reply->hdr_sz = t - httpState->reply_hdr;
        debug(11, 7, "httpProcessReplyHeader: hdr_sz = %d\n", reply->hdr_sz);
-       data->reply_hdr_state++;
+       httpState->reply_hdr_state++;
     }
-    if (data->reply_hdr_state == 1) {
-       headers = xstrdup(data->reply_hdr);
-       data->reply_hdr_state++;
+    if (httpState->reply_hdr_state == 1) {
+       httpState->reply_hdr_state++;
        debug(11, 9, "GOT HTTP REPLY HDR:\n---------\n%s\n----------\n",
-           data->reply_hdr);
-       t = strtok(headers, "\n");
-       while (t) {
-           s = t + strlen(t);
-           while (*s == '\r')
-               *s-- = '\0';
-           if (!strncasecmp(t, "HTTP", 4)) {
-               sscanf(t + 1, "%lf", &reply->version);
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   reply->code = atoi(t);
-               }
-           } else if (!strncasecmp(t, "Content-type:", 13)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->content_type, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Content-length:", 15)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   reply->content_length = atoi(t);
-               }
-           } else if (!strncasecmp(t, "Date:", 5)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->date, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Expires:", 8)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->expires, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           } else if (!strncasecmp(t, "Last-Modified:", 14)) {
-               if ((t = strchr(t, ' '))) {
-                   t++;
-                   strncpy(reply->last_modified, t, HTTP_REPLY_FIELD_SZ - 1);
-               }
-           }
-           t = strtok(NULL, "\n");
-       }
-       safe_free(headers);
+           httpState->reply_hdr);
+       /* Parse headers into reply structure */
+       httpParseHeaders(httpState->reply_hdr, reply);
+       /* Check if object is cacheable or not based on reply code */
        if (reply->code)
            debug(11, 3, "httpProcessReplyHeader: HTTP CODE: %d\n", reply->code);
        switch (reply->code) {
+           /* Responses that are cacheable */
        case 200:               /* OK */
        case 203:               /* Non-Authoritative Information */
        case 300:               /* Multiple Choices */
        case 301:               /* Moved Permanently */
        case 410:               /* Gone */
-           /* These can be cached for a long time, make the key public */
-           entry->expires = squid_curtime + ttlSet(entry);
-           if (BIT_TEST(entry->flag, CACHABLE))
-               storeSetPublicKey(entry);
+           /* don't cache objects from neighbors w/o LMT, Date, or Expires */
+           if (*reply->date)
+               httpMakePublic(entry);
+           else if (*reply->last_modified)
+               httpMakePublic(entry);
+           else if (!httpState->neighbor)
+               httpMakePublic(entry);
+           else if (*reply->expires)
+               httpMakePublic(entry);
+           else
+               httpMakePrivate(entry);
+           break;
+           /* Responses that only are cacheable if the server says so */
+       case 302:               /* Moved temporarily */
+           if (*reply->expires)
+               httpMakePublic(entry);
+           else
+               httpMakePrivate(entry);
            break;
+           /* Errors can be negatively cached */
+       case 204:               /* No Content */
+       case 305:               /* Use Proxy (proxy redirect) */
+       case 400:               /* Bad Request */
+       case 403:               /* Forbidden */
+       case 404:               /* Not Found */
+       case 405:               /* Method Now Allowed */
+       case 414:               /* Request-URI Too Long */
+       case 500:               /* Internal Server Error */
+       case 501:               /* Not Implemented */
+       case 502:               /* Bad Gateway */
+       case 503:               /* Service Unavailable */
+       case 504:               /* Gateway Timeout */
+           if (*reply->expires)
+               httpMakePublic(entry);
+           else
+               httpCacheNegatively(entry);
+           break;
+           /* Some responses can never be cached */
+       case 303:               /* See Other */
        case 304:               /* Not Modified */
        case 401:               /* Unauthorized */
        case 407:               /* Proxy Authentication Required */
-           /* These should never be cached at all */
-           storeSetPrivateKey(entry);
-           storeExpireNow(entry);
-           BIT_RESET(entry->flag, CACHABLE);
-           storeReleaseRequest(entry);
-           break;
-       default:
-           /* These can be negative cached, make key public */
-           entry->expires = squid_curtime + getNegativeTTL();
-           if (BIT_TEST(entry->flag, CACHABLE))
-               storeSetPublicKey(entry);
+       default:                /* Unknown status code */
+           httpMakePrivate(entry);
            break;
        }
     }
@@ -226,17 +384,18 @@ static void httpProcessReplyHeader(data, buf, size)
 /* This will be called when data is ready to be read from fd.  Read until
  * error or connection closed. */
 /* XXX this function is too long! */
-static void httpReadReply(fd, data)
+static void httpReadReply(fd, httpState)
      int fd;
-     HttpData *data;
+     HttpStateData *httpState;
 {
-    static char buf[READBUFSIZ];
+    static char buf[SQUID_TCP_SO_RCVBUF];
     int len;
+    int bin;
     int clen;
     int off;
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = httpState->entry;
     if (entry->flag & DELETE_BEHIND && !storeClientWaiting(entry)) {
        /* we can terminate connection right now */
        squid_error_entry(entry, ERR_NO_CLIENTS_BIG_OBJ, NULL);
@@ -247,6 +406,12 @@ static void httpReadReply(fd, data)
     clen = entry->mem_obj->e_current_len;
     off = storeGetLowestReaderOffset(entry);
     if ((clen - off) > HTTP_DELETE_GAP) {
+       if (entry->flag & CLIENT_ABORT_REQUEST) {
+           squid_error_entry(entry, ERR_CLIENT_ABORT, NULL);
+           comm_close(fd);
+           return;
+       }
+       IOStats.Http.reads_deferred++;
        debug(11, 3, "httpReadReply: Read deferred for Object: %s\n",
            entry->url);
        debug(11, 3, "                Current Gap: %d bytes\n", clen - off);
@@ -255,21 +420,28 @@ static void httpReadReply(fd, data)
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) httpReadReply,
-           (void *) data);
-       /* don't install read timeout until we are below the GAP */
+           (void *) httpState);
+       /* disable read timeout until we are below the GAP */
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) NULL,
            (void *) NULL,
            (time_t) 0);
+       comm_set_fd_lifetime(fd, 3600);         /* limit during deferring */
        /* dont try reading again for a while */
        comm_set_stall(fd, getStallDelay());
        return;
     }
     errno = 0;
-    len = read(fd, buf, READBUFSIZ);
+    IOStats.Http.reads++;
+    len = read(fd, buf, SQUID_TCP_SO_RCVBUF);
     debug(11, 5, "httpReadReply: FD %d: len %d.\n", fd, len);
-
+    comm_set_fd_lifetime(fd, 86400);   /* extend after good read */
+    if (len > 0) {
+       for (clen = len - 1, bin = 0; clen; bin++)
+           clen >>= 1;
+       IOStats.Http.read_hist[bin]++;
+    }
     if (len < 0) {
        debug(11, 2, "httpReadReply: FD %d: read failure: %s.\n",
            fd, xstrerror());
@@ -277,9 +449,9 @@ static void httpReadReply(fd, data)
            /* reinstall handlers */
            /* XXX This may loop forever */
            comm_set_select_handler(fd, COMM_SELECT_READ,
-               (PF) httpReadReply, (void *) data);
+               (PF) httpReadReply, (void *) httpState);
            comm_set_select_handler_plus_timeout(fd, COMM_SELECT_TIMEOUT,
-               (PF) httpReadReplyTimeout, (void *) data, getReadTimeout());
+               (PF) httpReadReplyTimeout, (void *) httpState, getReadTimeout());
        } else {
            BIT_RESET(entry->flag, CACHABLE);
            storeReleaseRequest(entry);
@@ -303,11 +475,11 @@ static void httpReadReply(fd, data)
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) httpReadReply,
-           (void *) data);
+           (void *) httpState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) httpReadReplyTimeout,
-           (void *) data, getReadTimeout());
+           (void *) httpState, getReadTimeout());
     } else if (entry->flag & CLIENT_ABORT_REQUEST) {
        /* append the last bit of info we get */
        storeAppend(entry, buf, len);
@@ -315,16 +487,16 @@ static void httpReadReply(fd, data)
        comm_close(fd);
     } else {
        storeAppend(entry, buf, len);
-       if (data->reply_hdr_state < 2 && len > 0)
-           httpProcessReplyHeader(data, buf, len);
+       if (httpState->reply_hdr_state < 2 && len > 0)
+           httpProcessReplyHeader(httpState, buf, len);
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) httpReadReply,
-           (void *) data);
+           (void *) httpState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) httpReadReplyTimeout,
-           (void *) data,
+           (void *) httpState,
            getReadTimeout());
     }
 }
@@ -336,20 +508,21 @@ static void httpSendComplete(fd, buf, size, errflag, data)
      char *buf;
      int size;
      int errflag;
-     HttpData *data;
+     void *data;
 {
+    HttpStateData *httpState = data;
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = httpState->entry;
     debug(11, 5, "httpSendComplete: FD %d: size %d: errflag %d.\n",
        fd, size, errflag);
 
-    if (buf) {
-       put_free_8k_page(buf);  /* Allocated by httpSendRequest. */
-       buf = NULL;
+    if (httpState->reqbuf && httpState->buf_type == BUF_TYPE_8K) {
+       put_free_8k_page(httpState->reqbuf);
+       httpState->reqbuf = NULL;
+    } else {
+       safe_free(httpState->reqbuf);
     }
-    data->icp_page_ptr = NULL; /* So lifetime expire doesn't re-free */
-    data->icp_rwd_ptr = NULL;  /* Don't double free in lifetimeexpire */
 
     if (errflag) {
        squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
@@ -360,20 +533,20 @@ static void httpSendComplete(fd, buf, size, errflag, data)
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) httpReadReply,
-           (void *) data);
+           (void *) httpState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) httpReadReplyTimeout,
-           (void *) data,
+           (void *) httpState,
            getReadTimeout());
-       comm_set_fd_lifetime(fd, -1);   /* disable lifetime DPW */
+       comm_set_fd_lifetime(fd, 86400);        /* extend lifetime */
     }
 }
 
 /* This will be called when connect completes. Write request. */
-static void httpSendRequest(fd, data)
+static void httpSendRequest(fd, httpState)
      int fd;
-     HttpData *data;
+     HttpStateData *httpState;
 {
     char *xbuf = NULL;
     char *ybuf = NULL;
@@ -385,34 +558,37 @@ static void httpSendRequest(fd, data)
     int len = 0;
     int buflen;
     int cfd = -1;
-    request_t *req = data->request;
+    request_t *req = httpState->request;
     char *Method = RequestMethodStr[req->method];
 
-    debug(11, 5, "httpSendRequest: FD %d: data %p.\n", fd, data);
+    debug(11, 5, "httpSendRequest: FD %d: httpState %p.\n", fd, httpState);
     buflen = strlen(Method) + strlen(req->urlpath);
-    if (data->req_hdr)
-       buflen += strlen(data->req_hdr);
+    if (httpState->req_hdr)
+       buflen += strlen(httpState->req_hdr);
     buflen += 512;             /* lots of extra */
 
-    if (req->method == METHOD_POST && data->req_hdr) {
-       if ((t = strstr(data->req_hdr, "\r\n\r\n"))) {
-           post_buf = xstrdup(t + 4);
-           *(t + 4) = '\0';
+    if ((req->method == METHOD_POST || req->method == METHOD_PUT) && httpState->req_hdr) {
+       if ((t = mime_headers_end(httpState->req_hdr))) {
+           post_buf = xstrdup(t);
+           *t = '\0';
        }
     }
-    /* Since we limit the URL read to a 4K page, I doubt that the
-     * mime header could be longer than an 8K page */
-    buf = (char *) get_free_8k_page();
-    data->icp_page_ptr = buf;
-    if (buflen > DISK_PAGE_SIZE) {
-       debug(11, 0, "Mime header length %d is breaking ICP code\n", buflen);
+    if (buflen < DISK_PAGE_SIZE) {
+       httpState->reqbuf = get_free_8k_page();
+       memset(httpState->reqbuf, '\0', buflen);
+       httpState->buf_type = BUF_TYPE_8K;
+    } else {
+       httpState->reqbuf = xcalloc(buflen, 1);
+       httpState->buf_type = BUF_TYPE_MALLOC;
     }
-    memset(buf, '\0', buflen);
+    buf = httpState->reqbuf;
 
-    sprintf(buf, "%s %s HTTP/1.0\r\n", Method, req->urlpath);
+    sprintf(buf, "%s %s HTTP/1.0\r\n",
+       Method,
+       *req->urlpath ? req->urlpath : "/");
     len = strlen(buf);
-    if (data->req_hdr) {       /* we have to parse the request header */
-       xbuf = xstrdup(data->req_hdr);
+    if (httpState->req_hdr) {  /* we have to parse the request header */
+       xbuf = xstrdup(httpState->req_hdr);
        for (t = strtok(xbuf, crlf); t; t = strtok(NULL, crlf)) {
            if (strncasecmp(t, "User-Agent:", 11) == 0) {
                ybuf = (char *) get_free_4k_page();
@@ -434,14 +610,12 @@ static void httpSendRequest(fd, data)
     }
     /* Add Forwarded: header */
     ybuf = get_free_4k_page();
-    if (data->entry->mem_obj)
-       cfd = data->entry->mem_obj->fd_of_first_client;
+    if (httpState->entry->mem_obj)
+       cfd = httpState->entry->mem_obj->fd_of_first_client;
     if (cfd < 0) {
-       sprintf(ybuf, "Forwarded: by http://%s:%d/\r\n",
-           getMyHostname(), getAsciiPortNum());
+       sprintf(ybuf, "%s\r\n", ForwardedBy);
     } else {
-       sprintf(ybuf, "Forwarded: by http://%s:%d/ for %s\r\n",
-           getMyHostname(), getAsciiPortNum(), fd_table[cfd].ipaddr);
+       sprintf(ybuf, "%s for %s\r\n", ForwardedBy, fd_table[cfd].ipaddr);
     }
     strcat(buf, ybuf);
     len += strlen(ybuf);
@@ -456,22 +630,22 @@ static void httpSendRequest(fd, data)
        xfree(post_buf);
     }
     debug(11, 6, "httpSendRequest: FD %d: buf '%s'\n", fd, buf);
-    data->icp_rwd_ptr = icpWrite(fd,
+    comm_write(fd,
        buf,
        len,
        30,
        httpSendComplete,
-       (void *) data);
+       httpState);
 }
 
-static void httpConnInProgress(fd, data)
+static void httpConnInProgress(fd, httpState)
      int fd;
-     HttpData *data;
+     HttpStateData *httpState;
 {
-    StoreEntry *entry = data->entry;
-    request_t *req = data->request;
+    StoreEntry *entry = httpState->entry;
+    request_t *req = httpState->request;
 
-    debug(11, 5, "httpConnInProgress: FD %d data=%p\n", fd, data);
+    debug(11, 5, "httpConnInProgress: FD %d httpState=%p\n", fd, httpState);
 
     if (comm_connect(fd, req->host, req->port) != COMM_OK) {
        debug(11, 5, "httpConnInProgress: FD %d: %s\n", fd, xstrerror());
@@ -482,7 +656,7 @@ static void httpConnInProgress(fd, data)
            comm_set_select_handler(fd,
                COMM_SELECT_WRITE,
                (PF) httpConnInProgress,
-               (void *) data);
+               (void *) httpState);
            return;
        default:
            squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
@@ -492,7 +666,7 @@ static void httpConnInProgress(fd, data)
     }
     /* Call the real write handler, now that we're fully connected */
     comm_set_select_handler(fd, COMM_SELECT_WRITE,
-       (PF) httpSendRequest, (void *) data);
+       (PF) httpSendRequest, (void *) httpState);
 }
 
 int proxyhttpStart(e, url, entry)
@@ -502,7 +676,7 @@ int proxyhttpStart(e, url, entry)
 {
     int sock;
     int status;
-    HttpData *data = NULL;
+    HttpStateData *httpState = NULL;
     request_t *request = NULL;
 
     debug(11, 3, "proxyhttpStart: \"%s %s\"\n",
@@ -510,37 +684,36 @@ int proxyhttpStart(e, url, entry)
     debug(11, 10, "proxyhttpStart: HTTP request header:\n%s\n",
        entry->mem_obj->mime_hdr);
 
-    if (e->proxy_only)
+    if (e->options & NEIGHBOR_PROXY_ONLY)
        storeStartDeleteBehind(entry);
 
     /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
+    sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
     if (sock == COMM_ERROR) {
        debug(11, 4, "proxyhttpStart: Failed because we're out of sockets.\n");
        squid_error_entry(entry, ERR_NO_FDS, xstrerror());
        return COMM_ERROR;
     }
-    data = (HttpData *) xcalloc(1, sizeof(HttpData));
-    data->entry = entry;
-    data->req_hdr = entry->mem_obj->mime_hdr;
-    request = (request_t *) xcalloc(1, sizeof(request_t));
-    data->free_request = 1;
-    data->request = request;
+    httpState = xcalloc(1, sizeof(HttpStateData));
+    storeLockObject(httpState->entry = entry, NULL, NULL);
+    httpState->req_hdr = entry->mem_obj->mime_hdr;
+    request = get_free_request_t();
+    httpState->request = requestLink(request);
+    httpState->neighbor = e;
     /* register the handler to free HTTP state data when the FD closes */
-    comm_set_select_handler(sock,
-       COMM_SELECT_CLOSE,
+    comm_add_close_handler(sock,
        (PF) httpStateFree,
-       (void *) data);
+       (void *) httpState);
 
     request->method = entry->method;
     strncpy(request->host, e->host, SQUIDHOSTNAMELEN);
-    request->port = e->ascii_port;
+    request->port = e->http_port;
     strncpy(request->urlpath, url, MAX_URL);
 
     /* check if IP is already in cache. It must be. 
      * It should be done before this route is called. 
      * Otherwise, we cannot check return code for connect. */
-    if (!ipcache_gethostbyname(request->host)) {
+    if (!ipcache_gethostbyname(request->host, IP_BLOCKING_LOOKUP)) {
        debug(11, 4, "proxyhttpstart: Called without IP entry in ipcache. OR lookup failed.\n");
        squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
        comm_close(sock);
@@ -557,18 +730,18 @@ int proxyhttpStart(e, url, entry)
        } else {
            debug(11, 5, "proxyhttpStart: FD %d: EINPROGRESS.\n", sock);
            comm_set_select_handler(sock, COMM_SELECT_LIFETIME,
-               (PF) httpLifetimeExpire, (void *) data);
+               (PF) httpLifetimeExpire, (void *) httpState);
            comm_set_select_handler(sock, COMM_SELECT_WRITE,
-               (PF) httpConnInProgress, (void *) data);
+               (PF) httpConnInProgress, (void *) httpState);
            return COMM_OK;
        }
     }
     /* Install connection complete handler. */
     fd_note(sock, entry->url);
     comm_set_select_handler(sock, COMM_SELECT_LIFETIME,
-       (PF) httpLifetimeExpire, (void *) data);
+       (PF) httpLifetimeExpire, (void *) httpState);
     comm_set_select_handler(sock, COMM_SELECT_WRITE,
-       (PF) httpSendRequest, (void *) data);
+       (PF) httpSendRequest, (void *) httpState);
     return COMM_OK;
 }
 
@@ -581,32 +754,31 @@ int httpStart(unusedfd, url, request, req_hdr, entry)
 {
     /* Create state structure. */
     int sock, status;
-    HttpData *data = NULL;
+    HttpStateData *httpState = NULL;
 
     debug(11, 3, "httpStart: \"%s %s\"\n",
        RequestMethodStr[request->method], url);
     debug(11, 10, "httpStart: req_hdr '%s'\n", req_hdr);
 
     /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
+    sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
     if (sock == COMM_ERROR) {
        debug(11, 4, "httpStart: Failed because we're out of sockets.\n");
        squid_error_entry(entry, ERR_NO_FDS, xstrerror());
        return COMM_ERROR;
     }
-    data = (HttpData *) xcalloc(1, sizeof(HttpData));
-    data->entry = entry;
-    data->req_hdr = req_hdr;
-    data->request = request;
-    comm_set_select_handler(sock,
-       COMM_SELECT_CLOSE,
+    httpState = xcalloc(1, sizeof(HttpStateData));
+    storeLockObject(httpState->entry = entry, NULL, NULL);
+    httpState->req_hdr = req_hdr;
+    httpState->request = requestLink(request);
+    comm_add_close_handler(sock,
        (PF) httpStateFree,
-       (void *) data);
+       (void *) httpState);
 
     /* check if IP is already in cache. It must be. 
      * It should be done before this route is called. 
      * Otherwise, we cannot check return code for connect. */
-    if (!ipcache_gethostbyname(request->host)) {
+    if (!ipcache_gethostbyname(request->host, 0)) {
        debug(11, 4, "httpstart: Called without IP entry in ipcache. OR lookup failed.\n");
        squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
        comm_close(sock);
@@ -621,17 +793,37 @@ int httpStart(unusedfd, url, request, req_hdr, entry)
        } else {
            debug(11, 5, "httpStart: FD %d: EINPROGRESS.\n", sock);
            comm_set_select_handler(sock, COMM_SELECT_LIFETIME,
-               (PF) httpLifetimeExpire, (void *) data);
+               (PF) httpLifetimeExpire, (void *) httpState);
            comm_set_select_handler(sock, COMM_SELECT_WRITE,
-               (PF) httpConnInProgress, (void *) data);
+               (PF) httpConnInProgress, (void *) httpState);
            return COMM_OK;
        }
     }
     /* Install connection complete handler. */
     fd_note(sock, entry->url);
     comm_set_select_handler(sock, COMM_SELECT_LIFETIME,
-       (PF) httpLifetimeExpire, (void *) data);
+       (PF) httpLifetimeExpire, (void *) httpState);
     comm_set_select_handler(sock, COMM_SELECT_WRITE,
-       (PF) httpSendRequest, (void *) data);
+       (PF) httpSendRequest, (void *) httpState);
     return COMM_OK;
 }
+
+void httpReplyHeaderStats(entry)
+     StoreEntry *entry;
+{
+    storeAppendPrintf(entry, open_bracket);
+    storeAppendPrintf(entry, "{HTTP Reply Headers}\n");
+    storeAppendPrintf(entry, "{Headers parsed: %d}\n",
+       ReplyHeaderStats.parsed);
+    storeAppendPrintf(entry, "{          Date: %d}\n",
+       ReplyHeaderStats.date);
+    storeAppendPrintf(entry, "{ Last-Modified: %d}\n",
+       ReplyHeaderStats.lm);
+    storeAppendPrintf(entry, "{       Expires: %d}\n",
+       ReplyHeaderStats.exp);
+    storeAppendPrintf(entry, "{  Content-Type: %d}\n",
+       ReplyHeaderStats.ctype);
+    storeAppendPrintf(entry, "{Content-Length: %d}\n",
+       ReplyHeaderStats.clen);
+    storeAppendPrintf(entry, close_bracket);
+}
index 5435dd01dc98d94d88aeb8e35186fdc4be8936dd..1b21a81c916a20e19876096940be6864e240adcc 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: ident.cc,v 1.1 1996/05/03 23:22:22 wessels Exp $ */
+/* $Id: ident.cc,v 1.2 1996/07/09 03:41:31 wessels Exp $ */
 
 /*
  * DEBUG: Section 30           ident/RFC931
@@ -8,7 +8,7 @@
 
 #define IDENT_PORT 113
 
-static void identRequestComplete _PARAMS((int, char *, int, int, icpStateData *));
+static void identRequestComplete _PARAMS((int, char *, int, int, void *));
 static void identReadReply _PARAMS((int, icpStateData *));
 static void identClose _PARAMS((int, icpStateData *));
 
@@ -35,14 +35,12 @@ void identStart(sock, icpState)
     debug(30, 1, "identStart: peer is %s:%d\n", host, port);
 
     if (sock < 0) {
-       if ((sock = comm_open(COMM_NONBLOCKING, 0, 0, "ident")) == COMM_ERROR) {
-           debug(30, 4, "identStart: Failed because we're out of sockets.\n");
+       sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, "ident");
+       if (sock == COMM_ERROR)
            return;
-       }
     }
     icpState->ident_fd = sock;
-    comm_set_select_handler(sock,
-       COMM_SELECT_CLOSE,
+    comm_add_close_handler(sock,
        (PF) identClose,
        (void *) icpState);
     if ((status = comm_connect(sock, host, IDENT_PORT)) < 0) {
@@ -61,9 +59,7 @@ void identStart(sock, icpState)
     sprintf(reqbuf, "%d, %d\r\n",
        ntohs(icpState->peer.sin_port),
        ntohs(icpState->me.sin_port));
-    /* XXX icpWrite() returns a data structure which we need to free if there is
-     * a timeout */
-    (void) icpWrite(sock,
+    (void) comm_write(sock,
        reqbuf,
        strlen(reqbuf),
        5,                      /* timeout */
@@ -75,12 +71,12 @@ void identStart(sock, icpState)
        (void *) icpState);
 }
 
-static void identRequestComplete(fd, buf, size, errflag, state)
+static void identRequestComplete(fd, buf, size, errflag, data)
      int fd;
      char *buf;
      int size;
      int errflag;
-     icpStateData *state;
+     void *data;
 {
     debug(30, 1, "identRequestComplete: FD %d: wrote %d bytes\n", fd, size);
 }
index 70a47206a8e981b9b0553e85802d2d9b5aeb3653..6b848bde4cc27d4e7c1c5bc0a942d6a6ddfcaa57 100644 (file)
-/* $Id: ipcache.cc,v 1.28 1996/05/03 22:56:29 wessels Exp $ */
+/*
+ * $Id: ipcache.cc,v 1.29 1996/07/09 03:41:31 wessels Exp $
+ *
+ * DEBUG: section 14    IP Cache
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 14          ipcache: IP Cache
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
-
 #define MAX_LINELEN (4096)
-char ipcache_status_char _PARAMS((ipcache_entry *));
-int ipcache_hash_entry_count();
 
 #define MAX_IP          1024   /* Maximum cached IP */
-#define IP_LOW_WATER       70
-#define IP_HIGH_WATER      90
+#define IP_LOW_WATER       90
+#define IP_HIGH_WATER      95
 #define MAX_HOST_NAME    256
-#define IP_INBUF        4096
+#define IP_INBUF_SZ     4096
 
-long ipcache_low = 180;
-long ipcache_high = 200;
-
-typedef struct _ip_pending {
+struct _ip_pending {
     int fd;
     IPH handler;
-    void *data;
+    void *handlerData;
     struct _ip_pending *next;
-} IpPending;
-
+};
 
-typedef struct _ipcache_list {
-    ipcache_entry *entry;
-    struct _ipcache_list *next;
-} ipcache_list;
+#define DNS_FLAG_ALIVE         0x01
+#define DNS_FLAG_BUSY          0x02
+#define DNS_FLAG_CLOSING       0x04
 
-
-typedef struct _dnsserver_entry {
+typedef struct _dnsserver {
     int id;
-    int alive;
+    int flags;
     int inpipe;
     int outpipe;
-    int pending_count;         /* counter of outstanding request */
-    long lastcall;
-    long answer;
+    time_t lastcall;
+    time_t answer;
     unsigned int offset;
     unsigned int size;
     char *ip_inbuf;
-    /* global ipcache_entry list for pending entry */
-    ipcache_list *global_pending;
-    ipcache_list *global_pending_tail;
-} dnsserver_entry;
+    struct timeval dispatch_time;
+    ipcache_entry *ip_entry;
+} dnsserver_t;
+
+static struct {
+    int requests;
+    int hits;
+    int misses;
+    int pending_hits;
+    int negative_hits;
+    int dnsserver_requests;
+    int dnsserver_replies;
+    int errors;
+    int avg_svc_time;
+    int ghbn_calls;            /* # calls to blocking gethostbyname() */
+    int dnsserver_hist[DefaultDnsChildrenMax];
+} IpcacheStats;
 
 typedef struct _line_entry {
     char *line;
     struct _line_entry *next;
 } line_entry;
 
-static dnsserver_entry **dns_child_table = NULL;
-static int last_dns_dispatched = 2;
+struct dnsQueueData {
+    struct dnsQueueData *next;
+    ipcache_entry *ip_entry;
+};
+
+static int ipcache_testname _PARAMS((void));
+static dnsserver_t *dnsGetFirstAvailable _PARAMS((void));
+static int ipcache_compareLastRef _PARAMS((ipcache_entry **, ipcache_entry **));
+static int ipcache_create_dnsserver _PARAMS((char *command));
+static int ipcache_dnsHandleRead _PARAMS((int, dnsserver_t *));
+static int ipcache_parsebuffer _PARAMS((char *buf, unsigned int offset, dnsserver_t *));
+static int ipcache_purgelru _PARAMS((void));
+static void ipcache_release _PARAMS((ipcache_entry *));
+static ipcache_entry *ipcache_GetFirst _PARAMS((void));
+static ipcache_entry *ipcache_GetNext _PARAMS((void));
+static ipcache_entry *ipcache_create _PARAMS((void));
+static void free_lines _PARAMS((line_entry *));
+static void ipcache_add_to_hash _PARAMS((ipcache_entry *));
+static void ipcache_call_pending _PARAMS((ipcache_entry *));
+static void ipcache_call_pending_badname _PARAMS((int fd, IPH handler, void *));
+static void ipcache_add _PARAMS((char *, ipcache_entry *, struct hostent *, int));
+static ipcache_entry *dnsDequeue _PARAMS(());
+static void dnsEnqueue _PARAMS((ipcache_entry *));
+static void dnsDispatch _PARAMS((dnsserver_t *, ipcache_entry *));
+static int ipcacheHasPending _PARAMS((ipcache_entry *));
+static ipcache_entry *ipcache_get _PARAMS((char *));
+static int dummy_handler _PARAMS((int, struct hostent * hp, void *));
+static int ipcacheExpiredEntry _PARAMS((ipcache_entry *));
+static void ipcacheAddPending _PARAMS((ipcache_entry *, int fd, IPH, void *));
+
+static dnsserver_t **dns_child_table = NULL;
 static struct hostent *static_result = NULL;
-static int dns_child_alive = 0;
-
+static int NDnsServersAlloc = 0;
+static struct dnsQueueData *dnsQueueHead = NULL;
+static struct dnsQueueData **dnsQueueTailP = &dnsQueueHead;
+static HashID ip_table = 0;
 char *dns_error_message = NULL;        /* possible error message */
-HashID ip_table = 0;
-
-extern int do_dns_test;
-extern int getMaxFD();
-extern int getDnsChildren();
-extern void fatal_dump _PARAMS((char *));
-extern int file_update_open _PARAMS((int, char *));
+long ipcache_low = 180;
+long ipcache_high = 200;
 
-void update_dns_child_alive()
+static char ipcache_status_char[] =
 {
-    int i;
-    int N = getDnsChildren();
-
-    dns_child_alive = 0;
-    for (i = 0; i < N; ++i) {
-       if (dns_child_table[i]->alive) {
-           dns_child_alive = 1;
-           break;
-       }
-    }
-}
+    'C',
+    'N',
+    'P',
+    'D'
+};
 
-int ipcache_testname()
+static int ipcache_testname()
 {
     wordlist *w = NULL;
     debug(14, 1, "Performing DNS Tests...\n");
     if ((w = getDnsTestnameList()) == NULL)
        return 1;
     for (; w; w = w->next) {
+       IpcacheStats.ghbn_calls++;
        if (gethostbyname(w->key) != NULL)
            return 1;
     }
     return 0;
 }
 
-
-/*
- * open a UNIX domain socket for rendevouing with dnsservers
- */
-int ipcache_create_dnsserver(command)
+/* TCP SOCKET VERSION */
+static int ipcache_create_dnsserver(command)
      char *command;
 {
     int pid;
-    struct sockaddr_un addr;
-    static int n_dnsserver = 0;
-    char *socketname = NULL;
-    int cfd;                   /* socket for child (dnsserver) */
-    int sfd;                   /* socket for server (squid) */
+    u_short port;
+    struct sockaddr_in S;
+    int cfd;
+    int sfd;
+    int len;
     int fd;
 
-    if ((cfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-       debug(14, 0, "ipcache_create_dnsserver: socket: %s\n", xstrerror());
+    cfd = comm_open(COMM_NOCLOEXEC,
+       local_addr,
+       0,
+       "socket to dnsserver");
+    if (cfd == COMM_ERROR) {
+       debug(14, 0, "ipcache_create_dnsserver: Failed to create dnsserver\n");
        return -1;
     }
-    fdstat_open(cfd, Socket);
-    fd_note(cfd, "socket to dnsserver");
-    memset(&addr, '\0', sizeof(addr));
-    addr.sun_family = AF_UNIX;
-    socketname = tempnam(NULL, "dns");
-    /* sprintf(socketname, "dns/dns%d.%d", (int) getpid(), n_dnsserver++); */
-    strcpy(addr.sun_path, socketname);
-    debug(14, 4, "ipcache_create_dnsserver: path is %s\n", addr.sun_path);
-
-    if (bind(cfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-       close(cfd);
-       debug(14, 0, "ipcache_create_dnsserver: bind: %s\n", xstrerror());
-       xfree(socketname);
+    len = sizeof(S);
+    memset(&S, '\0', len);
+    if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) {
+       debug(14, 0, "ipcache_create_dnsserver: getsockname: %s\n", xstrerror());
+       comm_close(cfd);
        return -1;
     }
+    port = ntohs(S.sin_port);
     debug(14, 4, "ipcache_create_dnsserver: bind to local host.\n");
     listen(cfd, 1);
-
     if ((pid = fork()) < 0) {
        debug(14, 0, "ipcache_create_dnsserver: fork: %s\n", xstrerror());
-       close(cfd);
-       xfree(socketname);
+       comm_close(cfd);
        return -1;
     }
     if (pid > 0) {             /* parent */
-       close(cfd);             /* close shared socket with child */
-
+       comm_close(cfd);        /* close shared socket with child */
        /* open new socket for parent process */
-       if ((sfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-           debug(14, 0, "ipcache_create_dnsserver: socket: %s\n", xstrerror());
-           xfree(socketname);
+       sfd = comm_open(0, local_addr, 0, NULL);        /* blocking! */
+       if (sfd == COMM_ERROR)
            return -1;
-       }
-       fcntl(sfd, F_SETFD, 1); /* set close-on-exec */
-       memset(&addr, '\0', sizeof(addr));
-       addr.sun_family = AF_UNIX;
-       strcpy(addr.sun_path, socketname);
-       xfree(socketname);
-       if (connect(sfd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-           close(sfd);
-           debug(14, 0, "ipcache_create_dnsserver: connect: %s\n", xstrerror());
+       if (comm_connect(sfd, localhost, port) == COMM_ERROR) {
+           comm_close(sfd);
            return -1;
        }
-       debug(14, 4, "ipcache_create_dnsserver: FD %d connected to %s #%d.\n",
-           sfd, command, n_dnsserver);
+       comm_set_fd_lifetime(sfd, -1);
        return sfd;
     }
     /* child */
 
-    /* give up extra priviliges */
-    no_suid();
-
-    /* setup filedescriptors */
+    no_suid();                 /* give up extra priviliges */
     dup2(cfd, 3);
-    for (fd = getMaxFD(); fd > 3; fd--) {
-       (void) close(fd);
-    }
-
-    execlp(command, "(dnsserver)", "-p", socketname, NULL);
+    for (fd = FD_SETSIZE; fd > 3; fd--)
+       close(fd);
+    execlp(command, "(dnsserver)", "-t", NULL);
     debug(14, 0, "ipcache_create_dnsserver: %s: %s\n", command, xstrerror());
     _exit(1);
-    return (0);                        /* NOTREACHED */
+    return 0;
 }
 
-
 /* removes the given ipcache entry */
-int ipcache_release(e)
-     ipcache_entry *e;
+static void ipcache_release(i)
+     ipcache_entry *i;
 {
     ipcache_entry *result = 0;
-    int i;
+    hash_link *table_entry = NULL;
+    int k;
 
-    debug(14, 5, "ipcache_release: ipcache_count before: %d \n", meta_data.ipcache_count);
-
-    if (e != NULL && ip_table) {       /* sometimes called with NULL e */
-       hash_link *table_entry = hash_lookup(ip_table, e->name);
-       if (table_entry) {
-           result = (ipcache_entry *) table_entry;
-           debug(14, 5, "HASH table count before delete: %d\n", ipcache_hash_entry_count());
-           if (hash_remove_link(ip_table, table_entry)) {
-               debug(14, 3, "ipcache_release: Cannot delete '%s' from hash table %d\n", e->name, ip_table);
-           }
-           debug(14, 5, "HASH table count after delete: %d\n", ipcache_hash_entry_count());
-           if (result) {
-               if (result->status == PENDING) {
-                   debug(14, 1, "ipcache_release: Try to release entry with PENDING status. ignored.\n");
-                   debug(14, 5, "ipcache_release: ipcache_count: %d \n", meta_data.ipcache_count);
-                   return -1;
-               }
-               if (result->status == CACHED) {
-                   if (result->addr_count)
-                       for (i = 0; i < (int) result->addr_count; i++)
-                           safe_free(result->entry.h_addr_list[i]);
-                   if (result->entry.h_addr_list)
-                       safe_free(result->entry.h_addr_list);
-                   if (result->alias_count)
-                       for (i = 0; i < (int) result->alias_count; i++)
-                           safe_free(result->entry.h_aliases[i]);
-                   if (result->entry.h_aliases)
-                       safe_free(result->entry.h_aliases);
-                   safe_free(result->entry.h_name);
-                   debug(14, 5, "ipcache_release: Released IP cached record for '%s'.\n", e->name);
-               }
-               /* XXX: we're having mem mgmt problems; zero, then free */
-               safe_free(result->name);
-               memset(result, '\0', sizeof(ipcache_entry));
-               safe_free(result);
-           }
-           --meta_data.ipcache_count;
-           debug(14, 5, "ipcache_release: ipcache_count when return: %d \n", meta_data.ipcache_count);
-           return meta_data.ipcache_count;
-       }
+    if ((table_entry = hash_lookup(ip_table, i->name)) == NULL) {
+       debug(14, 0, "ipcache_release: Could not find key '%s'\n", i->name);
+       return;
+    }
+    result = (ipcache_entry *) table_entry;
+    if (i != result)
+       fatal_dump("ipcache_release: expected i == result!");
+    if (i->status == IP_PENDING) {
+       debug(14, 1, "ipcache_release: Someone called on a PENDING entry\n");
+       return;
+    }
+    if (i->status == IP_DISPATCHED) {
+       debug(14, 1, "ipcache_release: Someone called on a DISPATCHED entry\n");
+       return;
     }
-    debug(14, 3, "ipcache_release: can't delete entry\n");
-    return -1;                 /* can't delete entry */
+    if (hash_remove_link(ip_table, table_entry)) {
+       debug(14, 0, "ipcache_release: hash_remove_link() failed for '%s'\n",
+           result->name);
+       return;
+    }
+    if (result->status == IP_CACHED) {
+       for (k = 0; k < (int) result->addr_count; k++)
+           safe_free(result->entry.h_addr_list[k]);
+       safe_free(result->entry.h_addr_list);
+       for (k = 0; k < (int) result->alias_count; k++)
+           safe_free(result->entry.h_aliases[k]);
+       if (result->entry.h_aliases)
+           safe_free(result->entry.h_aliases);
+       safe_free(result->entry.h_name);
+       debug(14, 5, "ipcache_release: Released IP cached record for '%s'.\n",
+           result->name);
+    }
+    safe_free(result->name);
+    safe_free(result->error_message);
+    memset(result, '\0', sizeof(ipcache_entry));
+    safe_free(result);
+    --meta_data.ipcache_count;
+    return;
 }
 
 /* return match for given name */
-ipcache_entry *ipcache_get(name)
+static ipcache_entry *ipcache_get(name)
      char *name;
 {
     hash_link *e;
-    static ipcache_entry *result;
+    static ipcache_entry *i;
 
-    result = NULL;
+    i = NULL;
     if (ip_table) {
        if ((e = hash_lookup(ip_table, name)) != NULL)
-           result = (ipcache_entry *) e;
-    }
-    if (result == NULL)
-       return NULL;
-
-    if (((result->timestamp + result->ttl) < squid_curtime) &&
-       (result->status != PENDING)) {  /* expired? */
-       ipcache_release(result);
-       return NULL;
+           i = (ipcache_entry *) e;
     }
-    return result;
+    return i;
 }
 
-
 /* get the first ip entry in the storage */
-ipcache_entry *ipcache_GetFirst()
+static ipcache_entry *ipcache_GetFirst()
 {
-    static hash_link *entryPtr;
-
-    if ((!ip_table) || ((entryPtr = hash_first(ip_table)) == NULL))
-       return NULL;
-    return ((ipcache_entry *) entryPtr);
+    return (ipcache_entry *) hash_first(ip_table);
 }
 
-
 /* get the next ip entry in the storage for a given search pointer */
-ipcache_entry *ipcache_GetNext()
+static ipcache_entry *ipcache_GetNext()
 {
-    static hash_link *entryPtr;
-
-    if ((!ip_table) || ((entryPtr = hash_next(ip_table)) == NULL))
-       return NULL;
-    return ((ipcache_entry *) entryPtr);
+    return (ipcache_entry *) hash_next(ip_table);
 }
 
-int ipcache_compareLastRef(e1, e2)
+static int ipcache_compareLastRef(e1, e2)
      ipcache_entry **e1, **e2;
 {
     if (!e1 || !e2)
        fatal_dump(NULL);
-
     if ((*e1)->lastref > (*e2)->lastref)
        return (1);
-
     if ((*e1)->lastref < (*e2)->lastref)
        return (-1);
-
     return (0);
 }
 
-
+static int ipcacheExpiredEntry(i)
+     ipcache_entry *i;
+{
+    if (i->lock)
+       return 0;
+    if (i->status == IP_PENDING)
+       return 0;
+    if (i->status == IP_DISPATCHED)
+       return 0;
+    if (i->ttl + i->lastref > squid_curtime)
+       return 0;
+    return 1;
+}
 
 /* finds the LRU and deletes */
-int ipcache_purgelru()
+static int ipcache_purgelru()
 {
-    ipcache_entry *e;
+    ipcache_entry *i = NULL;
     int local_ip_count = 0;
     int local_ip_notpending_count = 0;
     int removed = 0;
-    int i;
-    ipcache_entry **LRU_list;
+    int k;
+    ipcache_entry **LRU_list = NULL;
     int LRU_list_count = 0;
     int LRU_cur_size = meta_data.ipcache_count;
 
-    LRU_list = (ipcache_entry **) xcalloc(LRU_cur_size, sizeof(ipcache_entry *));
+    LRU_list = xcalloc(LRU_cur_size, sizeof(ipcache_entry *));
 
-    e = NULL;
-
-    for (e = ipcache_GetFirst(); e; e = ipcache_GetNext()) {
+    for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) {
+       if (ipcacheExpiredEntry(i)) {
+           ipcache_release(i);
+           removed++;
+           continue;
+       }
        local_ip_count++;
 
        if (LRU_list_count >= LRU_cur_size) {
@@ -318,63 +407,55 @@ int ipcache_purgelru()
            LRU_cur_size += 16;
            debug(14, 3, "ipcache_purgelru: Have to grow LRU_list to %d. This shouldn't happen.\n",
                LRU_cur_size);
-           LRU_list = (ipcache_entry **) xrealloc((char *) LRU_list,
+           LRU_list = xrealloc((char *) LRU_list,
                LRU_cur_size * sizeof(ipcache_entry *));
        }
-       if ((e->status != PENDING) && (e->pending_head == NULL)) {
-           local_ip_notpending_count++;
-           LRU_list[LRU_list_count++] = e;
-       }
+       if (i->status == IP_PENDING)
+           continue;
+       if (i->status == IP_DISPATCHED)
+           continue;
+       if (i->lock)
+           continue;
+       local_ip_notpending_count++;
+       LRU_list[LRU_list_count++] = i;
     }
 
     debug(14, 3, "ipcache_purgelru: ipcache_count: %5d\n", meta_data.ipcache_count);
     debug(14, 3, "                  actual count : %5d\n", local_ip_count);
-    debug(14, 3, "                  high W mark  : %5d\n", ipcache_high);
-    debug(14, 3, "                  low  W mark  : %5d\n", ipcache_low);
-    debug(14, 3, "                  not pending  : %5d\n", local_ip_notpending_count);
-    debug(14, 3, "              LRU candidated   : %5d\n", LRU_list_count);
+    debug(14, 3, "                   high W mark : %5d\n", ipcache_high);
+    debug(14, 3, "                   low  W mark : %5d\n", ipcache_low);
+    debug(14, 3, "                   not pending : %5d\n", local_ip_notpending_count);
+    debug(14, 3, "                LRU candidates : %5d\n", LRU_list_count);
 
     /* sort LRU candidate list */
-    qsort((char *) LRU_list, LRU_list_count, sizeof(e), (int (*)(const void *, const void *)) ipcache_compareLastRef);
-
-    for (i = 0; LRU_list[i] && (meta_data.ipcache_count > ipcache_low)
-       && i < LRU_list_count;
-       ++i) {
-       ipcache_release(LRU_list[i]);
+    qsort((char *) LRU_list,
+       LRU_list_count,
+       sizeof(i),
+       (int (*)(const void *, const void *)) ipcache_compareLastRef);
+    for (k = 0; LRU_list[k] && (meta_data.ipcache_count > ipcache_low)
+       && k < LRU_list_count;
+       ++k) {
+       ipcache_release(LRU_list[k]);
        removed++;
     }
 
-    debug(14, 3, "                   removed      : %5d\n", removed);
+    debug(14, 3, "                       removed : %5d\n", removed);
     safe_free(LRU_list);
     return (removed > 0) ? 0 : -1;
 }
 
 
 /* create blank ipcache_entry */
-ipcache_entry *ipcache_create()
+static ipcache_entry *ipcache_create()
 {
-    static ipcache_entry *ipe;
     static ipcache_entry *new;
-    debug(14, 5, "ipcache_create: when enter. ipcache_count == %d\n", meta_data.ipcache_count);
 
     if (meta_data.ipcache_count > ipcache_high) {
-       if (ipcache_purgelru() < 0) {
-           debug(14, 1, "ipcache_create: Cannot release needed IP entry via LRU: %d > %d, removing first entry...\n", meta_data.ipcache_count, MAX_IP);
-           ipe = ipcache_GetFirst();
-           if (!ipe) {
-               debug(14, 1, "ipcache_create: First entry is a null pointer ???\n");
-               /* have to let it grow beyond limit here */
-           } else if (ipe && ipe->status != PENDING) {
-               ipcache_release(ipe);
-           } else {
-               debug(14, 1, "ipcache_create: First entry is also PENDING entry.\n");
-               /* have to let it grow beyond limit here */
-           }
-       }
+       if (ipcache_purgelru() < 0)
+           debug(14, 0, "HELP!! IP Cache is overflowing!\n");
     }
     meta_data.ipcache_count++;
-    debug(14, 5, "ipcache_create: before return. ipcache_count == %d\n", meta_data.ipcache_count);
-    new = (ipcache_entry *) xcalloc(1, sizeof(ipcache_entry));
+    new = xcalloc(1, sizeof(ipcache_entry));
     /* set default to 4, in case parser fail to get token $h_length from
      * dnsserver. */
     new->entry.h_length = 4;
@@ -382,202 +463,116 @@ ipcache_entry *ipcache_create()
 
 }
 
-void ipcache_add_to_hash(e)
-     ipcache_entry *e;
+static void ipcache_add_to_hash(i)
+     ipcache_entry *i;
 {
-    if (hash_join(ip_table, (hash_link *) e)) {
+    if (hash_join(ip_table, (hash_link *) i)) {
        debug(14, 1, "ipcache_add_to_hash: Cannot add %s (%p) to hash table %d.\n",
-           e->name, e, ip_table);
+           i->name, i, ip_table);
     }
-    debug(14, 5, "ipcache_add_to_hash: name <%s>\n", e->name);
-    debug(14, 5, "                     ipcache_count: %d\n", meta_data.ipcache_count);
+    debug(14, 5, "ipcache_add_to_hash: name <%s>\n", i->name);
 }
 
 
-void ipcache_add(name, e, data, cached)
+static void ipcache_add(name, i, hp, cached)
      char *name;
-     ipcache_entry *e;
-     struct hostent *data;
+     ipcache_entry *i;
+     struct hostent *hp;
      int cached;
 {
-    int addr_count, alias_count, i;
+    int addr_count;
+    int alias_count;
+    int k;
 
+    if (ipcache_get(name))
+       fatal_dump("ipcache_add: somebody adding a duplicate!");
     debug(14, 10, "ipcache_add: Adding name '%s' (%s).\n", name,
        cached ? "cached" : "not cached");
-
-    e->name = xstrdup(name);
+    i->name = xstrdup(name);
     if (cached) {
-
        /* count for IPs */
        addr_count = 0;
-       while ((addr_count < 255) && data->h_addr_list[addr_count])
+       while ((addr_count < 255) && hp->h_addr_list[addr_count])
            ++addr_count;
 
-       e->addr_count = addr_count;
+       i->addr_count = addr_count;
 
        /* count for Alias */
        alias_count = 0;
-       if (data->h_aliases)
-           while ((alias_count < 255) && data->h_aliases[alias_count])
+       if (hp->h_aliases)
+           while ((alias_count < 255) && hp->h_aliases[alias_count])
                ++alias_count;
 
-       e->alias_count = alias_count;
+       i->alias_count = alias_count;
 
        /* copy ip addresses information */
-       e->entry.h_addr_list = (char **) xcalloc(addr_count + 1, sizeof(char *));
-       for (i = 0; i < addr_count; i++) {
-           e->entry.h_addr_list[i] = (char *) xcalloc(1, data->h_length);
-           memcpy(e->entry.h_addr_list[i], data->h_addr_list[i], data->h_length);
+       i->entry.h_addr_list = xcalloc(addr_count + 1, sizeof(char *));
+       for (k = 0; k < addr_count; k++) {
+           i->entry.h_addr_list[k] = xcalloc(1, hp->h_length);
+           xmemcpy(i->entry.h_addr_list[k], hp->h_addr_list[k], hp->h_length);
        }
 
        if (alias_count) {
            /* copy aliases information */
-           e->entry.h_aliases = (char **) xcalloc(alias_count + 1, sizeof(char *));
-           for (i = 0; i < alias_count; i++) {
-               e->entry.h_aliases[i] = (char *) xcalloc(1, strlen(data->h_aliases[i]) + 1);
-               strcpy(e->entry.h_aliases[i], data->h_aliases[i]);
+           i->entry.h_aliases = xcalloc(alias_count + 1, sizeof(char *));
+           for (k = 0; k < alias_count; k++) {
+               i->entry.h_aliases[k] = xcalloc(1, strlen(hp->h_aliases[k]) + 1);
+               strcpy(i->entry.h_aliases[k], hp->h_aliases[k]);
            }
        }
-       e->entry.h_length = data->h_length;
-       e->entry.h_name = xstrdup(data->h_name);
-       e->lastref = e->timestamp = squid_curtime;
-       e->status = CACHED;
-       e->ttl = DnsPositiveTtl;
+       i->entry.h_length = hp->h_length;
+       i->entry.h_name = xstrdup(hp->h_name);
+       i->lastref = i->timestamp = squid_curtime;
+       i->status = IP_CACHED;
+       i->ttl = DnsPositiveTtl;
     } else {
-       e->lastref = e->timestamp = squid_curtime;
-       e->status = NEGATIVE_CACHED;
-       e->ttl = getNegativeDNSTTL();
+       i->lastref = i->timestamp = squid_curtime;
+       i->status = IP_NEGATIVE_CACHED;
+       i->ttl = getNegativeDNSTTL();
     }
-
-    ipcache_add_to_hash(e);
+    ipcache_add_to_hash(i);
 }
 
 
-/* exactly the same to ipcache_add, 
- * except it does NOT
- * - create entry->name (assume it's there already.)
- * - add the entry to the hash (it's should be in hash table already.).
- * 
- * Intend to be used by ipcache_cleanup_pendinglist.
- */
-void ipcache_update_content(name, e, data, cached)
-     char *name;
-     ipcache_entry *e;
-     struct hostent *data;
-     int cached;
-{
-    int addr_count, alias_count, i;
-
-    debug(14, 10, "ipcache_update: Updating name '%s' (%s).\n", name,
-       cached ? "cached" : "not cached");
-
-    if (cached) {
-
-       /* count for IPs */
-       addr_count = 0;
-       while ((addr_count < 255) && data->h_addr_list[addr_count])
-           ++addr_count;
-
-       e->addr_count = addr_count;
-
-       /* count for Alias */
-       alias_count = 0;
-       while ((alias_count < 255) && data->h_aliases[alias_count])
-           ++alias_count;
-
-       e->alias_count = alias_count;
-
-       /* copy ip addresses information */
-       e->entry.h_addr_list = (char **) xcalloc(addr_count + 1, sizeof(char *));
-       for (i = 0; i < addr_count; i++) {
-           e->entry.h_addr_list[i] = (char *) xcalloc(1, data->h_length);
-           memcpy(e->entry.h_addr_list[i], data->h_addr_list[i], data->h_length);
-       }
-
-       /* copy aliases information */
-       e->entry.h_aliases = (char **) xcalloc(alias_count + 1, sizeof(char *));
-       for (i = 0; i < alias_count; i++) {
-           e->entry.h_aliases[i] = (char *) xcalloc(1, strlen(data->h_aliases[i]) + 1);
-           strcpy(e->entry.h_aliases[i], data->h_aliases[i]);
-       }
-
-       e->entry.h_length = data->h_length;
-       e->entry.h_name = xstrdup(data->h_name);
-       e->lastref = e->timestamp = squid_curtime;
-       e->status = CACHED;
-       e->ttl = DnsPositiveTtl;
-    } else {
-       e->lastref = e->timestamp = squid_curtime;
-       e->status = NEGATIVE_CACHED;
-       e->ttl = getNegativeDNSTTL();
-    }
-
-}
-
 
 
 /* walks down the pending list, calling handlers */
-void ipcache_call_pending(entry)
-     ipcache_entry *entry;
+static void ipcache_call_pending(i)
+     ipcache_entry *i;
 {
-    IpPending *p;
+    struct _ip_pending *p = NULL;
     int nhandler = 0;
 
-    entry->lastref = squid_curtime;
+    i->lastref = squid_curtime;
 
-    while (entry->pending_head != NULL) {
-       p = entry->pending_head;
-       entry->pending_head = entry->pending_head->next;
-       if (entry->pending_head == NULL)
-           entry->pending_tail = NULL;
-       if (p->handler != NULL) {
+    while (i->pending_head != NULL) {
+       p = i->pending_head;
+       i->pending_head = p->next;
+       if (p->handler) {
            nhandler++;
-           p->handler(p->fd, (entry->status == CACHED) ?
-               &(entry->entry) : NULL, p->data);
+           dns_error_message = i->error_message;
+           p->handler(p->fd,
+               (i->status == IP_CACHED) ? &(i->entry) : NULL,
+               p->handlerData);
        }
-       memset(p, '\0', sizeof(IpPending));
+       memset(p, '\0', sizeof(struct _ip_pending));
        safe_free(p);
     }
-    entry->pending_head = entry->pending_tail = NULL;  /* nuke list */
+    i->pending_head = NULL;    /* nuke list */
     debug(14, 10, "ipcache_call_pending: Called %d handlers.\n", nhandler);
 }
 
-void ipcache_call_pending_badname(fd, handler, data)
+static void ipcache_call_pending_badname(fd, handler, data)
      int fd;
      IPH handler;
      void *data;
 {
-    debug(14, 4, "ipcache_call_pending_badname: Bad Name: Calling handler with NULL result.\n");
+    debug(14, 0, "ipcache_call_pending_badname: Bad Name: Calling handler with NULL result.\n");
     handler(fd, NULL, data);
 }
 
-
-/* call when dnsserver is broken, have to switch to blocking mode. 
- * All pending lookup will be looked up by blocking call.
- */
-int ipcache_cleanup_pendinglist(data)
-     dnsserver_entry *data;
-{
-    ipcache_list *p;
-    struct hostent *s_result = NULL;
-
-    while (data->global_pending != NULL) {
-       s_result = gethostbyname(data->global_pending->entry->name);
-       ipcache_update_content(data->global_pending->entry->name,
-           data->global_pending->entry, s_result, s_result ? 1 : 0);
-       ipcache_call_pending(data->global_pending->entry);
-       p = data->global_pending;
-       data->global_pending = data->global_pending->next;
-       /* XXX: we're having mem mgmt problems; zero, then free */
-       memset(p, '\0', sizeof(ipcache_list));
-       safe_free(p);
-    }
-    data->global_pending = data->global_pending_tail = NULL;   /* nuke */
-    return 0;
-}
-
 /* free all lines in the list */
-void free_lines(line)
+static void free_lines(line)
      line_entry *line;
 {
     line_entry *tmp;
@@ -590,76 +585,12 @@ void free_lines(line)
     }
 }
 
-/* return entry in global pending list that has entry which key match to name */
-ipcache_list *globalpending_search(name, global_pending)
-     char *name;
-     ipcache_list *global_pending;
-{
-    static ipcache_list *p;
-
-    if (name == NULL)
-       return NULL;
-
-    for (p = global_pending; p != NULL; p = p->next) {
-       /* XXX: this is causing core dumps! p->entry is corrupt */
-       if (p->entry && p->entry->name &&
-           strcmp(p->entry->name, name) == 0) {
-           return p;
-       }
-    }
-    return NULL;
-
-}
-
-/* remove entry from global pending list */
-void globalpending_remove(p, data)
-     ipcache_list *p;
-     dnsserver_entry *data;
-{
-    ipcache_list *q, *r;
-
-    r = q = data->global_pending;
-    while (q && (p != q)) {
-       r = q;                  /* r is the node before the one to kill */
-       q = q->next;            /* q (and 'p') is the node to kill */
-    }
-
-    if (q == NULL) {           /* 'p' is not in the list? */
-       debug(14, 1, "globalpending_remove: Failure while deleting entry from global pending list.\n");
-       return;
-    }
-    /* nuke p from the list; do this carefully... */
-    if (p == data->global_pending) {   /* p is head */
-       if (p->next != NULL) {  /* nuke head */
-           data->global_pending = p->next;
-       } else {                /* nuke whole list */
-           data->global_pending = NULL;
-           data->global_pending_tail = NULL;
-       }
-    } else if (p == data->global_pending_tail) {       /* p is tail */
-       data->global_pending_tail = r;  /* tail is prev */
-       data->global_pending_tail->next = NULL;         /* last node */
-    } else {                   /* p in middle */
-       r->next = p->next;
-    }
-
-    /* we need to delete all references to p */
-    /* XXX: we're having mem mgmt probs; zero then free DRH */
-    memset(p, '\0', sizeof(ipcache_list));
-    /* XXX: what about freeing p->entry? DRH */
-    safe_free(p);
-
-    if (data->pending_count > 0)
-       data->pending_count--;
-
-}
-
 /* scan through buffer and do a conversion if possible 
  * return number of char used */
-int ipcache_parsebuffer(buf, offset, data)
+static int ipcache_parsebuffer(buf, offset, dnsData)
      char *buf;
      unsigned int offset;
-     dnsserver_entry *data;
+     dnsserver_t *dnsData;
 {
     char *pos = NULL;
     char *tpos = NULL;
@@ -669,9 +600,10 @@ int ipcache_parsebuffer(buf, offset, data)
     line_entry *line_head = NULL;
     line_entry *line_tail = NULL;
     line_entry *line_cur = NULL;
-    ipcache_list *plist = NULL;
+    int ipcount;
+    int aliascount;
+    ipcache_entry *i = NULL;
 
-    *dns_error_message = '\0';
 
     pos = buf;
     while (pos < (buf + offset)) {
@@ -685,7 +617,7 @@ int ipcache_parsebuffer(buf, offset, data)
 
        while (pos < endpos) {
            /* add the next line to the end of the list */
-           line_cur = (line_entry *) xcalloc(1, sizeof(line_entry));
+           line_cur = xcalloc(1, sizeof(line_entry));
 
            if ((tpos = memchr(pos, '\n', 4096)) == NULL) {
                debug(14, 2, "ipcache_parsebuffer: DNS response incomplete.\n");
@@ -714,7 +646,7 @@ int ipcache_parsebuffer(buf, offset, data)
         *  Start parsing...
         */
        if (strstr(line_head->line, "$alive")) {
-           data->answer = squid_curtime;
+           dnsData->answer = squid_curtime;
            free_lines(line_head);
            debug(14, 10, "ipcache_parsebuffer: $alive succeeded.\n");
        } else if (strstr(line_head->line, "$fail")) {
@@ -723,161 +655,141 @@ int ipcache_parsebuffer(buf, offset, data)
             *      $fail host\n$message msg\n$end\n
             */
            token = strtok(line_head->line, w_space);   /* skip first token */
-           token = strtok(NULL, w_space);
-
-           line_cur = line_head->next;
-           if (line_cur && !strncmp(line_cur->line, "$message", 8)) {
-               strcpy(dns_error_message, line_cur->line + 8);
-           }
-           if (token == NULL) {
-               debug(14, 1, "ipcache_parsebuffer: Invalid $fail for DNS table?\n");
+           if ((token = strtok(NULL, w_space)) == NULL) {
+               debug(14, 1, "ipcache_parsebuffer: Invalid $fail?\n");
            } else {
-               plist = globalpending_search(token, data->global_pending);
-               if (plist) {
-                   plist->entry->lastref = plist->entry->timestamp = squid_curtime;
-                   plist->entry->ttl = getNegativeDNSTTL();
-                   plist->entry->status = NEGATIVE_CACHED;
-                   ipcache_call_pending(plist->entry);
-                   globalpending_remove(plist, data);
-                   debug(14, 10, "ipcache_parsebuffer: $fail succeeded: %s.\n",
-                       dns_error_message[0] ? dns_error_message : "why?");
-               } else {
-                   debug(14, 1, "ipcache_parsebuffer: No entry in DNS table?\n");
-               }
+               line_cur = line_head->next;
+               i = dnsData->ip_entry;
+               i->lastref = i->timestamp = squid_curtime;
+               i->ttl = getNegativeDNSTTL();
+               i->status = IP_NEGATIVE_CACHED;
+               if (line_cur && !strncmp(line_cur->line, "$message", 8))
+                   i->error_message = xstrdup(line_cur->line + 8);
+               dns_error_message = i->error_message;
+               ipcache_call_pending(i);
            }
            free_lines(line_head);
        } else if (strstr(line_head->line, "$name")) {
            tmp_ptr = line_head->line;
            /* skip the first token */
            token = strtok(tmp_ptr, w_space);
-           tmp_ptr = NULL;
-           token = strtok(tmp_ptr, w_space);
-           if (!token) {
-               debug(14, 1, "ipcache_parsebuffer: Invalid OPCODE for DNS table?\n");
+           if ((token = strtok(NULL, w_space)) == NULL) {
+               debug(14, 0, "ipcache_parsebuffer: Invalid OPCODE?\n");
            } else {
-               plist = globalpending_search(token, data->global_pending);
-               if (plist) {
-                   int ipcount, aliascount;
-                   ipcache_entry *e = plist->entry;
-
-                   if (e->status != PENDING) {
-                       debug(14, 4, "ipcache_parsebuffer: DNS record already resolved.\n");
+               i = dnsData->ip_entry;
+               if (i->status != IP_DISPATCHED) {
+                   debug(14, 0, "ipcache_parsebuffer: DNS record already resolved.\n");
+               } else {
+                   i->lastref = i->timestamp = squid_curtime;
+                   i->ttl = DnsPositiveTtl;
+                   i->status = IP_CACHED;
+
+                   line_cur = line_head->next;
+
+                   /* get $h_name */
+                   if (line_cur == NULL ||
+                       !strstr(line_cur->line, "$h_name")) {
+                       debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $h_name.\n");
+                       /* abandon this record */
+                       break;
+                   }
+                   tmp_ptr = line_cur->line;
+                   /* skip the first token */
+                   token = strtok(tmp_ptr, w_space);
+                   tmp_ptr = NULL;
+                   token = strtok(tmp_ptr, w_space);
+                   i->entry.h_name = xstrdup(token);
+
+                   line_cur = line_cur->next;
+
+                   /* get $h_length */
+                   if (line_cur == NULL ||
+                       !strstr(line_cur->line, "$h_len")) {
+                       debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $h_len.\n");
+                       /* abandon this record */
+                       break;
+                   }
+                   tmp_ptr = line_cur->line;
+                   /* skip the first token */
+                   token = strtok(tmp_ptr, w_space);
+                   tmp_ptr = NULL;
+                   token = strtok(tmp_ptr, w_space);
+                   i->entry.h_length = atoi(token);
+
+                   line_cur = line_cur->next;
+
+                   /* get $ipcount */
+                   if (line_cur == NULL ||
+                       !strstr(line_cur->line, "$ipcount")) {
+                       debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $ipcount.\n");
+                       /* abandon this record */
+                       break;
+                   }
+                   tmp_ptr = line_cur->line;
+                   /* skip the first token */
+                   token = strtok(tmp_ptr, w_space);
+                   tmp_ptr = NULL;
+                   token = strtok(tmp_ptr, w_space);
+                   i->addr_count = ipcount = atoi(token);
+
+                   if (ipcount == 0) {
+                       i->entry.h_addr_list = NULL;
                    } else {
-                       e->lastref = e->timestamp = squid_curtime;
-                       e->ttl = DnsPositiveTtl;
-                       e->status = CACHED;
-
-                       line_cur = line_head->next;
-
-                       /* get $h_name */
-                       if (line_cur == NULL ||
-                           !strstr(line_cur->line, "$h_name")) {
-                           debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $h_name.\n");
-                           /* abandon this record */
-                           break;
-                       }
-                       tmp_ptr = line_cur->line;
-                       /* skip the first token */
-                       token = strtok(tmp_ptr, w_space);
-                       tmp_ptr = NULL;
-                       token = strtok(tmp_ptr, w_space);
-                       e->entry.h_name = xstrdup(token);
-
-                       line_cur = line_cur->next;
-
-                       /* get $h_length */
-                       if (line_cur == NULL ||
-                           !strstr(line_cur->line, "$h_len")) {
-                           debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $h_len.\n");
-                           /* abandon this record */
-                           break;
-                       }
-                       tmp_ptr = line_cur->line;
-                       /* skip the first token */
-                       token = strtok(tmp_ptr, w_space);
-                       tmp_ptr = NULL;
-                       token = strtok(tmp_ptr, w_space);
-                       e->entry.h_length = atoi(token);
+                       i->entry.h_addr_list = xcalloc(ipcount + 1, sizeof(char *));
+                   }
 
+                   /* get ip addresses */
+                   {
+                       int k = 0;
                        line_cur = line_cur->next;
-
-                       /* get $ipcount */
-                       if (line_cur == NULL ||
-                           !strstr(line_cur->line, "$ipcount")) {
-                           debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $ipcount.\n");
-                           /* abandon this record */
-                           break;
-                       }
-                       tmp_ptr = line_cur->line;
-                       /* skip the first token */
-                       token = strtok(tmp_ptr, w_space);
-                       tmp_ptr = NULL;
-                       token = strtok(tmp_ptr, w_space);
-                       e->addr_count = ipcount = atoi(token);
-
-                       if (ipcount == 0) {
-                           e->entry.h_addr_list = NULL;
-                       } else {
-                           e->entry.h_addr_list = (char **) xcalloc(ipcount, sizeof(char *));
-                       }
-
-                       /* get ip addresses */
-                       {
-                           int i = 0;
-                           line_cur = line_cur->next;
-                           while (i < ipcount) {
-                               if (line_cur == NULL) {
-                                   debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $ipcount data.\n");
-                                   break;
-                               }
-                               e->entry.h_addr_list[i] = (char *) xcalloc(1, e->entry.h_length);
-                               *((unsigned long *) (void *) e->entry.h_addr_list[i]) = inet_addr(line_cur->line);
-                               line_cur = line_cur->next;
-                               i++;
+                       while (k < ipcount) {
+                           if (line_cur == NULL) {
+                               debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $ipcount data.\n");
+                               break;
                            }
+                           i->entry.h_addr_list[k] = xcalloc(1, i->entry.h_length);
+                           *((u_num32 *) (void *) i->entry.h_addr_list[k]) = inet_addr(line_cur->line);
+                           line_cur = line_cur->next;
+                           k++;
                        }
+                   }
 
-                       /* get $aliascount */
-                       if (line_cur == NULL ||
-                           !strstr(line_cur->line, "$aliascount")) {
-                           debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $aliascount.\n");
-                           /* abandon this record */
-                           break;
-                       }
-                       tmp_ptr = line_cur->line;
-                       /* skip the first token */
-                       token = strtok(tmp_ptr, w_space);
-                       tmp_ptr = NULL;
-                       token = strtok(tmp_ptr, w_space);
-                       e->alias_count = aliascount = atoi(token);
-
-                       if (aliascount == 0) {
-                           e->entry.h_aliases = NULL;
-                       } else {
-                           e->entry.h_aliases = (char **) xcalloc(aliascount, sizeof(char *));
-                       }
+                   /* get $aliascount */
+                   if (line_cur == NULL ||
+                       !strstr(line_cur->line, "$aliascount")) {
+                       debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $aliascount.\n");
+                       /* abandon this record */
+                       break;
+                   }
+                   tmp_ptr = line_cur->line;
+                   /* skip the first token */
+                   token = strtok(tmp_ptr, w_space);
+                   tmp_ptr = NULL;
+                   token = strtok(tmp_ptr, w_space);
+                   i->alias_count = aliascount = atoi(token);
+
+                   if (aliascount == 0) {
+                       i->entry.h_aliases = NULL;
+                   } else {
+                       i->entry.h_aliases = xcalloc(aliascount, sizeof(char *));
+                   }
 
-                       /* get aliases */
-                       {
-                           int i = 0;
-                           line_cur = line_cur->next;
-                           while (i < aliascount) {
-                               if (line_cur == NULL) {
-                                   debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $aliascount data.\n");
-                                   break;
-                               }
-                               e->entry.h_aliases[i] = xstrdup(line_cur->line);
-                               line_cur = line_cur->next;
-                               i++;
+                   /* get aliases */
+                   {
+                       int k = 0;
+                       line_cur = line_cur->next;
+                       while (k < aliascount) {
+                           if (line_cur == NULL) {
+                               debug(14, 1, "ipcache_parsebuffer: DNS record in invalid format? No $aliascount data.\n");
+                               break;
                            }
+                           i->entry.h_aliases[k] = xstrdup(line_cur->line);
+                           line_cur = line_cur->next;
+                           k++;
                        }
-
-                       ipcache_call_pending(e);
-                       globalpending_remove(plist, data);
-                       debug(14, 10, "ipcache_parsebuffer: $name succeeded.\n");
                    }
-               } else {
-                   debug(14, 1, "ipcache_parsebuffer: No entries in DNS $name record?\n");
+                   ipcache_call_pending(i);
+                   debug(14, 10, "ipcache_parsebuffer: $name succeeded.\n");
                }
            }
            free_lines(line_head);
@@ -891,169 +803,225 @@ int ipcache_parsebuffer(buf, offset, data)
 }
 
 
-int ipcache_dnsHandleRead(fd, data)
+static int ipcache_dnsHandleRead(fd, dnsData)
      int fd;
-     dnsserver_entry *data;
+     dnsserver_t *dnsData;
 {
     int char_scanned;
-    int len = read(fd, data->ip_inbuf + data->offset, data->size - data->offset);
-
-    debug(14, 5, "ipcache_dnsHandleRead: Result from DNS ID %d.\n", data->id);
-
-    if (len == 0) {
-       debug(14, 1, "ipcache_dnsHandleRead: Connection from DNSSERVER is closed.\n");
-       debug(14, 1, "                       Disabling this server ID %d.\n", data->id);
-       data->alive = 0;
-       update_dns_child_alive();
-       ipcache_cleanup_pendinglist(data);
-       close(fd);
-       fdstat_close(fd);
+    int len;
+    int svc_time;
+    int n;
+    ipcache_entry *i = NULL;
+
+    len = read(fd,
+       dnsData->ip_inbuf + dnsData->offset,
+       dnsData->size - dnsData->offset);
+    debug(14, 5, "ipcache_dnsHandleRead: Result from DNS ID %d (%d bytes)\n",
+       dnsData->id, len);
+    if (len <= 0) {
+       debug(14, dnsData->flags & DNS_FLAG_CLOSING ? 5 : 1,
+           "FD %d: Connection from DNSSERVER #%d is closed, disabling\n",
+           fd, dnsData->id);
+       dnsData->flags = 0;
+       comm_set_select_handler(fd,
+           COMM_SELECT_WRITE,
+           NULL,
+           NULL);
+       comm_close(fd);
        return 0;
     }
-    data->offset += len;
-    data->ip_inbuf[data->offset] = '\0';
+    n = ++IpcacheStats.dnsserver_replies;
+    dnsData->offset += len;
+    dnsData->ip_inbuf[dnsData->offset] = '\0';
 
-    if (strstr(data->ip_inbuf, "$end\n")) {
+    if (strstr(dnsData->ip_inbuf, "$end\n")) {
        /* end of record found */
-       char_scanned = ipcache_parsebuffer(data->ip_inbuf, data->offset, data);
+       svc_time = tvSubMsec(dnsData->dispatch_time, current_time);
+       if (n > IPCACHE_AV_FACTOR)
+           n = IPCACHE_AV_FACTOR;
+       IpcacheStats.avg_svc_time
+           = (IpcacheStats.avg_svc_time * (n - 1) + svc_time) / n;
+       char_scanned = ipcache_parsebuffer(dnsData->ip_inbuf,
+           dnsData->offset,
+           dnsData);
        if (char_scanned > 0) {
            /* update buffer */
-           memcpy(data->ip_inbuf, data->ip_inbuf + char_scanned, data->offset - char_scanned);
-           data->offset -= char_scanned;
-           data->ip_inbuf[data->offset] = '\0';
+           xmemcpy(dnsData->ip_inbuf,
+               dnsData->ip_inbuf + char_scanned,
+               dnsData->offset - char_scanned);
+           dnsData->offset -= char_scanned;
+           dnsData->ip_inbuf[dnsData->offset] = '\0';
        }
     }
+    if (dnsData->offset == 0) {
+       dnsData->ip_entry = NULL;
+       dnsData->flags &= ~DNS_FLAG_BUSY;
+    }
     /* reschedule */
-    comm_set_select_handler(data->inpipe, COMM_SELECT_READ,
-       (PF) ipcache_dnsHandleRead, (void *) data);
+    comm_set_select_handler(dnsData->inpipe,
+       COMM_SELECT_READ,
+       (PF) ipcache_dnsHandleRead,
+       dnsData);
+    while ((dnsData = dnsGetFirstAvailable()) && (i = dnsDequeue()))
+       dnsDispatch(dnsData, i);
     return 0;
 }
 
-int ipcache_nbgethostbyname(name, fd, handler, data)
+static void ipcacheAddPending(i, fd, handler, handlerData)
+     ipcache_entry *i;
+     int fd;
+     IPH handler;
+     void *handlerData;
+{
+    struct _ip_pending *pending = xcalloc(1, sizeof(struct _ip_pending));
+    struct _ip_pending **I = NULL;
+
+    pending->fd = fd;
+    pending->handler = handler;
+    pending->handlerData = handlerData;
+
+    for (I = &(i->pending_head); *I; I = &((*I)->next));
+    *I = pending;
+}
+
+int ipcache_nbgethostbyname(name, fd, handler, handlerData)
      char *name;
      int fd;
      IPH handler;
-     void *data;
+     void *handlerData;
 {
-    ipcache_entry *e;
-    IpPending *pending;
-    dnsserver_entry *dns;
+    ipcache_entry *i = NULL;
+    dnsserver_t *dnsData = NULL;
+
+    if (!handler)
+       fatal_dump("ipcache_nbgethostbyname: NULL handler");
 
     debug(14, 4, "ipcache_nbgethostbyname: FD %d: Name '%s'.\n", fd, name);
+    IpcacheStats.requests++;
 
     if (name == NULL || name[0] == '\0') {
        debug(14, 4, "ipcache_nbgethostbyname: Invalid name!\n");
-       ipcache_call_pending_badname(fd, handler, data);
+       ipcache_call_pending_badname(fd, handler, handlerData);
        return 0;
     }
-    if ((e = ipcache_get(name)) != NULL && (e->status != PENDING)) {
-       /* hit here */
-       debug(14, 4, "ipcache_nbgethostbyname: Hit for name '%s'.\n", name);
-       pending = (IpPending *) xcalloc(1, sizeof(IpPending));
-       pending->fd = fd;
-       pending->handler = handler;
-       pending->data = data;
-       pending->next = NULL;
-       if (e->pending_head == NULL) {  /* empty list */
-           e->pending_head = e->pending_tail = pending;
-       } else {                /* add to tail of list */
-           e->pending_tail->next = pending;
-           e->pending_tail = e->pending_tail->next;
+    if ((i = ipcache_get(name))) {
+       if (ipcacheExpiredEntry(i)) {
+           ipcache_release(i);
+           i = NULL;
        }
-       ipcache_call_pending(e);
-       return 0;
     }
-    debug(14, 4, "ipcache_nbgethostbyname: Name '%s': MISS or PENDING.\n", name);
-
-    pending = (IpPending *) xcalloc(1, sizeof(IpPending));
-    pending->fd = fd;
-    pending->handler = handler;
-    pending->data = data;
-    pending->next = NULL;
-    if (e == NULL) {
-       /* No entry, create the new one */
-       debug(14, 5, "ipcache_nbgethostbyname: Creating new entry for '%s'...\n",
-           name);
-       e = ipcache_create();
-       e->name = xstrdup(name);
-       e->status = PENDING;
-       e->pending_tail = e->pending_head = pending;
-       ipcache_add_to_hash(e);
-    } else {
-       /* There is an entry. Add handler to list */
-       debug(14, 5, "ipcache_nbgethostbyname: Adding handler to pending list for '%s'.\n", name);
-       if (e->pending_head == NULL) {  /* empty list */
-           e->pending_head = e->pending_tail = pending;
-       } else {                /* add to tail of list */
-           e->pending_tail->next = pending;
-           e->pending_tail = e->pending_tail->next;
-       }
+    if (i == NULL) {
+       /* MISS: No entry, create the new one */
+       debug(14, 5, "ipcache_nbgethostbyname: MISS for '%s'\n", name);
+       IpcacheStats.misses++;
+       i = ipcache_create();
+       i->name = xstrdup(name);
+       i->status = IP_PENDING;
+       ipcacheAddPending(i, fd, handler, handlerData);
+       ipcache_add_to_hash(i);
+    } else if (i->status == IP_CACHED || i->status == IP_NEGATIVE_CACHED) {
+       /* HIT */
+       debug(14, 4, "ipcache_nbgethostbyname: HIT for '%s'\n", name);
+       if (i->status == IP_NEGATIVE_CACHED)
+           IpcacheStats.negative_hits++;
+       else
+           IpcacheStats.hits++;
+       ipcacheAddPending(i, fd, handler, handlerData);
+       ipcache_call_pending(i);
        return 0;
+    } else if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
+       debug(14, 4, "ipcache_nbgethostbyname: PENDING for '%s'\n", name);
+       IpcacheStats.pending_hits++;
+       ipcacheAddPending(i, fd, handler, handlerData);
+       return 0;
+    } else {
+       fatal_dump("ipcache_nbgethostbyname: BAD ipcache_entry status");
     }
 
-    if (dns_child_alive) {
-       int i, j, min_dns = 0, min_count = 255, alive = 0;
-
-       j = last_dns_dispatched;
-       /* select DNS server with the lowest number of pending */
-       for (i = 0; i < getDnsChildren(); ++i) {
-           j += 1;
-           j %= getDnsChildren();
-           if ((dns_child_table[j]->alive) &&
-               (dns_child_table[j]->pending_count < min_count)) {
-               min_dns = j;
-               min_count = dns_child_table[j]->pending_count;
-           }
-           alive = dns_child_table[j]->alive | alive;
-       }
+    /* for HIT, PENDING, DISPATCHED we've returned.  For MISS we continue */
 
-       if (alive == 0) {
-           dns_child_alive = 0;        /* all dead */
-           last_dns_dispatched = 0;    /* use entry 0 */
-       } else {
-           last_dns_dispatched = min_dns;
+    if ((dnsData = dnsGetFirstAvailable()))
+       dnsDispatch(dnsData, i);
+    else
+       dnsEnqueue(i);
+    return 0;
+}
+
+static void dnsEnqueue(i)
+     ipcache_entry *i;
+{
+    struct dnsQueueData *new = xcalloc(1, sizeof(struct dnsQueueData));
+    new->ip_entry = i;
+    *dnsQueueTailP = new;
+    dnsQueueTailP = &new->next;
+}
+
+static ipcache_entry *dnsDequeue()
+{
+    struct dnsQueueData *old = NULL;
+    ipcache_entry *i = NULL;
+    if (dnsQueueHead) {
+       i = dnsQueueHead->ip_entry;
+       old = dnsQueueHead;
+       dnsQueueHead = dnsQueueHead->next;
+       if (dnsQueueHead == NULL)
+           dnsQueueTailP = &dnsQueueHead;
+       safe_free(old);
+    }
+#ifdef SANITY_CHECK
+    if (i == NULL) {
+       for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) {
+           if (i->status == IP_PENDING) {      /* This can't happen */
+               debug(14, 0, "IP Cache inconsistency: %s still pending\n",
+                   i->name);
+           }
        }
-    } else {
-       last_dns_dispatched = 0;
+       i = NULL;
     }
+#endif
+    return i;
+}
 
-    dns = dns_child_table[last_dns_dispatched];
-    debug(14, 5, "ipcache_nbgethostbyname: Dispatched DNS %d.\n",
-       last_dns_dispatched);
-
-    /* add to global pending list */
-    if (dns->global_pending == NULL) { /* new list */
-       dns->global_pending = (ipcache_list *) xcalloc(1, sizeof(ipcache_list));
-       dns->global_pending->entry = e;
-       dns->global_pending->next = NULL;
-       dns->global_pending_tail = dns->global_pending;
-    } else {                   /* add to end of list */
-       ipcache_list *p = (ipcache_list *) xcalloc(1, sizeof(ipcache_list));
-       p->entry = e;
-       p->next = NULL;
-       dns->global_pending_tail->next = p;
-       dns->global_pending_tail = dns->global_pending_tail->next;
+static dnsserver_t *dnsGetFirstAvailable()
+{
+    int k;
+    dnsserver_t *dns = NULL;
+    for (k = 0; k < NDnsServersAlloc; k++) {
+       dns = *(dns_child_table + k);
+       if (!(dns->flags & DNS_FLAG_BUSY))
+           return dns;
     }
+    return NULL;
+}
 
-    if (dns_child_alive) {
-       char *buf = (char *) xcalloc(1, 256);
-       strncpy(buf, name, 254);
-       strcat(buf, "\n");
-       dns->pending_count++;
-       file_write(dns->outpipe,
-           buf,
-           strlen(buf),
-           0,                  /* Lock */
-           0,                  /* Handler */
-           0);                 /* Handler-data */
-
-       debug(14, 5, "ipcache_nbgethostbyname: Request sent DNS server ID %d.\n", last_dns_dispatched);
-    } else {
-       /* do a blocking mode */
-       debug(14, 4, "ipcache_nbgethostbyname: Fall back to blocking mode.  Server's dead...\n");
-       ipcache_cleanup_pendinglist(dns);
+static void dnsDispatch(dns, i)
+     dnsserver_t *dns;
+     ipcache_entry *i;
+{
+    char *buf = NULL;
+    if (!ipcacheHasPending(i)) {
+       debug(14, 0, "dnsDispatch: skipping '%s' because no handler.\n",
+           i->name);
+       i->status = IP_NEGATIVE_CACHED;
+       ipcache_release(i);
+       return;
     }
-    return 0;
+    i->status = IP_DISPATCHED;
+    buf = xcalloc(1, 256);
+    sprintf(buf, "%1.254s\n", i->name);
+    dns->flags |= DNS_FLAG_BUSY;
+    dns->ip_entry = i;
+    comm_write(dns->outpipe,
+       buf,
+       strlen(buf),
+       0,                      /* timeout */
+       NULL,                   /* Handler */
+       NULL);                  /* Handler-data */
+    debug(14, 5, "dnsDispatch: Request sent to DNS server #%d.\n",
+       dns->id);
+    dns->dispatch_time = current_time;
+    IpcacheStats.dnsserver_requests++;
+    IpcacheStats.dnsserver_hist[dns->id - 1]++;
 }
 
 
@@ -1061,68 +1029,61 @@ void ipcacheOpenServers()
 {
     int N = getDnsChildren();
     char *prg = getDnsProgram();
-    int i;
+    int k;
     int dnssocket;
     static char fd_note_buf[FD_ASCII_NOTE_SZ];
-    static int NChildrenAlloc = 0;
 
     /* free old structures if present */
     if (dns_child_table) {
-       for (i = 0; i < NChildrenAlloc; i++)
-           safe_free(dns_child_table[i]->ip_inbuf);
+       for (k = 0; k < NDnsServersAlloc; k++) {
+           safe_free(dns_child_table[k]->ip_inbuf);
+           safe_free(dns_child_table[k]);
+       }
        safe_free(dns_child_table);
     }
-    dns_child_table = (dnsserver_entry **) xcalloc(N, sizeof(dnsserver_entry));
-    NChildrenAlloc = N;
-    dns_child_alive = 0;
+    dns_child_table = xcalloc(N, sizeof(dnsserver_t *));
+    NDnsServersAlloc = N;
     debug(14, 1, "ipcacheOpenServers: Starting %d 'dns_server' processes\n", N);
-    for (i = 0; i < N; i++) {
-       dns_child_table[i] = (dnsserver_entry *) xcalloc(1, sizeof(dnsserver_entry));
+    for (k = 0; k < N; k++) {
+       dns_child_table[k] = xcalloc(1, sizeof(dnsserver_t));
        if ((dnssocket = ipcache_create_dnsserver(prg)) < 0) {
            debug(14, 1, "ipcacheOpenServers: WARNING: Cannot run 'dnsserver' process.\n");
            debug(14, 1, "              Fallling back to the blocking version.\n");
-           dns_child_table[i]->alive = 0;
+           dns_child_table[k]->flags &= ~DNS_FLAG_ALIVE;
        } else {
-           dns_child_alive = 1;
-           dns_child_table[i]->id = i;
-           dns_child_table[i]->inpipe = dnssocket;
-           dns_child_table[i]->outpipe = dnssocket;
-           dns_child_table[i]->lastcall = squid_curtime;
-           dns_child_table[i]->pending_count = 0;
-           dns_child_table[i]->size = IP_INBUF - 1;    /* spare one for \0 */
-           dns_child_table[i]->offset = 0;
-           dns_child_table[i]->alive = 1;
-           dns_child_table[i]->ip_inbuf = (char *) xcalloc(1, IP_INBUF);
+           debug(14, 4, "ipcacheOpenServers: FD %d connected to %s #%d.\n",
+               dnssocket, prg, k + 1);
+           dns_child_table[k]->flags |= DNS_FLAG_ALIVE;
+           dns_child_table[k]->id = k + 1;
+           dns_child_table[k]->inpipe = dnssocket;
+           dns_child_table[k]->outpipe = dnssocket;
+           dns_child_table[k]->lastcall = squid_curtime;
+           dns_child_table[k]->size = IP_INBUF_SZ - 1;         /* spare one for \0 */
+           dns_child_table[k]->offset = 0;
+           dns_child_table[k]->ip_inbuf = xcalloc(IP_INBUF_SZ, 1);
 
            /* update fd_stat */
 
-           sprintf(fd_note_buf, "%s #%d",
-               prg,
-               dns_child_table[i]->id);
-           file_update_open(dns_child_table[i]->inpipe, fd_note_buf);
-
-           debug(14, 5, "Calling fd_note() with FD %d and buf '%s'\n",
-               dns_child_table[i]->inpipe, fd_note_buf);
-
-           fd_note(dns_child_table[i]->inpipe, fd_note_buf);
-           commSetNonBlocking(dns_child_table[i]->inpipe);
+           sprintf(fd_note_buf, "%s #%d", prg, dns_child_table[k]->id);
+           fd_note(dns_child_table[k]->inpipe, fd_note_buf);
+           commSetNonBlocking(dns_child_table[k]->inpipe);
 
            /* clear unused handlers */
-           comm_set_select_handler(dns_child_table[i]->inpipe,
+           comm_set_select_handler(dns_child_table[k]->inpipe,
                COMM_SELECT_WRITE,
                0,
                0);
-           comm_set_select_handler(dns_child_table[i]->outpipe,
+           comm_set_select_handler(dns_child_table[k]->outpipe,
                COMM_SELECT_READ,
                0,
                0);
 
            /* set handler for incoming result */
-           comm_set_select_handler(dns_child_table[i]->inpipe,
+           comm_set_select_handler(dns_child_table[k]->inpipe,
                COMM_SELECT_READ,
                (PF) ipcache_dnsHandleRead,
-               (void *) dns_child_table[i]);
-           debug(14, 3, "ipcacheOpenServers: 'dns_server' %d started\n", i);
+               (void *) dns_child_table[k]);
+           debug(14, 3, "ipcacheOpenServers: 'dns_server' %d started\n", k);
        }
     }
 }
@@ -1133,12 +1094,10 @@ void ipcache_init()
 
     debug(14, 3, "Initializing IP Cache...\n");
 
-    last_dns_dispatched = getDnsChildren() - 1;
-    if (!dns_error_message)
-       dns_error_message = xcalloc(1, 256);
+    memset(&IpcacheStats, '\0', sizeof(IpcacheStats));
 
     /* test naming lookup */
-    if (!do_dns_test) {
+    if (!opt_dns_tests) {
        debug(14, 4, "ipcache_init: Skipping DNS name lookup tests.\n");
     } else if (!ipcache_testname()) {
        fatal("ipcache_init: DNS name lookup tests failed/");
@@ -1148,12 +1107,12 @@ void ipcache_init()
 
     ip_table = hash_create(urlcmp, 229);       /* small hash table */
     /* init static area */
-    static_result = (struct hostent *) xcalloc(1, sizeof(struct hostent));
+    static_result = xcalloc(1, sizeof(struct hostent));
     static_result->h_length = 4;
     /* Need a terminating NULL address (h_addr_list[1]) */
-    static_result->h_addr_list = (char **) xcalloc(2, sizeof(char *));
-    static_result->h_addr_list[0] = (char *) xcalloc(1, 4);
-    static_result->h_name = (char *) xcalloc(1, MAX_HOST_NAME + 1);
+    static_result->h_addr_list = xcalloc(2, sizeof(char *));
+    static_result->h_addr_list[0] = xcalloc(1, 4);
+    static_result->h_name = xcalloc(1, MAX_HOST_NAME + 1);
 
     ipcacheOpenServers();
 
@@ -1169,201 +1128,201 @@ int ipcache_unregister(name, fd)
      char *name;
      int fd;
 {
-    ipcache_entry *e;
-    IpPending *p, *q;
-
-    e = ipcache_get(name);
-    if (!e) {
-       /* not found any where */
-       return 0;
-    }
-    /* look for matched fd */
-    for (q = p = e->pending_head; p; q = p, p = p->next) {
-       if (p->fd == fd) {
-           break;
-       }
-    }
+    ipcache_entry *i = NULL;
+    struct _ip_pending *p = NULL;
+    int n = 0;
 
-    if (p == NULL) {
-       /* Can not find this ipcache_entry, weird */
-       debug(14, 1, "ipcache_unregister: Failed to unregister FD %d from name: %s, can't find this FD.\n",
-           fd, name);
+    debug(14, 3, "ipcache_unregister: FD %d, name '%s'\n", fd, name);
+    if ((i = ipcache_get(name)) == NULL)
        return 0;
-    }
-    /* found */
-    if (p == e->pending_head) {
-       /* it's at the head of the queue */
-       if (p->next) {
-           /* there is something along the line */
-           e->pending_head = p->next;
-           safe_free(p->data);
-           safe_free(p);
-       } else {
-           /* it is the only entry */
-           e->pending_head = e->pending_tail = NULL;
-           safe_free(p->data);
-           safe_free(p);
+    if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
+       for (p = i->pending_head; p; p = p->next) {
+           if (p->fd == fd && p->handler != NULL) {
+               p->handler = NULL;
+               p->fd = -1;
+               n++;
+           }
        }
-    } else if (p == e->pending_tail) {
-       /* it's at the tail */
-       e->pending_tail = q;
-       q->next = NULL;
-       safe_free(p->data);
-       safe_free(p);
-    } else {
-       /* it's in the middle */
-       /* skip it in the list */
-       q->next = p->next;
-       safe_free(p->data);
-       safe_free(p);
     }
-    return 1;
+    debug(14, 3, "ipcache_unregister: unregistered %d handlers\n", n);
+    return n;
 }
 
-
-struct hostent *ipcache_gethostbyname(name)
+struct hostent *ipcache_gethostbyname(name, flags)
      char *name;
+     int flags;
 {
-    ipcache_entry *result;
-    unsigned int a1, a2, a3, a4;
-    struct hostent *s_result = NULL;
-
-    if (!name) {
-       debug(14, 5, "ipcache_gethostbyname: Invalid argument?\n");
-       return (NULL);
-    }
-    if (!(result = ipcache_get(name))) {
-       /* cache miss */
-       if (name) {
-           debug(14, 5, "ipcache_gethostbyname: IPcache miss for '%s'.\n", name);
-       }
-       /* check if it's already a IP address in text form. */
-       if (sscanf(name, "%u.%u.%u.%u", &a1, &a2, &a3, &a4) == 4) {
-           *((unsigned long *) (void *) static_result->h_addr_list[0]) = inet_addr(name);
-           strncpy(static_result->h_name, name, MAX_HOST_NAME);
-           return static_result;
+    ipcache_entry *i = NULL;
+    struct hostent *hp = NULL;
+    unsigned int ip;
+
+    if (!name)
+       fatal_dump("ipcache_gethostbyname: NULL name");
+    IpcacheStats.requests++;
+    if ((i = ipcache_get(name))) {
+       if (i->status == IP_PENDING || i->status == IP_DISPATCHED) {
+           IpcacheStats.pending_hits++;
+           return NULL;
+       } else if (i->status == IP_NEGATIVE_CACHED) {
+           IpcacheStats.negative_hits++;
+           dns_error_message = i->error_message;
+           return NULL;
        } else {
-           s_result = gethostbyname(name);
+           IpcacheStats.hits++;
+           i->lastref = squid_curtime;
+           return &i->entry;
        }
-
-       if (s_result && s_result->h_name && (s_result->h_name[0] != '\0')) {
+    }
+    IpcacheStats.misses++;
+    /* check if it's already a IP address in text form. */
+    if ((ip = inet_addr(name)) != INADDR_NONE) {
+       *((u_num32 *) (void *) static_result->h_addr_list[0]) = ip;
+       strncpy(static_result->h_name, name, MAX_HOST_NAME);
+       return static_result;
+    }
+    if (flags & IP_BLOCKING_LOOKUP) {
+       IpcacheStats.ghbn_calls++;
+       hp = gethostbyname(name);
+       if (hp && hp->h_name && (hp->h_name[0] != '\0') && ip_table) {
            /* good address, cached */
-           debug(14, 10, "ipcache_gethostbyname: DNS success: cache for '%s'.\n", name);
-           ipcache_add(name, ipcache_create(), s_result, 1);
-           result = ipcache_get(name);
-           return &(result->entry);
-       } else {
-           /* bad address, negative cached */
-           debug(14, 3, "ipcache_gethostbyname: DNS failure: negative cache for '%s'.\n", name);
-           ipcache_add(name, ipcache_create(), s_result, 0);
-           return NULL;
+           ipcache_add(name, ipcache_create(), hp, 1);
+           i = ipcache_get(name);
+           return &i->entry;
        }
-
+       /* bad address, negative cached */
+       if (ip_table)
+           ipcache_add(name, ipcache_create(), hp, 0);
+       return NULL;
     }
-    /* cache hit */
-    debug(14, 5, "ipcache_gethostbyname: Hit for '%s'.\n", name ? name : "NULL");
-    result->lastref = squid_curtime;
-    return (result->status == CACHED) ? &(result->entry) : NULL;
+    if (flags & IP_LOOKUP_IF_MISS)
+       ipcache_nbgethostbyname(name, -1, dummy_handler, NULL);
+    return NULL;
 }
 
 
-
 /* process objects list */
-void stat_ipcache_get(sentry, obj)
+void stat_ipcache_get(sentry)
      StoreEntry *sentry;
-     cacheinfo *obj;
 {
-    char buffer[MAX_LINELEN];
-    ipcache_entry *e = NULL;
-    int i;
+    ipcache_entry *i = NULL;
+    int k;
     int ttl;
-    char status;
-
-    sprintf(buffer, "{IP Cache Contents:\n\n");
-    storeAppend(sentry, buffer, strlen(buffer));
-
-    for (e = ipcache_GetFirst(); (e); e = ipcache_GetNext()) {
-       if (e) {
-           ttl = (e->ttl - squid_curtime + e->lastref);
-           status = ipcache_status_char(e);
-           if (status == 'P')
-               ttl = 0;
-
-           sprintf(buffer, " {%s %c %d %d",
-               e->name, status, ttl, e->addr_count);
-           storeAppend(sentry, buffer, strlen(buffer));
-
-           for (i = 0; i < (int) e->addr_count; i++) {
-               struct in_addr addr;
-               memcpy((char *) &addr, e->entry.h_addr_list[i], e->entry.h_length);
 
-               sprintf(buffer, " %s", inet_ntoa(addr));
-               storeAppend(sentry, buffer, strlen(buffer));
-           }
-           for (i = 0; i < (int) e->alias_count; i++) {
-               sprintf(buffer, " %s", e->entry.h_aliases[i]);
-               storeAppend(sentry, buffer, strlen(buffer));
-           }
-           if (e->entry.h_name && strncmp(e->name, e->entry.h_name, MAX_LINELEN)) {
-               sprintf(buffer, " %s", e->entry.h_name);
-               storeAppend(sentry, buffer, strlen(buffer));
-           }
-           sprintf(buffer, "}\n");
-           storeAppend(sentry, buffer, strlen(buffer));
-       }
-    }
-    sprintf(buffer, "}\n");
-    storeAppend(sentry, buffer, strlen(buffer));
-
-}
+    if (!ip_table)
+       return;
 
-char ipcache_status_char(e)
-     ipcache_entry *e;
-{
-    switch (e->status) {
-    case CACHED:
-       return ('C');
-    case PENDING:
-       return ('P');
-    case NEGATIVE_CACHED:
-       return ('N');
-    default:
-       debug(14, 1, "ipcache_status_char: unexpected IP cache status.\n");
+    storeAppendPrintf(sentry, "{IP Cache Statistics:\n");
+    storeAppendPrintf(sentry, "{IPcache Entries: %d}\n",
+       meta_data.ipcache_count);
+    storeAppendPrintf(sentry, "{IPcache Requests: %d}\n",
+       IpcacheStats.requests);
+    storeAppendPrintf(sentry, "{IPcache Hits: %d}\n",
+       IpcacheStats.hits);
+    storeAppendPrintf(sentry, "{IPcache Pending Hits: %d}\n",
+       IpcacheStats.pending_hits);
+    storeAppendPrintf(sentry, "{IPcache Negative Hits: %d}\n",
+       IpcacheStats.negative_hits);
+    storeAppendPrintf(sentry, "{IPcache Misses: %d}\n",
+       IpcacheStats.misses);
+    storeAppendPrintf(sentry, "{Blocking calls to gethostbyname(): %d}\n",
+       IpcacheStats.ghbn_calls);
+    storeAppendPrintf(sentry, "{dnsserver requests: %d}\n",
+       IpcacheStats.dnsserver_requests);
+    storeAppendPrintf(sentry, "{dnsserver replies: %d}\n",
+       IpcacheStats.dnsserver_replies);
+    storeAppendPrintf(sentry, "{dnsserver avg service time: %d msec}\n",
+       IpcacheStats.avg_svc_time);
+    storeAppendPrintf(sentry, "{number of dnsservers: %d}\n",
+       getDnsChildren());
+    storeAppendPrintf(sentry, "{dnsservers use histogram:}\n");
+    for (k = 0; k < getDnsChildren(); k++) {
+       storeAppendPrintf(sentry, "{    dnsserver #%d: %d}\n",
+           k + 1,
+           IpcacheStats.dnsserver_hist[k]);
     }
-    return ('X');
-}
-
-int ipcache_hash_entry_count()
-{
-    ipcache_entry *e;
-    int local_ip_count = 0;
-
-    e = NULL;
-
-    for (e = ipcache_GetFirst(); e; e = ipcache_GetNext()) {
-       local_ip_count++;
+    storeAppendPrintf(sentry, "}\n\n");
+    storeAppendPrintf(sentry, "{IP Cache Contents:\n\n");
+
+    for (i = ipcache_GetFirst(); i; i = ipcache_GetNext()) {
+       if (i->status == IP_PENDING || i->status == IP_DISPATCHED)
+           ttl = 0;
+       else
+           ttl = (i->ttl - squid_curtime + i->lastref);
+       storeAppendPrintf(sentry, " {%-32.32s %c%c %6d %d",
+           i->name,
+           ipcache_status_char[i->status],
+           i->lock ? 'L' : ' ',
+           ttl,
+           i->addr_count);
+       for (k = 0; k < (int) i->addr_count; k++) {
+           struct in_addr addr;
+           xmemcpy(&addr, i->entry.h_addr_list[k], i->entry.h_length);
+           storeAppendPrintf(sentry, " %15s", inet_ntoa(addr));
+       }
+       for (k = 0; k < (int) i->alias_count; k++) {
+           storeAppendPrintf(sentry, " %s", i->entry.h_aliases[k]);
+       }
+       if (i->entry.h_name && strncmp(i->name, i->entry.h_name, MAX_LINELEN)) {
+           storeAppendPrintf(sentry, " %s", i->entry.h_name);
+       }
+       storeAppendPrintf(sentry, close_bracket);
     }
-
-    return local_ip_count;
+    storeAppendPrintf(sentry, close_bracket);
 }
 
 void ipcacheShutdownServers()
 {
-    dnsserver_entry *dns = NULL;
-    int i;
+    dnsserver_t *dnsData = NULL;
+    int k;
     static char *shutdown = "$shutdown\n";
 
     debug(14, 3, "ipcacheShutdownServers:\n");
 
-    for (i = 0; i < getDnsChildren(); i++) {
-       dns = *(dns_child_table + i);
-       debug(14, 3, "ipcacheShutdownServers: sending '$shutdown' to dnsserver #%d\n", i);
-       debug(14, 3, "ipcacheShutdownServers: --> FD %d\n", dns->outpipe);
-       file_write(dns->outpipe,
+    for (k = 0; k < getDnsChildren(); k++) {
+       dnsData = *(dns_child_table + k);
+       if (!(dnsData->flags & DNS_FLAG_ALIVE))
+           continue;
+       if (dnsData->flags & DNS_FLAG_BUSY)
+           continue;
+       if (dnsData->flags & DNS_FLAG_CLOSING)
+           continue;
+       debug(14, 3, "ipcacheShutdownServers: sending '$shutdown' to dnsserver #%d\n", dnsData->id);
+       debug(14, 3, "ipcacheShutdownServers: --> FD %d\n", dnsData->outpipe);
+       comm_write(dnsData->outpipe,
            xstrdup(shutdown),
            strlen(shutdown),
-           0,                  /* Lock */
-           0,                  /* Handler */
-           0);                 /* Handler-data */
+           0,                  /* timeout */
+           NULL,               /* Handler */
+           NULL);              /* Handler-data */
+       dnsData->flags |= DNS_FLAG_CLOSING;
     }
 }
+
+static int dummy_handler(u1, u2, u3)
+     int u1;
+     struct hostent *u2;
+     void *u3;
+{
+    return 0;
+}
+
+void ipcacheLockEntry(name)
+     char *name;
+{
+    ipcache_entry *i;
+    if ((i = ipcache_get(name)) == NULL)
+       return;
+    i->lock++;
+}
+
+static int ipcacheHasPending(i)
+     ipcache_entry *i;
+{
+    struct _ip_pending *p = NULL;
+    if (i->status != IP_PENDING)
+       return 0;
+    for (p = i->pending_head; p; p = p->next)
+       if (p->handler)
+           return 1;
+    return 0;
+}
index 1a008ccd6815dcae3a0181901041768cfdf9a1ae..5ae143e14ee839a4b70e1d50417b4b934e3f7e82 100644 (file)
-/* $Id: main.cc,v 1.46 1996/05/03 22:56:29 wessels Exp $ */
-
-/* DEBUG: Section 1             main: startup and main loop */
+/*
+ * $Id: main.cc,v 1.47 1996/07/09 03:41:32 wessels Exp $
+ *
+ * DEBUG: section 1     Startup and Main Loop
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include "squid.h"
 
 time_t squid_starttime = 0;
 time_t next_cleaning = 0;
-int theAsciiConnection = -1;
-int theUdpConnection = -1;
+int theHttpConnection = -1;
+int theInIcpConnection = -1;
+int theOutIcpConnection = -1;
 int do_reuse = 1;
 int opt_unlink_on_reload = 0;
+int opt_reload_hit_only = 0;   /* only UDP_HIT during store relaod */
 int catch_signals = 1;
-int do_dns_test = 1;
+int opt_dns_tests = 1;
+int opt_foreground_rebuild = 0;
 int vhost_mode = 0;
 int unbuffered_logs = 1;       /* debug and hierarhcy unbuffered by default */
 int shutdown_pending = 0;      /* set by SIGTERM handler (shut_down()) */
 int reread_pending = 0;                /* set by SIGHUP handler */
-char *version_string = SQUID_VERSION;
-char *appname = "squid";
-
-extern void (*failure_notify) ();      /* for error reporting from xmalloc */
-
-static int asciiPortNumOverride = 0;
-static int udpPortNumOverride = 0;
+char version_string[] = SQUID_VERSION;
+char appname[] = "squid";
+char localhost[] = "127.0.0.1";
+struct in_addr local_addr;
+
+/* for error reporting from xmalloc and friends */
+extern void (*failure_notify) _PARAMS((char *));
+
+static int rotate_pending = 0; /* set by SIGUSR1 handler */
+static int httpPortNumOverride = 1;
+static int icpPortNumOverride = 1;     /* Want to detect "-u 0" */
+#if MALLOC_DBG
 static int malloc_debug_level = 0;
+#endif
+static void rotate_logs _PARAMS((int));
+static void reconfigure _PARAMS((int));
 
 static void usage()
 {
     fprintf(stderr, "\
-Usage: %s [-Rsehvz] [-f config-file] [-[apu] port]\n\
+Usage: %s [-hsvzCDFRUVY] [-f config-file] [-[au] port]\n\
+       -a port   Specify ASCII port number (default: %d).\n\
+       -f file   Use given config-file instead of\n\
+                 %s\n\
        -h        Print help message.\n\
        -s        Enable logging to syslog.\n\
+       -u port   Specify UDP port number (default: %d), disable with 0.\n\
        -v        Print version.\n\
        -z        Zap disk storage -- deletes all objects in disk cache.\n\
        -C        Do not catch fatal signals.\n\
        -D        Disable initial DNS tests.\n\
+       -F        Foreground fast store rebuild.\n\
        -R        Do not set REUSEADDR on port.\n\
        -U        Unlink expired objects on reload.\n\
-       -f file   Use given config-file instead of\n\
-                 %s\n\
-       -a port  Specify ASCII port number (default: %d).\n\
-       -u port  Specify UDP port number (default: %d).\n",
-       appname, DefaultConfigFile, CACHE_HTTP_PORT, CACHE_ICP_PORT);
+       -V        Virtual host httpd-accelerator.\n\
+       -Y        Only return UDP_HIT or UDP_DENIED during fast store reload.\n",
+       appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
     exit(1);
 }
 
@@ -52,26 +167,16 @@ static void mainParseOptions(argc, argv)
     extern char *optarg;
     int c;
 
-    while ((c = getopt(argc, argv, "vCDRVUbsif:a:p:u:m:zh?")) != -1) {
+    while ((c = getopt(argc, argv, "CDFRUVYa:bf:hm:su:vz?")) != -1) {
        switch (c) {
-       case 'v':
-           printf("Squid Cache: Version %s\n", version_string);
-           exit(0);
-           /* NOTREACHED */
-       case 'b':
-           unbuffered_logs = 0;
-           break;
-       case 'V':
-           vhost_mode = 1;
-           break;
        case 'C':
            catch_signals = 0;
            break;
        case 'D':
-           do_dns_test = 0;
+           opt_dns_tests = 0;
            break;
-       case 's':
-           syslog_enable = 0;
+       case 'F':
+           opt_foreground_rebuild = 1;
            break;
        case 'R':
            do_reuse = 0;
@@ -79,24 +184,48 @@ static void mainParseOptions(argc, argv)
        case 'U':
            opt_unlink_on_reload = 1;
            break;
+       case 'V':
+           vhost_mode = 1;
+           break;
+       case 'Y':
+           opt_reload_hit_only = 1;
+           break;
+       case 'a':
+           httpPortNumOverride = atoi(optarg);
+           break;
+       case 'b':
+           unbuffered_logs = 0;
+           break;
        case 'f':
            xfree(ConfigFile);
            ConfigFile = xstrdup(optarg);
            break;
-       case 'a':
-           asciiPortNumOverride = atoi(optarg);
-           break;
-       case 'u':
-           udpPortNumOverride = atoi(optarg);
+       case 'h':
+           usage();
            break;
        case 'm':
+#if MALLOC_DBG
            malloc_debug_level = atoi(optarg);
            break;
+#else
+           fatal("Need to add -DMALLOC_DBG when compiling to use -m option");
+#endif
+       case 's':
+           syslog_enable = 0;
+           break;
+       case 'u':
+           icpPortNumOverride = atoi(optarg);
+           if (icpPortNumOverride < 0)
+               icpPortNumOverride = 0;
+           break;
+       case 'v':
+           printf("Squid Cache: Version %s\n", version_string);
+           exit(0);
+           /* NOTREACHED */
        case 'z':
            zap_disk_store = 1;
            break;
        case '?':
-       case 'h':
        default:
            usage();
            break;
@@ -104,72 +233,132 @@ static void mainParseOptions(argc, argv)
     }
 }
 
+void rotate_logs(sig)
+     int sig;
+{
+    debug(21, 1, "rotate_logs: SIGUSR1 received.\n");
+    rotate_pending = 1;
+#if !HAVE_SIGACTION
+    signal(sig, rotate_logs);
+#endif
+}
+
+void reconfigure(sig)
+     int sig;
+{
+    debug(21, 1, "reconfigure: SIGHUP received\n");
+    debug(21, 1, "Waiting %d seconds for active connections to finish\n",
+       getShutdownLifetime());
+    reread_pending = 1;
+#if !HAVE_SIGACTION
+    signal(sig, reconfigure);
+#endif
+}
+
+void shut_down(sig)
+     int sig;
+{
+    debug(21, 1, "Preparing for shutdown after %d connections\n",
+       ntcpconn + nudpconn);
+    debug(21, 1, "Waiting %d seconds for active connections to finish\n",
+       getShutdownLifetime());
+    shutdown_pending = 1;
+}
+
 void serverConnectionsOpen()
 {
+    struct in_addr addr;
+    u_short port;
     /* Get our real priviliges */
-    get_suid();
 
     /* Open server ports */
-    theAsciiConnection = comm_open(COMM_NONBLOCKING,
-       getAsciiPortNum(),
-       0,
-       "Ascii Port");
-    if (theAsciiConnection < 0) {
-       fatal("Cannot open ascii Port");
+    enter_suid();
+    theHttpConnection = comm_open(COMM_NONBLOCKING,
+       getTcpIncomingAddr(),
+       getHttpPortNum(),
+       "HTTP Port");
+    leave_suid();
+    if (theHttpConnection < 0) {
+       fatal("Cannot open HTTP Port");
     }
-    fd_note(theAsciiConnection, "HTTP (Ascii) socket");
-    comm_listen(theAsciiConnection);
-    comm_set_select_handler(theAsciiConnection,
+    fd_note(theHttpConnection, "HTTP socket");
+    comm_listen(theHttpConnection);
+    comm_set_select_handler(theHttpConnection,
        COMM_SELECT_READ,
        asciiHandleConn,
        0);
-    debug(1, 1, "Accepting HTTP (ASCII) connections on FD %d.\n",
-       theAsciiConnection);
+    debug(1, 1, "Accepting HTTP connections on FD %d.\n",
+       theHttpConnection);
 
     if (!httpd_accel_mode || getAccelWithProxy()) {
-       if (getUdpPortNum() > -1) {
-           theUdpConnection = comm_open(COMM_NONBLOCKING | COMM_DGRAM,
-               getUdpPortNum(),
-               0,
-               "Ping Port");
-           if (theUdpConnection < 0)
-               fatal("Cannot open UDP Port");
-           fd_note(theUdpConnection, "ICP (UDP) socket");
-           comm_set_select_handler(theUdpConnection,
+       if ((port = getIcpPortNum()) > 0) {
+           theInIcpConnection = comm_open(COMM_NONBLOCKING | COMM_DGRAM,
+               getUdpIncomingAddr(),
+               port,
+               "ICP Port");
+           if (theInIcpConnection < 0)
+               fatal("Cannot open ICP Port");
+           fd_note(theInIcpConnection, "ICP socket");
+           comm_set_select_handler(theInIcpConnection,
                COMM_SELECT_READ,
                icpHandleUdp,
                0);
-           debug(1, 1, "Accepting ICP (UDP) connections on FD %d.\n",
-               theUdpConnection);
+           debug(1, 1, "Accepting ICP connections on FD %d.\n",
+               theInIcpConnection);
+
+           if ((addr = getUdpOutgoingAddr()).s_addr != INADDR_NONE) {
+               theOutIcpConnection = comm_open(COMM_NONBLOCKING | COMM_DGRAM,
+                   addr,
+                   port,
+                   "ICP Port");
+               if (theOutIcpConnection < 0)
+                   fatal("Cannot open Outgoing ICP Port");
+               comm_set_select_handler(theOutIcpConnection,
+                   COMM_SELECT_READ,
+                   icpHandleUdp,
+                   0);
+               debug(1, 1, "Accepting ICP connections on FD %d.\n",
+                   theOutIcpConnection);
+               fd_note(theOutIcpConnection, "Outgoing ICP socket");
+               fd_note(theInIcpConnection, "Incoming ICP socket");
+           } else {
+               theOutIcpConnection = theInIcpConnection;
+           }
        }
     }
-    /* And restore our priviliges to normal */
-    check_suid();
 }
 
 void serverConnectionsClose()
 {
-    if (theAsciiConnection >= 0) {
-       debug(21, 1, "FD %d Closing Ascii connection\n",
-           theAsciiConnection);
-       comm_close(theAsciiConnection);
-       comm_set_select_handler(theAsciiConnection,
+    /* NOTE, this function will be called repeatedly while shutdown
+     * is pending */
+    if (theHttpConnection >= 0) {
+       debug(21, 1, "FD %d Closing HTTP connection\n",
+           theHttpConnection);
+       comm_close(theHttpConnection);
+       comm_set_select_handler(theHttpConnection,
            COMM_SELECT_READ,
            NULL,
            0);
-       theAsciiConnection = -1;
+       theHttpConnection = -1;
     }
-    if (theUdpConnection >= 0) {
-       debug(21, 1, "FD %d Closing Udp connection\n",
-           theUdpConnection);
-       /* Dont actually close it, just disable the read handler */
-       /* so we can still transmit while shutdown pending */
-       /* comm_close(theUdpConnection); */
-       comm_set_select_handler(theUdpConnection,
+    if (theInIcpConnection >= 0) {
+       /* NOTE, don't close outgoing ICP connection, we need to write to
+        * it during shutdown */
+       debug(21, 1, "FD %d Closing ICP connection\n",
+           theInIcpConnection);
+       if (theInIcpConnection != theOutIcpConnection)
+           comm_close(theInIcpConnection);
+       comm_set_select_handler(theInIcpConnection,
            COMM_SELECT_READ,
            NULL,
            0);
-       /* theUdpConnection = -1; */
+       if (theInIcpConnection != theOutIcpConnection)
+           comm_set_select_handler(theOutIcpConnection,
+               COMM_SELECT_READ,
+               NULL,
+               0);
+       theInIcpConnection = -1;
     }
 }
 
@@ -180,58 +369,58 @@ static void mainReinitialize()
     neighborsDestroy();
 
     parseConfigFile(ConfigFile);
-    _db_init(getCacheLogFile());
+    _db_init(getCacheLogFile(), getDebugOptions());
     neighbors_init();
     ipcacheOpenServers();
     serverConnectionsOpen();
     (void) ftpInitialize();
-    if (theUdpConnection >= 0 && (!httpd_accel_mode || getAccelWithProxy()))
-       neighbors_open(theUdpConnection);
+    if (theOutIcpConnection >= 0 && (!httpd_accel_mode || getAccelWithProxy()))
+       neighbors_open(theOutIcpConnection);
     debug(1, 0, "Ready to serve requests.\n");
 }
 
 static void mainInitialize()
 {
     static int first_time = 1;
-
     if (catch_signals) {
-       signal(SIGSEGV, death);
-       signal(SIGBUS, death);
+       squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
+       squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
     }
-    signal(SIGPIPE, SIG_IGN);
-    signal(SIGCHLD, sig_child);
+    squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
+    squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
 
     if (ConfigFile == NULL)
        ConfigFile = xstrdup(DefaultConfigFile);
     parseConfigFile(ConfigFile);
 
-    if (asciiPortNumOverride > 0)
-       setAsciiPortNum(asciiPortNumOverride);
-    if (udpPortNumOverride > 0)
-       setUdpPortNum(udpPortNumOverride);
+    leave_suid();              /* Run as non privilegied user */
 
-    _db_init(getCacheLogFile());
-    fdstat_open(fileno(debug_log), LOG);
+    if (httpPortNumOverride != 1)
+       setHttpPortNum((u_short) httpPortNumOverride);
+    if (icpPortNumOverride != 1)
+       setIcpPortNum((u_short) icpPortNumOverride);
+
+    _db_init(getCacheLogFile(), getDebugOptions());
+    fdstat_open(fileno(debug_log), FD_LOG);
     fd_note(fileno(debug_log), getCacheLogFile());
 
-    debug(1, 0, "Starting Squid Cache (version %s)...\n", version_string);
-    debug(1, 1, "With %d file descriptors available\n", getMaxFD());
+    debug(1, 0, "Starting Squid Cache version %s for %s...\n",
+       version_string,
+       CONFIG_HOST_TYPE);
+    debug(1, 1, "With %d file descriptors available\n", FD_SETSIZE);
 
     if (first_time) {
        disk_init();            /* disk_init must go before ipcache_init() */
-       writePidFile();         /* write PID file before setuid() */
+       writePidFile();         /* write PID file */
     }
     ipcache_init();
     neighbors_init();
     (void) ftpInitialize();
 
-#if defined(MALLOC_DBG)
+#if MALLOC_DBG
     malloc_debug(0, malloc_debug_level);
 #endif
 
-    /* do suid checking */
-    check_suid();
-
     if (first_time) {
        first_time = 0;
        /* module initialization */
@@ -252,14 +441,14 @@ static void mainInitialize()
        do_mallinfo = 1;
     }
     serverConnectionsOpen();
-    if (theUdpConnection >= 0 && (!httpd_accel_mode || getAccelWithProxy()))
-       neighbors_open(theUdpConnection);
-
-    signal(SIGUSR1, rotate_logs);
-    signal(SIGHUP, reconfigure);
-    signal(SIGTERM, shut_down);
-    signal(SIGINT, shut_down);
-
+    if (theOutIcpConnection >= 0 && (!httpd_accel_mode || getAccelWithProxy()))
+       neighbors_open(theOutIcpConnection);
+
+    squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
+    squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
+    squid_signal(SIGHUP, reconfigure, SA_RESTART);
+    squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
+    squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
     debug(1, 0, "Ready to serve requests.\n");
 }
 
@@ -274,6 +463,9 @@ int main(argc, argv)
     time_t last_announce = 0;
     time_t loop_delay;
 
+    memset(&local_addr, '\0', sizeof(struct in_addr));
+    local_addr.s_addr = inet_addr(localhost);
+
     errorInitialize();
 
     squid_starttime = getCurrentTime();
@@ -283,28 +475,33 @@ int main(argc, argv)
 
     setMaxFD();
 
-    for (n = getMaxFD(); n > 2; n--)
-       close(n);
+    if (catch_signals)
+       for (n = FD_SETSIZE; n > 2; n--)
+           close(n);
 
 #if HAVE_MALLOPT
-    /* set malloc option */
-    /* use small block algorithm for faster allocation */
-    /* grain of small block */
+#ifdef M_GRAIN
+    /* Round up all sizes to a multiple of this */
     mallopt(M_GRAIN, 16);
+#endif
+#ifdef M_MXFAST
     /* biggest size that is considered a small block */
-    mallopt(M_MXFAST, 4096);
-    /* number of holding small block */
-    mallopt(M_NLBLKS, 100);
+    mallopt(M_MXFAST, 256);
 #endif
+#ifdef M_NBLKS
+    /* allocate this many small blocks at once */
+    mallopt(M_NLBLKS, 32);
+#endif
+#endif /* HAVE_MALLOPT */
 
     /*init comm module */
     comm_init();
 
     /* we have to init fdstat here. */
     fdstat_init(PREOPEN_FD);
-    fdstat_open(0, LOG);
-    fdstat_open(1, LOG);
-    fdstat_open(2, LOG);
+    fdstat_open(0, FD_LOG);
+    fdstat_open(1, FD_LOG);
+    fdstat_open(2, FD_LOG);
     fd_note(0, "STDIN");
     fd_note(1, "STDOUT");
     fd_note(2, "STDERR");
@@ -322,12 +519,22 @@ int main(argc, argv)
     if (getCleanRate() > 0)
        next_cleaning = time(NULL) + getCleanRate();
     for (;;) {
-       loop_delay = (time_t) 60;
+       loop_delay = (time_t) 10;
        /* maintain cache storage */
        if (squid_curtime > last_maintain) {
            storeMaintainSwapSpace();
            last_maintain = squid_curtime;
        }
+       if (rotate_pending) {
+           ftpServerClose();
+           _db_rotate_log();   /* cache.log */
+           storeWriteCleanLog();
+           storeRotateLog();   /* store.log */
+           neighbors_rotate_log();     /* hierarchy.log */
+           stat_rotate_log();  /* access.log */
+           (void) ftpInitialize();
+           rotate_pending = 0;
+       }
        /* do background processing */
        if (doBackgroundProcessing())
            loop_delay = (time_t) 0;
@@ -342,9 +549,6 @@ int main(argc, argv)
                fatal_dump("Select Loop failed!");
            break;
        case COMM_TIMEOUT:
-           /* this happens after 1 minute of idle time, or
-            * when next_cleaning has arrived */
-           /* garbage collection */
            if (getCleanRate() > 0 && squid_curtime >= next_cleaning) {
                debug(1, 1, "Performing a garbage collection...\n");
                n = storePurgeOld();
@@ -360,9 +564,9 @@ int main(argc, argv)
            break;
        case COMM_SHUTDOWN:
            /* delayed close so we can transmit while shutdown pending */
-           if (theUdpConnection > 0) {
-               comm_close(theUdpConnection);
-               theUdpConnection = -1;
+           if (theOutIcpConnection > 0) {
+               comm_close(theOutIcpConnection);
+               theOutIcpConnection = -1;
            }
            if (shutdown_pending) {
                normal_shutdown();
index 055989c36b2a4e057c2cd54840ef9b4924f2f260..7c1335c4a55580bb4d4e4600f6da80c9fe1e0cce 100644 (file)
@@ -1,8 +1,106 @@
-
-/* $Id: mime.cc,v 1.12 1996/04/16 05:05:25 wessels Exp $ */
+/*
+ * $Id: mime.cc,v 1.13 1996/07/09 03:41:33 wessels Exp $
+ *
+ * DEBUG: section 25    MIME Parsing
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 25          mime
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
@@ -50,19 +148,36 @@ char *mime_get_header(char *mime, char *name)
     return NULL;
 }
 
-int mime_refresh_request(mime)
-     char *mime;
+/* need to take the lowest, non-zero pointer to the end of the headers.
+ * The headers end at the first empty line */
+char *mime_headers_end(char *mime)
 {
-    char *pr = NULL;
-    if (mime == NULL)
+    char *p1, *p2;
+    char *end = NULL;
+
+    p1 = strstr(mime, "\r\n\r\n");
+    p2 = strstr(mime, "\n\n");
+
+    if (p1 && p2)
+       end = p1 < p2 ? p1 : p2;
+    else
+       end = p1 ? p1 : p2;
+    if (end)
+       end += (end == p1 ? 4 : 2);
+
+    return end;
+}
+
+int mime_headers_size(char *mime)
+{
+    char *end;
+
+    end = mime_headers_end(mime);
+
+    if (end)
+       return end - mime;
+    else
        return 0;
-    if (mime_get_header(mime, "If-Modified-Since"))
-       return 1;
-    if ((pr = mime_get_header(mime, "pragma"))) {
-       if (strcasecmp(pr, "no-cache"))
-           return 1;
-    }
-    return 0;
 }
 
 ext_table_entry *mime_ext_to_type(extension)
@@ -106,27 +221,39 @@ ext_table_entry *mime_ext_to_type(extension)
  *  returns non-zero on error, or 0 on success.
  */
 int mk_mime_hdr(result, ttl, size, lmt, type)
-     char *result, *type;
+     char *result;
+     char *type;
      int size;
-     time_t ttl, lmt;
+     time_t ttl;
+     time_t lmt;
 {
     time_t expiretime;
     time_t t;
     static char date[100];
-    static char expire[100];
-    static char last_modified_time[100];
+    static char expires[100];
+    static char last_modified[100];
+    static char content_length[100];
 
     if (result == NULL)
        return 1;
-
     t = squid_curtime;
-    expiretime = t + ttl;
-
-    date[0] = expire[0] = last_modified_time[0] = result[0] = '\0';
-    strncpy(date, mkrfc850(&t), 100);
-    strncpy(expire, mkrfc850(&expiretime), 100);
-    strncpy(last_modified_time, mkrfc850(&lmt), 100);
-
-    sprintf(result, "Content-Type: %s\r\nContent-Size: %d\r\nDate: %s\r\nExpires: %s\r\nLast-Modified-Time: %s\r\n", type, size, date, expire, last_modified_time);
+    expiretime = ttl ? t + ttl : 0;
+    date[0] = expires[0] = last_modified[0] = '\0';
+    content_length[0] = result[0] = '\0';
+    sprintf(date, "Date: %s\r\n", mkrfc850(&t));
+    if (ttl >= 0)
+       sprintf(expires, "Expires: %s\r\n", mkrfc850(&expiretime));
+    if (lmt)
+       sprintf(last_modified, "Last-Modified: %s\r\n", mkrfc850(&lmt));
+    if (size > 0)
+       sprintf(content_length, "Content-Length: %d\r\n", size);
+    sprintf(result, "Server: %s/%s\r\n%s%s%sContent-Type: %s\r\n%s",
+       appname,
+       version_string,
+       date,
+       expires,
+       last_modified,
+       type,
+       content_length);
     return 0;
 }
index 97824417ea965947c9e37298e9519fcbb63e6fea..73074b61fd9476bede0fd9a1b0cd18279b6c5b7f 100644 (file)
-/* $Id: neighbors.cc,v 1.23 1996/05/01 22:36:35 wessels Exp $ */
-
-/* TODO:
- * - change 'neighbor' to 'sibling'
- * - change 'edge' to neighbor?
- * - make ->flags structure
- * - fix "can't continue" if DNS lookup for neighbor fails.
+/*
+ * $Id: neighbors.cc,v 1.24 1996/07/09 03:41:33 wessels Exp $
+ *
+ * DEBUG: section 15    Neighbor Routines
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
 
 /*
- * DEBUG: Section 15          neighbors:
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
-static neighbors *friends = NULL;
+static int edgeWouldBePinged _PARAMS((edge *, request_t *));
+static void neighborRemove _PARAMS((edge *));
 
+static neighbors *friends = NULL;
 static struct neighbor_cf *Neighbor_cf = NULL;
-
 static icp_common_t echo_hdr;
-static short echo_port;
+static u_short echo_port;
+static struct in_addr any_addr;
+
 FILE *cache_hierarchy_log = NULL;
 
-static char *hier_strings[] =
+char *hier_strings[] =
 {
     "NONE",
     "DIRECT",
     "NEIGHBOR_HIT",
     "PARENT_HIT",
     "SINGLE_PARENT",
+    "FIRST_UP_PARENT",
     "NO_PARENT_DIRECT",
     "FIRST_PARENT_MISS",
     "LOCAL_IP_DIRECT",
+    "FIREWALL_IP_DIRECT",
     "DEAD_PARENT",
     "DEAD_NEIGHBOR",
     "REVIVE_PARENT",
     "REVIVE_NEIGHBOR",
     "NO_DIRECT_FAIL",
     "SOURCE_FASTEST",
+    "UDP_HIT_OBJ",
     "INVALID CODE"
 };
 
@@ -46,7 +144,7 @@ edge *whichEdge(header, from)
      struct sockaddr_in *from;
 {
     int j;
-    int port;
+    u_short port;
     struct in_addr ip;
     edge *e = NULL;
 
@@ -57,7 +155,7 @@ edge *whichEdge(header, from)
 
     for (e = friends->edges_head; e; e = e->next) {
        for (j = 0; j < e->n_addresses; j++) {
-           if (ip.s_addr == e->addresses[j].s_addr && port == e->udp_port) {
+           if (ip.s_addr == e->addresses[j].s_addr && port == e->icp_port) {
                return e;
            }
        }
@@ -124,36 +222,38 @@ void hierarchy_log_append(url, code, timeout, cache_host)
        fflush(cache_hierarchy_log);
 }
 
-static int edgeWouldBePinged(e, host)
+static int edgeWouldBePinged(e, request)
      edge *e;
-     char *host;
+     request_t *request;
 {
-    int offset;
     dom_list *d = NULL;
     int do_ping = 1;
+    struct _acl_list *a = NULL;
 
-    if (e->domains == NULL)
+    if (e->domains == NULL && e->acls == NULL)
        return do_ping;
-
     do_ping = 0;
     for (d = e->domains; d; d = d->next) {
-       if ((offset = strlen(host) - strlen(d->domain)) < 0) {
-           do_ping = !d->do_ping;
-           continue;
-       }
-       if (strcasecmp(d->domain, host + offset) == 0) {
-           /* found a match, no need to check any more domains */
-           do_ping = d->do_ping;
-           break;
-       } else {
-           do_ping = !d->do_ping;
-       }
+       if (matchDomainName(d->domain, request->host))
+           return d->do_ping;
+       do_ping = !d->do_ping;
+    }
+    for (a = e->acls; a; a = a->next) {
+       if (aclMatchAcl(a->acl,
+               any_addr,       /* bogus */
+               request->method,
+               request->protocol,
+               request->host,
+               request->port,
+               request->urlpath))
+           return a->op;
+       do_ping = !a->op;
     }
     return do_ping;
 }
 
-edge *getSingleParent(host, n)
-     char *host;
+edge *getSingleParent(request, n)
+     request_t *request;
      int *n;
 {
     edge *p = NULL;
@@ -163,7 +263,7 @@ edge *getSingleParent(host, n)
     if (n == NULL && friends->n_parent < 1)
        return NULL;
     for (e = friends->edges_head; e; e = e->next) {
-       if (edgeWouldBePinged(e, host)) {
+       if (edgeWouldBePinged(e, request)) {
            count++;
            if (e->type != EDGE_PARENT) {
                /* we matched a neighbor, not a parent.  There
@@ -191,16 +291,18 @@ edge *getSingleParent(host, n)
     return NULL;
 }
 
-edge *getFirstParent(host)
-     char *host;
+edge *getFirstUpParent(request)
+     request_t *request;
 {
     edge *e = NULL;
     if (friends->n_parent < 1)
        return NULL;
     for (e = friends->edges_head; e; e = e->next) {
+       if (!e->neighbor_up)
+           continue;
        if (e->type != EDGE_PARENT)
            continue;
-       if (edgeWouldBePinged(e, host))
+       if (edgeWouldBePinged(e, request))
            return e;
     }
     return NULL;
@@ -216,6 +318,25 @@ edge *getFirstEdge()
     return friends->edges_head;
 }
 
+void neighborRemove(target)
+     edge *target;
+{
+    edge *e = NULL;
+    edge **E = NULL;
+    e = friends->edges_head;
+    E = &friends->edges_head;
+    while (e) {
+       if (target == e)
+           break;
+       E = &e->next;
+       e = e->next;
+    }
+    if (e) {
+       *E = e->next;
+       safe_free(e);
+    }
+}
+
 void neighborsDestroy()
 {
     edge *e = NULL;
@@ -226,6 +347,7 @@ void neighborsDestroy()
     for (e = friends->edges_head; e; e = next) {
        next = e->next;
        safe_free(e->host);
+       /* XXX I think we need to free e->domains too -DW */
        safe_free(e);
     }
     safe_free(friends);
@@ -260,84 +382,96 @@ void neighbors_open(fd)
      int fd;
 {
     int j;
-    struct sockaddr_in our_socket_name;
+    struct sockaddr_in name;
     struct sockaddr_in *ap;
-    int sock_name_length = sizeof(our_socket_name);
+    int len = sizeof(struct sockaddr_in);
     char **list = NULL;
     edge *e = NULL;
+    edge *next = NULL;
+    edge **E = NULL;
     struct in_addr *ina = NULL;
+    struct servent *sep = NULL;
 
-    if (getsockname(fd, (struct sockaddr *) &our_socket_name,
-           &sock_name_length) == -1) {
-       debug(15, 1, "getsockname(%d,%p,%p) failed.\n",
-           fd, &our_socket_name, &sock_name_length);
-    }
+    memset(&name, '\0', sizeof(struct sockaddr_in));
+    if (getsockname(fd, (struct sockaddr *) &name, &len) < 0)
+       debug(15, 1, "getsockname(%d,%p,%p) failed.\n", fd, &name, &len);
     friends->fd = fd;
 
     /* Prepare neighbor connections, one at a time */
-    for (e = friends->edges_head; e; e = e->next) {
+    E = &friends->edges_head;
+    next = friends->edges_head;
+    while ((e = next)) {
+       next = e->next;
        debug(15, 2, "Finding IP addresses for '%s'\n", e->host);
        if ((list = getAddressList(e->host)) == NULL) {
-           sprintf(tmp_error_buf, "DNS lookup for '%s' failed! Cannot continue.\n",
-               e->host);
-           fatal(tmp_error_buf);
+           debug(0, 0, "WARNING!!: DNS lookup for '%s' failed!\n", e->host);
+           debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
+           *E = next;          /* skip */
+           safe_free(e);
+           continue;
        }
+       ipcacheLockEntry(e->host);
        e->n_addresses = 0;
        for (j = 0; *list && j < EDGE_MAX_ADDRESSES; j++) {
            ina = &e->addresses[j];
-           memcpy(&(ina->s_addr), *list, 4);
+           xmemcpy(&(ina->s_addr), *list, 4);
            list++;
            e->n_addresses++;
        }
        if (e->n_addresses < 1) {
-           sprintf(tmp_error_buf, "No IP addresses found for '%s'; Cannot continue.\n", e->host);
-           fatal(tmp_error_buf);
+           debug(0, 0, "WARNING!!: No IP address found for '%s'!\n", e->host);
+           debug(0, 0, "THIS NEIGHBOR WILL BE IGNORED.\n");
+           *E = next;          /* skip */
+           safe_free(e);
+           continue;
        }
        for (j = 0; j < e->n_addresses; j++) {
-           debug(15, 2, "--> IP address #%d: %s\n", j, inet_ntoa(e->addresses[j]));
+           debug(15, 2, "--> IP address #%d: %s\n",
+               j, inet_ntoa(e->addresses[j]));
        }
-       e->rtt = 1000;
+       e->stats.rtt = 0;
 
        /* Prepare query packet for future use */
        e->header.opcode = ICP_OP_QUERY;
        e->header.version = ICP_VERSION_CURRENT;
        e->header.length = 0;
        e->header.reqnum = 0;
-       memset(e->header.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE);
-       e->header.shostid = our_socket_name.sin_addr.s_addr;
+       e->header.flags = 0;
+       e->header.pad = 0;
+       /* memset(e->header.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE); */
+       e->header.shostid = name.sin_addr.s_addr;
 
        ap = &e->in_addr;
        memset(ap, '\0', sizeof(struct sockaddr_in));
        ap->sin_family = AF_INET;
        ap->sin_addr = e->addresses[0];
-       ap->sin_port = htons(e->udp_port);
+       ap->sin_port = htons(e->icp_port);
 
        if (e->type == EDGE_PARENT) {
            debug(15, 3, "parent_install: host %s addr %s port %d\n",
                e->host, inet_ntoa(ap->sin_addr),
-               e->udp_port);
+               e->icp_port);
            e->neighbor_up = 1;
        } else {
            debug(15, 3, "neighbor_install: host %s addr %s port %d\n",
                e->host, inet_ntoa(ap->sin_addr),
-               e->udp_port);
+               e->icp_port);
            e->neighbor_up = 1;
        }
+       E = &e->next;
+    }
 
-       /* do this only the first time thru */
-       if (0 == echo_hdr.opcode) {
-           struct servent *sep;
-
-           echo_hdr.opcode = ICP_OP_SECHO;
-           echo_hdr.version = ICP_VERSION_CURRENT;
-           echo_hdr.length = 0;
-           echo_hdr.reqnum = 0;
-           memset(echo_hdr.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE);
-           echo_hdr.shostid = our_socket_name.sin_addr.s_addr;
-
-           sep = getservbyname("echo", "udp");
-           echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
-       }
+    if (0 == echo_hdr.opcode) {
+       echo_hdr.opcode = ICP_OP_SECHO;
+       echo_hdr.version = ICP_VERSION_CURRENT;
+       echo_hdr.length = 0;
+       echo_hdr.reqnum = 0;
+       echo_hdr.flags = 0;
+       echo_hdr.pad = 0;
+       /* memset(echo_hdr.auth, '\0', sizeof(u_num32) * ICP_AUTH_SIZE); */
+       echo_hdr.shostid = name.sin_addr.s_addr;
+       sep = getservbyname("echo", "udp");
+       echo_port = sep ? ntohs((u_short) sep->s_port) : 7;
     }
 }
 
@@ -353,13 +487,13 @@ int neighborsUdpPing(proto)
     struct sockaddr_in to_addr;
     edge *e = NULL;
     int i;
-    MemObject *m = entry->mem_obj;
+    MemObject *mem = entry->mem_obj;
 
-    m->e_pings_n_pings = 0;
-    m->e_pings_n_acks = 0;
-    m->e_pings_first_miss = NULL;
-    m->w_rtt = 0;
-    m->start_ping = current_time;
+    mem->e_pings_n_pings = 0;
+    mem->e_pings_n_acks = 0;
+    mem->e_pings_first_miss = NULL;
+    mem->w_rtt = 0;
+    mem->start_ping = current_time;
 
     if (friends->edges_head == (edge *) NULL)
        return 0;
@@ -371,16 +505,17 @@ int neighborsUdpPing(proto)
 
        /* Don't resolve refreshes through neighbors because we don't resolve
         * misses through neighbors */
-       if ((e->type == EDGE_SIBLING) && (entry->flag & REFRESH_REQUEST))
+       if (e->type == EDGE_SIBLING && entry->flag & REFRESH_REQUEST)
            continue;
 
-       /* skip dumb caches where we failed to connect() w/in the last 60s */
-       if (e->udp_port == echo_port &&
-           (squid_curtime - e->last_fail_time < 60))
+       /* skip any cache where we failed to connect() w/in the last 60s */
+       if (squid_curtime - e->last_fail_time < 60)
            continue;
 
-       if (!edgeWouldBePinged(e, host))
+       if (!edgeWouldBePinged(e, proto->request))
            continue;           /* next edge */
+       if (e->options & NEIGHBOR_NO_QUERY)
+           continue;
 
        debug(15, 4, "neighborsUdpPing: pinging cache %s for <URL:%s>\n",
            e->host, url);
@@ -393,32 +528,31 @@ int neighborsUdpPing(proto)
        debug(15, 3, "neighborsUdpPing: key = '%s'\n", entry->key);
        debug(15, 3, "neighborsUdpPing: reqnum = %d\n", e->header.reqnum);
 
-       if (e->udp_port == echo_port) {
+       if (e->icp_port == echo_port) {
            debug(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping\n");
-           icpUdpSend(friends->fd, url, &echo_hdr, &e->in_addr, ICP_OP_DECHO);
+           icpUdpSend(friends->fd, url, &echo_hdr, &e->in_addr, ICP_OP_DECHO, LOG_TAG_NONE);
        } else {
-           icpUdpSend(friends->fd, url, &e->header, &e->in_addr, ICP_OP_QUERY);
+           icpUdpSend(friends->fd, url, &e->header, &e->in_addr, ICP_OP_QUERY, LOG_TAG_NONE);
        }
 
-       e->ack_deficit++;
-       e->num_pings++;
-       e->pings_sent++;
+       e->stats.ack_deficit++;
+       e->stats.pings_sent++;
 
-       if (e->ack_deficit < HIER_MAX_DEFICIT) {
+       if (e->stats.ack_deficit < HIER_MAX_DEFICIT) {
            /* consider it's alive. count it */
            e->neighbor_up = 1;
-           m->e_pings_n_pings++;
+           mem->e_pings_n_pings++;
        } else {
            /* consider it's dead. send a ping but don't count it. */
            e->neighbor_up = 0;
-           if (e->ack_deficit > (HIER_MAX_DEFICIT << 1))
+           if (e->stats.ack_deficit > (HIER_MAX_DEFICIT << 1))
                /* do this to prevent wrap around but we still want it
                 * to move a bit so we can debug it easier. */
-               e->ack_deficit = HIER_MAX_DEFICIT + 1;
+               e->stats.ack_deficit = HIER_MAX_DEFICIT + 1;
            debug(15, 6, "cache %s is considered dead but send PING anyway, hope it comes up soon.\n",
                inet_ntoa(e->in_addr.sin_addr));
            /* log it once at the threshold */
-           if ((e->ack_deficit == HIER_MAX_DEFICIT)) {
+           if ((e->stats.ack_deficit == HIER_MAX_DEFICIT)) {
                if (e->type == EDGE_SIBLING) {
                    hierarchy_log_append("Detect: ",
                        HIER_DEAD_NEIGHBOR, 0,
@@ -435,23 +569,23 @@ int neighborsUdpPing(proto)
 
     /* only do source_ping if we have neighbors */
     if (echo_hdr.opcode) {
-       if (proto->source_ping && (hep = ipcache_gethostbyname(host))) {
+       if (proto->source_ping && (hep = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP))) {
            debug(15, 6, "neighborsUdpPing: Send to original host\n");
            debug(15, 6, "neighborsUdpPing: url=%s, host=%s, t=%d\n",
                url, host, t);
            to_addr.sin_family = AF_INET;
-           memcpy(&to_addr.sin_addr, hep->h_addr, hep->h_length);
-           to_addr.sin_port = echo_port;
+           xmemcpy(&to_addr.sin_addr, hep->h_addr, hep->h_length);
+           to_addr.sin_port = htons(echo_port);
            echo_hdr.reqnum = squid_curtime;
            debug(15, 6, "neighborsUdpPing - url: %s to url-host %s \n",
                url, inet_ntoa(to_addr.sin_addr));
            /* send to original site */
-           icpUdpSend(friends->fd, url, &echo_hdr, &to_addr, ICP_OP_SECHO);
+           icpUdpSend(friends->fd, url, &echo_hdr, &to_addr, ICP_OP_SECHO, LOG_TAG_NONE);
        } else {
            debug(15, 6, "neighborsUdpPing: Source Ping is disabled.\n");
        }
     }
-    return (m->e_pings_n_pings);
+    return (mem->e_pings_n_pings);
 }
 
 
@@ -461,16 +595,21 @@ int neighborsUdpPing(proto)
  * 
  * If a hit process is already started, then sobeit
  */
-void neighborsUdpAck(fd, url, header, from, entry)
+void neighborsUdpAck(fd, url, header, from, entry, data, data_sz)
      int fd;
      char *url;
      icp_common_t *header;
      struct sockaddr_in *from;
      StoreEntry *entry;
+     char *data;
+     int data_sz;
 {
     edge *e = NULL;
-    MemObject *m = entry->mem_obj;
+    MemObject *mem = entry->mem_obj;
     int w_rtt;
+    int rtt;
+    int n;
+    HttpStateData *httpState = NULL;
 
     debug(15, 6, "neighborsUdpAck: url=%s (%d chars), header=0x%x, from=0x%x, ent=0x%x\n",
        url, strlen(url), header, from, entry);
@@ -488,7 +627,7 @@ void neighborsUdpAck(fd, url, header, from, entry)
     if (e) {
        /* reset the deficit. It's alive now. */
        /* Don't care about exact count. */
-       if ((e->ack_deficit >= HIER_MAX_DEFICIT)) {
+       if ((e->stats.ack_deficit >= HIER_MAX_DEFICIT)) {
            if (e->type == EDGE_SIBLING) {
                hierarchy_log_append("Detect: ",
                    HIER_REVIVE_NEIGHBOR, 0, e->host);
@@ -497,13 +636,21 @@ void neighborsUdpAck(fd, url, header, from, entry)
                    HIER_REVIVE_PARENT, 0, e->host);
            }
        }
-       e->ack_deficit = 0;
        e->neighbor_up = 1;
-       e->pings_acked++;
+       e->stats.ack_deficit = 0;
+       n = ++e->stats.pings_acked;
+       if (header->opcode < ICP_OP_END)
+           e->stats.counts[header->opcode]++;
+       if (mem) {
+           if (n > RTT_AV_FACTOR)
+               n = RTT_AV_FACTOR;
+           rtt = tvSubMsec(mem->start_ping, current_time);
+           e->stats.rtt = (e->stats.rtt * (n - 1) + rtt) / n;
+       }
     }
     /* check if someone is already fetching it */
-    if (BIT_TEST(entry->flag, ENTRY_DISPATCHED) || (entry->ping_status != WAITING)) {
-       if (entry->ping_status == DONE) {
+    if (BIT_TEST(entry->flag, ENTRY_DISPATCHED) || (entry->ping_status != PING_WAITING)) {
+       if (entry->ping_status == PING_DONE) {
            debug(15, 5, "There is already a cache/source dispatched for this object\n");
            debug(15, 5, "--> <URL:%s>\n", entry->url);
            debug(15, 5, "--> entry->flag & ENTRY_DISPATCHED = %d\n",
@@ -535,36 +682,60 @@ void neighborsUdpAck(fd, url, header, from, entry)
                HIER_SOURCE_FASTEST,
                0,
                inet_ntoa(from->sin_addr));
+           if (mem)
+               mem->hierarchy_code = HIER_SOURCE_FASTEST;
            BIT_SET(entry->flag, ENTRY_DISPATCHED);
-           entry->ping_status = DONE;
+           entry->ping_status = PING_DONE;
            getFromCache(0, entry, NULL, entry->mem_obj->request);
        }
        return;
-    }
-    if (header->opcode == ICP_OP_HIT) {
+    } else if (header->opcode == ICP_OP_HIT_OBJ) {
+       if (entry->object_len != 0) {
+           debug(15, 0, "Too late UDP_HIT_OBJ '%s'?\n", entry->url);
+           return;
+       }
+       protoCancelTimeout(0, entry);
+       entry->ping_status = PING_DONE;
+       httpState = xcalloc(1, sizeof(HttpStateData));
+       httpState->entry = entry;
+       httpProcessReplyHeader(httpState, data, data_sz);
+       storeAppend(entry, data, data_sz);
+       storeComplete(entry);
+       hierarchy_log_append(entry->url,
+           HIER_UDP_HIT_OBJ,
+           0,
+           e ? e->host : inet_ntoa(from->sin_addr));
+       if (mem)
+           mem->hierarchy_code = HIER_UDP_HIT_OBJ;
+       if (httpState->reply_hdr)
+           put_free_8k_page(httpState->reply_hdr);
+       safe_free(httpState);
+       return;
+    } else if (header->opcode == ICP_OP_HIT) {
        /* If an edge is not found, count it as a MISS message. */
        if (!e) {
            /* count it as a MISS message */
-           m->e_pings_n_acks++;
+           mem->e_pings_n_acks++;
            return;
        }
        /* GOT a HIT here */
        debug(15, 6, "HIT: Getting %s from host: %s\n", entry->url, e->host);
        if (e->type == EDGE_SIBLING) {
            hierarchy_log_append(entry->url, HIER_NEIGHBOR_HIT, 0, e->host);
+           if (mem)
+               mem->hierarchy_code = HIER_NEIGHBOR_HIT;
        } else {
            hierarchy_log_append(entry->url, HIER_PARENT_HIT, 0, e->host);
+           if (mem)
+               mem->hierarchy_code = HIER_PARENT_HIT;
        }
        BIT_SET(entry->flag, ENTRY_DISPATCHED);
-       entry->ping_status = DONE;
+       entry->ping_status = PING_DONE;
        getFromCache(0, entry, e, entry->mem_obj->request);
-       e->hits++;
        return;
     } else if ((header->opcode == ICP_OP_MISS) || (header->opcode == ICP_OP_DECHO)) {
        /* everytime we get here, count it as a miss */
-       m->e_pings_n_acks++;
-       if (e)
-           e->misses++;
+       mem->e_pings_n_acks++;
 
        if (header->opcode == ICP_OP_DECHO) {
            /* receive ping back from non-ICP cache */
@@ -574,11 +745,11 @@ void neighborsUdpAck(fd, url, header, from, entry)
                    inet_ntoa(e->in_addr.sin_addr));
 
                if (e->type == EDGE_PARENT) {
-                   w_rtt = tvSubMsec(m->start_ping, current_time) / e->weight;
-                   if (m->w_rtt == 0 || w_rtt < m->w_rtt) {
+                   w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
+                   if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
                        debug(15, 6, "Dumb-cache has minimum weighted RTT = %d\n", w_rtt);
-                       m->e_pings_first_miss = e;
-                       m->w_rtt = w_rtt;
+                       mem->e_pings_first_miss = e;
+                       mem->w_rtt = w_rtt;
                    }
                } else {
                    debug(15, 6, "Dumb Cached as a neighbor does not make sense.\n");
@@ -592,43 +763,52 @@ void neighborsUdpAck(fd, url, header, from, entry)
 
        } else if (e && e->type == EDGE_PARENT) {
            /* ICP_OP_MISS from a cache */
-           w_rtt = tvSubMsec(m->start_ping, current_time) / e->weight;
-           if (m->w_rtt == 0 || w_rtt < m->w_rtt) {
-               m->e_pings_first_miss = e;
-               m->w_rtt = w_rtt;
+           w_rtt = tvSubMsec(mem->start_ping, current_time) / e->weight;
+           if (mem->w_rtt == 0 || w_rtt < mem->w_rtt) {
+               mem->e_pings_first_miss = e;
+               mem->w_rtt = w_rtt;
            }
        }
-       if (m->e_pings_n_acks == m->e_pings_n_pings) {
+       if (mem->e_pings_n_acks == mem->e_pings_n_pings) {
            BIT_SET(entry->flag, ENTRY_DISPATCHED);
-           entry->ping_status = DONE;
+           entry->ping_status = PING_DONE;
            debug(15, 6, "Receive MISSes from all neighbors and parents\n");
            /* pass in fd=0 here so getFromCache() looks up the real FD
             * and resets the timeout handler */
            getFromDefaultSource(0, entry);
            return;
        }
+    } else if (header->opcode == ICP_OP_DENIED) {
+       debug(15, 5, "neighborsUdpAck: Access denied for '%s'\n", entry->url);
+       if (e && e->stats.pings_acked > 100) {
+           if (100 * e->stats.counts[ICP_OP_DENIED] / e->stats.pings_acked > 95) {
+               debug(15, 0, "95%% of replies from '%s' are UDP_DENIED\n", e->host);
+               debug(15, 0, "Disabling '%s', please check your configuration.\n", e->host);
+               neighborRemove(e);
+           }
+       }
     } else {
        debug(15, 0, "neighborsUdpAck: WHY ARE WE HERE?  header->opcode = %d\n",
            header->opcode);
     }
 }
 
-void neighbors_cf_add(host, type, ascii_port, udp_port, proxy_only, weight)
+void neighbors_cf_add(host, type, http_port, icp_port, options, weight)
      char *host;
      char *type;
-     int ascii_port;
-     int udp_port;
-     int proxy_only;
+     int http_port;
+     int icp_port;
+     int options;
      int weight;
 {
     struct neighbor_cf *t, *u;
 
-    t = (struct neighbor_cf *) xcalloc(sizeof(struct neighbor_cf), 1);
+    t = xcalloc(1, sizeof(struct neighbor_cf));
     t->host = xstrdup(host);
     t->type = xstrdup(type);
-    t->ascii_port = ascii_port;
-    t->udp_port = udp_port;
-    t->proxy_only = proxy_only;
+    t->http_port = http_port;
+    t->icp_port = icp_port;
+    t->options = options;
     t->weight = weight;
     t->next = (struct neighbor_cf *) NULL;
 
@@ -640,23 +820,24 @@ void neighbors_cf_add(host, type, ascii_port, udp_port, proxy_only, weight)
     }
 }
 
-int neighbors_cf_domain(host, domain)
+void neighbors_cf_domain(host, domain)
      char *host;
      char *domain;
 {
-    struct neighbor_cf *t;
-    dom_list *l;
-    dom_list **L;
+    struct neighbor_cf *t = NULL;
+    dom_list *l = NULL;
+    dom_list **L = NULL;
 
     for (t = Neighbor_cf; t; t = t->next) {
        if (strcmp(t->host, host) == 0)
            break;
     }
-
-    if (t == NULL)
-       return 0;
-
-    l = (dom_list *) xmalloc(sizeof(dom_list));
+    if (t == NULL) {
+       debug(15, 0, "%s, line %d: No cache_host '%s'\n",
+           cfg_filename, config_lineno, host);
+       return;
+    }
+    l = xmalloc(sizeof(dom_list));
     l->do_ping = 1;
     if (*domain == '!') {      /* check for !.edu */
        l->do_ping = 0;
@@ -666,8 +847,51 @@ int neighbors_cf_domain(host, domain)
     l->next = NULL;
     for (L = &(t->domains); *L; L = &((*L)->next));
     *L = l;
+}
+
+void neighbors_cf_acl(host, aclname)
+     char *host;
+     char *aclname;
+{
+    struct neighbor_cf *t = NULL;
+    struct _acl_list *L = NULL;
+    struct _acl_list **Tail = NULL;
+    struct _acl *a = NULL;
 
-    return 1;
+    for (t = Neighbor_cf; t; t = t->next) {
+       if (strcmp(t->host, host) == 0)
+           break;
+    }
+    if (t == NULL) {
+       debug(15, 0, "%s, line %d: No cache_host '%s'\n",
+           cfg_filename, config_lineno, host);
+       return;
+    }
+    L = xcalloc(1, sizeof(struct _acl_list));
+    L->op = 1;
+    if (*aclname == '!') {
+       L->op = 0;
+       aclname++;
+    }
+    debug(15, 3, "neighbors_cf_acl: looking for ACL name '%s'\n", aclname);
+    a = aclFindByName(aclname);
+    if (a == NULL) {
+       debug(15, 0, "%s line %d: %s\n",
+           cfg_filename, config_lineno, config_input_line);
+       debug(15, 0, "neighbors_cf_acl: ACL name '%s' not found.\n", aclname);
+       xfree(L);
+       return;
+    }
+    if (a->type == ACL_SRC_IP) {
+       debug(15, 0, "%s line %d: %s\n",
+           cfg_filename, config_lineno, config_input_line);
+       debug(15, 0, "neighbors_cf_acl: 'src' ALC's not supported for 'cache_host_acl'\n");
+       xfree(L);
+       return;
+    }
+    L->acl = a;
+    for (Tail = &(t->acls); *Tail; Tail = &((*Tail)->next));
+    *Tail = L;
 }
 
 void neighbors_init()
@@ -681,27 +905,29 @@ void neighbors_init()
     debug(15, 1, "neighbors_init: Initializing Neighbors...\n");
 
     if (friends == NULL)
-       friends = (neighbors *) xcalloc(1, sizeof(neighbors));
+       friends = xcalloc(1, sizeof(neighbors));
 
     if ((fname = getHierarchyLogFile()))
        neighborsOpenLog(fname);
 
     for (t = Neighbor_cf; t; t = next) {
        next = t->next;
-       if (!strcmp(t->host, me) && t->ascii_port == getAsciiPortNum()) {
+       if (!strcmp(t->host, me) && t->http_port == getHttpPortNum()) {
            debug(15, 0, "neighbors_init: skipping cache_host %s %s %d %d\n",
-               t->type, t->host, t->ascii_port, t->udp_port);
+               t->type, t->host, t->http_port, t->icp_port);
            continue;
        }
-       debug(15, 1, "Adding a %s: %s\n", t->type, t->host);
+       debug(15, 1, "Adding a %s: %s/%d/%d\n",
+           t->type, t->host, t->http_port, t->icp_port);
 
-       e = (edge *) xcalloc(1, sizeof(edge));
-       e->ascii_port = t->ascii_port;
-       e->udp_port = t->udp_port;
-       e->proxy_only = t->proxy_only;
+       e = xcalloc(1, sizeof(edge));
+       e->http_port = t->http_port;
+       e->icp_port = t->icp_port;
+       e->options = t->options;
        e->weight = t->weight;
        e->host = t->host;
        e->domains = t->domains;
+       e->acls = t->acls;
        e->neighbor_up = 1;
        if (!strcmp(t->type, "parent")) {
            friends->n_parent++;
@@ -710,6 +936,7 @@ void neighbors_init()
            friends->n_neighbor++;
            e->type = EDGE_SIBLING;
        }
+       safe_free(t->type);
 
        /* Append edge */
        if (!friends->edges_head)
@@ -722,6 +949,7 @@ void neighbors_init()
        safe_free(t);
     }
     Neighbor_cf = NULL;
+    any_addr.s_addr = inet_addr("0.0.0.0");
 }
 
 void neighbors_rotate_log()
index 879ef13656fcda5000aa5881842ce1ff7e4f674e..8e3357cc81e5ff1ac6b41c750c38b3f2bc68be03 100644 (file)
@@ -1,4 +1,107 @@
-/* $Id: recv-announce.cc,v 1.4 1996/04/16 16:35:29 wessels Exp $ */
+/*
+ * $Id: recv-announce.cc,v 1.5 1996/07/09 03:41:36 wessels Exp $
+ *
+ * DEBUG: section 0     Announement Server
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
+ */
 
 #include <stdio.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
 #include <netdb.h>
+#include <unistd.h>
+#include <signal.h>
 
 #define RECV_BUF_SIZE 8192
 
@@ -51,7 +157,6 @@ int main(argc, argv)
     int len;
     struct hostent *hp = NULL;
     char logfile[BUFSIZ];
-    char *t = NULL;
     char ip[4];
 
     for (len = 0; len < 32; len++) {
@@ -81,7 +186,7 @@ int main(argc, argv)
            perror("recv");
            exit(2);
        }
-       memcpy(ip, &R.sin_addr.s_addr, 4);
+       xmemcpy(ip, &R.sin_addr.s_addr, 4);
        hp = gethostbyaddr(ip, 4, AF_INET);
        printf("==============================================================================\n");
        printf("Received from %s [%s]\n",
@@ -90,4 +195,5 @@ int main(argc, argv)
        fputs(buf, stdout);
        fflush(stdout);
     }
+    return 0;
 }
diff --git a/src/redirect.cc b/src/redirect.cc
new file mode 100644 (file)
index 0000000..8e10056
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * $Id: redirect.cc,v 1.2 1996/07/09 03:41:37 wessels Exp $
+ *
+ * DEBUG: section 29    Redirector
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
+
+#include "squid.h"
+
+#define REDIRECT_FLAG_ALIVE            0x01
+#define REDIRECT_FLAG_BUSY             0x02
+#define REDIRECT_FLAG_CLOSING  0x04
+
+typedef void (*RH) _PARAMS((int, char *));
+
+
+typedef struct {
+    int fd;
+    char *orig_url;
+    RH handler;
+} redirectStateData;
+
+typedef struct _redirector {
+    int index;
+    int flags;
+    int fd;
+    char *inbuf;
+    unsigned int size;
+    unsigned int offset;
+    redirectStateData *redirectState;
+} redirector_t;
+
+struct redirectQueueData {
+    struct redirectQueueData *next;
+    redirectStateData *redirectState;
+};
+
+static redirector_t *GetFirstAvailable _PARAMS((void));
+static int redirectCreateRedirector _PARAMS((char *command));
+static int redirectHandleRead _PARAMS((int, redirector_t *));
+static redirectStateData *Dequeue _PARAMS(());
+static void Enqueue _PARAMS((redirectStateData *));
+static void redirectDispatch _PARAMS((redirector_t *, redirectStateData *));
+
+
+static redirector_t **redirect_child_table = NULL;
+static int NRedirectors = 0;
+static struct redirectQueueData *redirectQueueHead = NULL;
+static struct redirectQueueData **redirectQueueTailP = &redirectQueueHead;
+
+/* TCP SOCKET VERSION */
+int redirectCreateRedirector(command)
+     char *command;
+{
+    int pid;
+    u_short port;
+    struct sockaddr_in S;
+    static int n_redirector = 0;
+    int cfd;
+    int sfd;
+    int len;
+    int fd;
+    cfd = comm_open(COMM_NOCLOEXEC,
+       local_addr,
+       0,
+       "socket to redirector");
+    if (cfd == COMM_ERROR) {
+       debug(14, 0, "redirect_create_redirector: Failed to create redirector\n");
+       return -1;
+    }
+    len = sizeof(S);
+    memset(&S, '\0', len);
+    if (getsockname(cfd, (struct sockaddr *) &S, &len) < 0) {
+       debug(14, 0, "redirect_create_redirector: getsockname: %s\n", xstrerror());
+       comm_close(cfd);
+       return -1;
+    }
+    port = ntohs(S.sin_port);
+    debug(14, 4, "redirect_create_redirector: bind to local host.\n");
+    listen(cfd, 1);
+    if ((pid = fork()) < 0) {
+       debug(14, 0, "redirect_create_redirector: fork: %s\n", xstrerror());
+       comm_close(cfd);
+       return -1;
+    }
+    if (pid > 0) {             /* parent */
+       comm_close(cfd);        /* close shared socket with child */
+       /* open new socket for parent process */
+       sfd = comm_open(0, local_addr, 0, NULL);        /* blocking! */
+       if (sfd == COMM_ERROR)
+           return -1;
+       if (comm_connect(sfd, localhost, port) == COMM_ERROR) {
+           comm_close(sfd);
+           return -1;
+       }
+       comm_set_fd_lifetime(sfd, -1);
+       debug(14, 4, "redirect_create_redirector: FD %d connected to %s #%d.\n",
+           sfd, command, n_redirector);
+       return sfd;
+    }
+    /* child */
+    no_suid();                 /* give up extra priviliges */
+    dup2(cfd, 3);
+    for (fd = FD_SETSIZE; fd > 3; fd--)
+       close(fd);
+    execlp(command, "(redirector)", "-t", NULL);
+    debug(14, 0, "redirect_create_redirector: %s: %s\n", command, xstrerror());
+    _exit(1);
+    return 0;
+}
+
+
+
+int redirectHandleRead(fd, redirector)
+     int fd;
+     redirector_t *redirector;
+{
+    int len;
+    redirectStateData *r = redirector->redirectState;
+    char *t = NULL;
+
+    len = read(fd,
+       redirector->inbuf + redirector->offset,
+       redirector->size - redirector->offset);
+    debug(14, 5, "redirectHandleRead: Result from Redirector %d.\n",
+       redirector->index + 1);
+    if (len <= 0) {
+       debug(14, redirector->flags & REDIRECT_FLAG_CLOSING ? 5 : 1,
+           "FD %d: Connection from Redirector #%d is closed, disabling\n",
+           fd, redirector->index + 1);
+       redirector->flags = 0;
+       comm_close(fd);
+       return 0;
+    }
+    redirector->offset += len;
+    redirector->inbuf[redirector->offset] = '\0';
+    /* reschedule */
+    comm_set_select_handler(redirector->fd,
+       COMM_SELECT_READ,
+       (PF) redirectHandleRead,
+       redirector);
+    if ((t = strchr(redirector->inbuf, '\n'))) {
+       /* end of record found */
+       *t = '\0';
+       if (t == redirector->inbuf)
+           r->handler(r->fd, r->orig_url);
+       else
+           r->handler(r->fd, redirector->inbuf);
+       redirector->redirectState = NULL;
+       redirector->flags &= ~REDIRECT_FLAG_BUSY;
+    }
+    while ((r = Dequeue()) && (redirector = GetFirstAvailable()))
+       redirectDispatch(redirector, r);
+    return 0;
+}
+
+void redirectStart(url, fd, handler)
+     char *url;
+     int fd;
+     RH handler;
+{
+    redirectStateData *r = NULL;
+    redirector_t *redirector = NULL;
+
+    if (!handler)
+       fatal_dump("redirectStart: NULL handler");
+    r = xcalloc(1, sizeof(redirectStateData));
+    r->fd = fd;
+    r->orig_url = url;
+    r->handler = handler;
+    if ((redirector = GetFirstAvailable()))
+       redirectDispatch(redirector, r);
+    else
+       Enqueue(r);
+}
+
+static void Enqueue(r)
+     redirectStateData *r;
+{
+    struct redirectQueueData *new = xcalloc(1, sizeof(struct redirectQueueData));
+    new->redirectState = r;
+    *redirectQueueTailP = new;
+    redirectQueueTailP = &new->next;
+}
+
+static redirectStateData *Dequeue()
+{
+    struct redirectQueueData *old = NULL;
+    redirectStateData *r = NULL;
+    if (redirectQueueHead) {
+       r = redirectQueueHead->redirectState;
+       old = redirectQueueHead;
+       redirectQueueHead = redirectQueueHead->next;
+       if (redirectQueueHead == NULL)
+           redirectQueueTailP = &redirectQueueHead;
+       safe_free(old);
+    }
+    return r;
+}
+
+static redirector_t *GetFirstAvailable()
+{
+    int k;
+    redirector_t *redirect = NULL;
+    for (k = 0; k < NRedirectors; k++) {
+       redirect = *(redirect_child_table + k);
+       if (!(redirect->flags & REDIRECT_FLAG_BUSY))
+           return redirect;
+    }
+    return NULL;
+}
+
+
+static void redirectDispatch(redirect, r)
+     redirector_t *redirect;
+     redirectStateData *r;
+{
+    char *buf = NULL;
+    redirect->flags |= REDIRECT_FLAG_BUSY;
+    redirect->redirectState = r;
+    comm_write(redirect->fd,
+       xstrdup(buf),
+       strlen(buf),
+       0,                      /* timeout */
+       NULL,                   /* Handler */
+       NULL);                  /* Handler-data */
+    debug(14, 5, "redirectDispatch: Request sent to Redirector #%d.\n",
+       redirect->index + 1);
+}
+
+
+void redirectOpenServers()
+{
+    char *prg = getRedirectProgram();
+    int k;
+    int redirectsocket;
+    static char fd_note_buf[FD_ASCII_NOTE_SZ];
+
+    /* free old structures if present */
+    if (redirect_child_table) {
+       for (k = 0; k < NRedirectors; k++)
+           safe_free(redirect_child_table[k]);
+       safe_free(redirect_child_table);
+    }
+    NRedirectors = getRedirectChildren();
+    redirect_child_table = xcalloc(NRedirectors, sizeof(redirector_t *));
+    debug(14, 1, "redirectOpenServers: Starting %d '%s' processes\n",
+       NRedirectors, prg);
+    for (k = 0; k < NRedirectors; k++) {
+       redirect_child_table[k] = xcalloc(1, sizeof(redirector_t));
+       if ((redirectsocket = redirectCreateRedirector(prg)) < 0) {
+           debug(14, 1, "WARNING: Cannot run '%s' process.\n", prg);
+           redirect_child_table[k]->flags &= ~REDIRECT_FLAG_ALIVE;
+       } else {
+           redirect_child_table[k]->flags |= REDIRECT_FLAG_ALIVE;
+           redirect_child_table[k]->index = k;
+           redirect_child_table[k]->fd = redirectsocket;
+           sprintf(fd_note_buf, "%s #%d",
+               prg,
+               redirect_child_table[k]->index + 1);
+           fd_note(redirect_child_table[k]->fd, fd_note_buf);
+           commSetNonBlocking(redirect_child_table[k]->fd);
+
+           /* set handler for incoming result */
+           comm_set_select_handler(redirect_child_table[k]->fd,
+               COMM_SELECT_READ,
+               (PF) redirectHandleRead,
+               (void *) redirect_child_table[k]);
+           debug(14, 3, "redirectOpenServers: 'redirect_server' %d started\n",
+               k);
+       }
+    }
+}
+
+int redirectUnregister(url, fd)
+     char *url;
+     int fd;
+{
+    return 0;
+}
+
+void redirectShutdownServers()
+{
+    redirector_t *redirector = NULL;
+    int k;
+    static char *shutdown = "$shutdown\n";
+
+    debug(14, 3, "redirectShutdownServers:\n");
+
+    for (k = 0; k < getRedirectChildren(); k++) {
+       redirector = *(redirect_child_table + k);
+       debug(14, 3, "redirectShutdownServers: sending '$shutdown' to redirector #%d\n", k);
+       debug(14, 3, "redirectShutdownServers: --> FD %d\n", redirector->fd);
+       comm_write(redirector->fd,
+           xstrdup(shutdown),
+           strlen(shutdown),
+           0,                  /* timeout */
+           NULL,               /* Handler */
+           NULL);              /* Handler-data */
+       redirector->flags |= REDIRECT_FLAG_CLOSING;
+    }
+}
index 4b49f274144c45b3f11789f7d47ec05f7baf50b5..3a5ce5fb145414043d3ca587c34a7c9b0e215f45 100644 (file)
@@ -1,12 +1,35 @@
-/* $Id: send-announce.cc,v 1.11 1996/05/01 22:36:36 wessels Exp $ */
-
 /*
- * DEBUG: Section 27          send-announce
+ * $Id: send-announce.cc,v 1.12 1996/07/09 03:41:37 wessels Exp $
+ *
+ * DEBUG: section 27    Cache Announcer
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
 
 #include "squid.h"
 
-
 void send_announce()
 {
     static char tbuf[256];
@@ -15,7 +38,7 @@ void send_announce()
     struct hostent *hp = NULL;
     char *host = NULL;
     char *file = NULL;
-    int port;
+    u_short port;
     int fd;
     int l;
     int n;
@@ -23,7 +46,7 @@ void send_announce()
     host = getAnnounceHost();
     port = getAnnouncePort();
 
-    if ((hp = ipcache_gethostbyname(host)) == NULL) {
+    if ((hp = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP)) == NULL) {
        debug(27, 1, "send_announce: Unknown host '%s'\n", host);
        return;
     }
@@ -32,8 +55,8 @@ void send_announce()
     strcat(sndbuf, tbuf);
     sprintf(tbuf, "Running on %s %d %d\n",
        getMyHostname(),
-       getAsciiPortNum(),
-       getUdpPortNum());
+       getHttpPortNum(),
+       getIcpPortNum());
     strcat(sndbuf, tbuf);
     if (getAdminEmail()) {
        sprintf(tbuf, "cache_admin: %s\n", getAdminEmail());
@@ -54,14 +77,14 @@ void send_announce()
            debug(27, 1, "send_announce: %s: %s\n", file, xstrerror());
        }
     }
-    qdata = (icpUdpData *) xcalloc(1, sizeof(icpUdpData));
+    qdata = xcalloc(1, sizeof(icpUdpData));
     qdata->msg = xstrdup(sndbuf);
     qdata->len = strlen(sndbuf) + 1;
     qdata->address.sin_family = AF_INET;
     qdata->address.sin_port = htons(port);
-    memcpy(&qdata->address.sin_addr, hp->h_addr_list[0], hp->h_length);
+    xmemcpy(&qdata->address.sin_addr, hp->h_addr_list[0], hp->h_length);
     AppendUdp(qdata);
-    comm_set_select_handler(theUdpConnection,
+    comm_set_select_handler(theOutIcpConnection,
        COMM_SELECT_WRITE,
        (PF) icpUdpReply,
        (void *) qdata);
index d0ead64acf5c6784b79177c8845278b01469dd88..488c1c4dfbfabff0d8263905094c858a3bb132f4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: squid.h,v 1.22 1996/07/08 22:42:53 wessels Exp $
+ * $Id: squid.h,v 1.23 1996/07/09 03:41:39 wessels Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -253,6 +253,7 @@ extern char version_string[];       /* main.c */
 extern char appname[];         /* main.c */
 extern struct in_addr local_addr;      /* main.c */
 extern char localhost[];
+extern struct in_addr any_addr;        /* comm.c */
 
 
 /* Prototypes and definitions which don't really deserve a seaprate
index 8d29e277db19dfa888c128a1b921889ea8b82af6..e5e70f27b310893dd8a8c6f483eb07a732fe9e12 100644 (file)
@@ -1,11 +1,34 @@
 /*
- *  $Id: ssl.cc,v 1.2 1996/05/03 22:56:31 wessels Exp $ 
+ * $Id: ssl.cc,v 1.3 1996/07/09 03:41:39 wessels Exp $
  *
- * DEBUG: Section 26                    ssl
+ * DEBUG: section 26    Secure Sockets Layer Proxy
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
-#include "squid.h"
 
-#define SSL_BUFSIZ (1<<14)
+#include "squid.h"
 
 typedef struct {
     char *url;
@@ -30,7 +53,40 @@ static void sslReadClient _PARAMS((int fd, SslStateData * sslState));
 static void sslWriteServer _PARAMS((int fd, SslStateData * sslState));
 static void sslWriteClient _PARAMS((int fd, SslStateData * sslState));
 static void sslConnected _PARAMS((int fd, SslStateData * sslState));
+static int sslConnect _PARAMS((int fd, struct hostent *, SslStateData *));
 static void sslConnInProgress _PARAMS((int fd, SslStateData * sslState));
+static void sslErrorComplete _PARAMS((int, char *, int, int, void *));
+static void sslClose _PARAMS((SslStateData * sslState));
+static int sslClientClosed _PARAMS((int fd, SslStateData * sslState));
+
+static void sslClose(sslState)
+     SslStateData *sslState;
+{
+    if (sslState->client.fd > -1) {
+       /* remove the "unexpected" client close handler */
+       comm_remove_close_handler(sslState->client.fd,
+           (PF) sslClientClosed,
+           (void *) sslState);
+       comm_close(sslState->client.fd);
+       sslState->client.fd = -1;
+    }
+    if (sslState->server.fd > -1) {
+       comm_close(sslState->server.fd);
+    }
+}
+
+/* This is called only if the client connect closes unexpectedly,
+ * ie from icpDetectClientClose() */
+static int sslClientClosed(fd, sslState)
+     int fd;
+     SslStateData *sslState;
+{
+    debug(26, 3, "sslClientClosed: FD %d\n", fd);
+    /* we have been called from comm_close for the client side, so
+     * just need to clean up the server side */
+    comm_close(sslState->server.fd);
+    return 0;
+}
 
 static int sslStateFree(fd, sslState)
      int fd;
@@ -48,6 +104,7 @@ static int sslStateFree(fd, sslState)
     safe_free(sslState->server.buf);
     safe_free(sslState->client.buf);
     xfree(sslState->url);
+    requestUnlink(sslState->request);
     memset(sslState, '\0', sizeof(SslStateData));
     safe_free(sslState);
     return 0;
@@ -60,8 +117,7 @@ static void sslLifetimeExpire(fd, sslState)
 {
     debug(26, 4, "sslLifeTimeExpire: FD %d: URL '%s'>\n",
        fd, sslState->url);
-    comm_close(sslState->client.fd);   /* close client first */
-    comm_close(sslState->server.fd);
+    sslClose(sslState);
 }
 
 /* Read from server side and queue it for writing to the client */
@@ -70,7 +126,7 @@ static void sslReadServer(fd, sslState)
      SslStateData *sslState;
 {
     int len;
-    len = read(sslState->server.fd, sslState->server.buf, 4096);
+    len = read(sslState->server.fd, sslState->server.buf, SQUID_TCP_SO_RCVBUF);
     debug(26, 5, "sslReadServer FD %d, read %d bytes\n", fd, len);
     if (len < 0) {
        debug(26, 1, "sslReadServer: FD %d: read failure: %s\n",
@@ -88,13 +144,11 @@ static void sslReadServer(fd, sslState)
                (void *) sslState,
                sslState->timeout);
        } else {
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           sslClose(sslState);
        }
     } else if (len == 0) {
        /* Connection closed; retrieval done. */
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
     } else {
        sslState->server.offset = 0;
        sslState->server.len = len;
@@ -120,7 +174,7 @@ static void sslReadClient(fd, sslState)
      SslStateData *sslState;
 {
     int len;
-    len = read(sslState->client.fd, sslState->client.buf, 4096);
+    len = read(sslState->client.fd, sslState->client.buf, SQUID_TCP_SO_RCVBUF);
     debug(26, 5, "sslReadClient FD %d, read %d bytes\n",
        sslState->client.fd, len);
     if (len < 0) {
@@ -139,13 +193,11 @@ static void sslReadClient(fd, sslState)
                (void *) sslState,
                sslState->timeout);
        } else {
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           sslClose(sslState);
        }
     } else if (len == 0) {
        /* Connection closed; retrieval done. */
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
     } else {
        sslState->client.offset = 0;
        sslState->client.len = len;
@@ -177,8 +229,7 @@ static void sslWriteServer(fd, sslState)
     if (len < 0) {
        debug(26, 2, "sslWriteServer: FD %d: write failure: %s.\n",
            sslState->server.fd, xstrerror());
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
        return;
     }
     if ((sslState->client.offset += len) >= sslState->client.len) {
@@ -213,8 +264,7 @@ static void sslWriteClient(fd, sslState)
     if (len < 0) {
        debug(26, 2, "sslWriteClient: FD %d: write failure: %s.\n",
            sslState->client.fd, xstrerror());
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
        return;
     }
     if (sslState->size_ptr)
@@ -238,11 +288,8 @@ static void sslReadTimeout(fd, sslState)
      int fd;
      SslStateData *sslState;
 {
-    if (fd != sslState->server.fd)
-       fatal_dump("sslReadTimeout: FD mismatch!\n");
     debug(26, 3, "sslReadTimeout: FD %d\n", fd);
-    comm_close(sslState->client.fd);
-    comm_close(sslState->server.fd);
+    sslClose(sslState);
 }
 
 static void sslConnected(fd, sslState)
@@ -257,7 +304,7 @@ static void sslConnected(fd, sslState)
        COMM_SELECT_WRITE,
        (PF) sslWriteClient,
        (void *) sslState);
-    comm_set_fd_lifetime(fd, -1);      /* disable lifetime */
+    comm_set_fd_lifetime(fd, 86400);   /* extend lifetime */
     comm_set_select_handler_plus_timeout(sslState->server.fd,
        COMM_SELECT_TIMEOUT,
        (PF) sslReadTimeout,
@@ -273,16 +320,28 @@ static void sslConnected(fd, sslState)
        (void *) sslState);
 }
 
+static void sslErrorComplete(fd, buf, size, errflag, sslState)
+     int fd;
+     char *buf;
+     int size;
+     int errflag;
+     void *sslState;
+{
+    safe_free(buf);
+    sslClose(sslState);
+}
+
 
 static void sslConnInProgress(fd, sslState)
      int fd;
      SslStateData *sslState;
 {
     request_t *req = sslState->request;
+    char *buf = NULL;
     debug(26, 5, "sslConnInProgress: FD %d sslState=%p\n", fd, sslState);
 
     if (comm_connect(fd, req->host, req->port) != COMM_OK) {
-       debug(26, 5, "sslConnInProgress: FD %d: %s", fd, xstrerror());
+       debug(26, 5, "sslConnInProgress: FD %d: %s\n", fd, xstrerror());
        switch (errno) {
 #if EINPROGRESS != EALREADY
        case EINPROGRESS:
@@ -294,8 +353,18 @@ static void sslConnInProgress(fd, sslState)
                (void *) sslState);
            return;
        default:
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           buf = squid_error_url(sslState->url,
+               METHOD_CONNECT,
+               ERR_CONNECT_FAIL,
+               NULL,
+               500,
+               xstrerror());
+           comm_write(sslState->client.fd,
+               xstrdup(buf),
+               strlen(buf),
+               30,
+               sslErrorComplete,
+               sslState);
            return;
        }
     }
@@ -304,64 +373,31 @@ static void sslConnInProgress(fd, sslState)
     return;
 }
 
-
-int sslStart(fd, url, request, mime_hdr, size_ptr)
+static int sslConnect(fd, hp, sslState)
      int fd;
-     char *url;
-     request_t *request;
-     char *mime_hdr;
-     int *size_ptr;
+     struct hostent *hp;
+     SslStateData *sslState;
 {
-    /* Create state structure. */
-    int sock, status;
-    SslStateData *sslState = NULL;
-
-    debug(26, 3, "sslStart: '%s %s'\n",
-       RequestMethodStr[request->method], url);
-
-    /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
-    if (sock == COMM_ERROR) {
-       debug(26, 4, "sslStart: Failed because we're out of sockets.\n");
-       squid_error_url(url,
-           request->method,
-           ERR_NO_FDS,
-           fd_table[fd].ipaddr,
-           500,
-           xstrerror());
-       return COMM_ERROR;
-    }
-    sslState = (SslStateData *) xcalloc(1, sizeof(SslStateData));
-    sslState->url = xstrdup(url);
-    sslState->request = request;
-    sslState->mime_hdr = mime_hdr;
-    sslState->timeout = getReadTimeout();
-    sslState->size_ptr = size_ptr;
-    sslState->client.fd = fd;
-    sslState->server.fd = sock;
-    sslState->server.buf = xmalloc(SSL_BUFSIZ);
-    sslState->client.buf = xmalloc(SSL_BUFSIZ);
-    comm_set_select_handler(sslState->server.fd,
-       COMM_SELECT_CLOSE,
-       (PF) sslStateFree,
-       (void *) sslState);
-
-    /* check if IP is already in cache. It must be. 
-     * It should be done before this route is called. 
-     * Otherwise, we cannot check return code for ssl. */
-    if (!ipcache_gethostbyname(request->host)) {
-       debug(26, 4, "sslstart: Called without IP entry in ipcache. OR lookup failed.\n");
-       squid_error_url(url,
+    request_t *request = sslState->request;
+    int status;
+    char *buf = NULL;
+    if (!ipcache_gethostbyname(request->host, 0)) {
+       debug(26, 4, "sslConnect: Unknown host: %s\n", request->host);
+       buf = squid_error_url(sslState->url,
            request->method,
            ERR_DNS_FAIL,
            fd_table[fd].ipaddr,
            500,
            dns_error_message);
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       comm_write(sslState->client.fd,
+           xstrdup(buf),
+           strlen(buf),
+           30,
+           sslErrorComplete,
+           (void *) sslState);
        return COMM_ERROR;
     }
-    debug(26, 5, "sslStart: client=%d server=%d\n",
+    debug(26, 5, "sslConnect: client=%d server=%d\n",
        sslState->client.fd,
        sslState->server.fd);
     /* Install lifetime handler */
@@ -378,19 +414,23 @@ int sslStart(fd, url, request, mime_hdr, size_ptr)
        (PF) sslLifetimeExpire,
        (void *) sslState);
     /* Open connection. */
-    if ((status = comm_connect(sock, request->host, request->port))) {
+    if ((status = comm_connect(fd, request->host, request->port))) {
        if (status != EINPROGRESS) {
-           squid_error_url(url,
+           buf = squid_error_url(sslState->url,
                request->method,
                ERR_CONNECT_FAIL,
                fd_table[fd].ipaddr,
                500,
                xstrerror());
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           comm_write(sslState->client.fd,
+               xstrdup(buf),
+               strlen(buf),
+               30,
+               sslErrorComplete,
+               (void *) sslState);
            return COMM_ERROR;
        } else {
-           debug(26, 5, "sslStart: conn %d EINPROGRESS\n", sock);
+           debug(26, 5, "sslConnect: conn %d EINPROGRESS\n", fd);
            /* The connection is in progress, install ssl handler */
            comm_set_select_handler(sslState->server.fd,
                COMM_SELECT_WRITE,
@@ -399,7 +439,62 @@ int sslStart(fd, url, request, mime_hdr, size_ptr)
            return COMM_OK;
        }
     }
-    /* We got immediately connected. (can this happen?) */
     sslConnected(sslState->server.fd, sslState);
     return COMM_OK;
 }
+
+int sslStart(fd, url, request, mime_hdr, size_ptr)
+     int fd;
+     char *url;
+     request_t *request;
+     char *mime_hdr;
+     int *size_ptr;
+{
+    /* Create state structure. */
+    SslStateData *sslState = NULL;
+    int sock;
+    char *buf = NULL;
+
+    debug(26, 3, "sslStart: '%s %s'\n",
+       RequestMethodStr[request->method], url);
+
+    /* Create socket. */
+    sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
+    if (sock == COMM_ERROR) {
+       debug(26, 4, "sslStart: Failed because we're out of sockets.\n");
+       buf = squid_error_url(url,
+           request->method,
+           ERR_NO_FDS,
+           fd_table[fd].ipaddr,
+           500,
+           xstrerror());
+       comm_write(sslState->client.fd,
+           xstrdup(buf),
+           strlen(buf),
+           30,
+           sslErrorComplete,
+           (void *) sslState);
+       return COMM_ERROR;
+    }
+    sslState = xcalloc(1, sizeof(SslStateData));
+    sslState->url = xstrdup(url);
+    sslState->request = requestLink(request);
+    sslState->mime_hdr = mime_hdr;
+    sslState->timeout = getReadTimeout();
+    sslState->size_ptr = size_ptr;
+    sslState->client.fd = fd;
+    sslState->server.fd = sock;
+    sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
+    sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
+    comm_add_close_handler(sslState->server.fd,
+       (PF) sslStateFree,
+       (void *) sslState);
+    comm_add_close_handler(sslState->client.fd,
+       (PF) sslClientClosed,
+       (void *) sslState);
+    ipcache_nbgethostbyname(request->host,
+       sslState->server.fd,
+       (IPH) sslConnect,
+       sslState);
+    return COMM_OK;
+}
index ef139153a4e435ef89417db4ccd1904c0c2c15c3..fd81fe764bf0b859557be1dac64f219e4c3771ca 100644 (file)
-/* $Id: stat.cc,v 1.34 1996/05/15 05:13:25 wessels Exp $ */
+/*
+ * $Id: stat.cc,v 1.35 1996/07/09 03:41:41 wessels Exp $
+ *
+ * DEBUG: section 18    Cache Manager Statistics
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 18          stat
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 
 #include "squid.h"
 
-#ifdef _SQUID_HPUX_
-#define getrusage(a, b)  syscall(SYS_GETRUSAGE, a, b)
-#define getpagesize( )   sysconf(_SC_PAGE_SIZE)
-#endif /* _SQUID_HPUX_ */
-
 extern int emulate_httpd_log;
 
-#define MIN_BUFSIZE (4096)
 #define MAX_LINELEN (4096)
 #define max(a,b)  ((a)>(b)? (a): (b))
 
@@ -31,6 +124,7 @@ typedef struct _squid_read_data_t {
 Meta_data meta_data;
 unsigned long ntcpconn = 0;
 unsigned long nudpconn = 0;
+struct _iostats IOStats;
 
 char *stat_describe();
 char *mem_describe();
@@ -39,6 +133,10 @@ char *flags_describe();
 char *elapsed_time();
 char *diskFileName();
 
+/* LOCALS */
+char *open_bracket = "{\n";
+char *close_bracket = "}\n";
+
 /* process utilization information */
 void stat_utilization_get(obj, sentry)
      cacheinfo *obj;
@@ -51,7 +149,7 @@ void stat_utilization_get(obj, sentry)
 
     secs = (int) (squid_curtime - squid_starttime);
 
-    storeAppendPrintf(sentry, "{\n");
+    storeAppendPrintf(sentry, open_bracket);
 
     strcpy(p->protoname, "TOTAL");
     p->object_count = 0;
@@ -66,7 +164,7 @@ void stat_utilization_get(obj, sentry)
 
 
     /* find the total */
-    for (proto_id = 0; proto_id < PROTO_MAX; ++proto_id) {
+    for (proto_id = PROTO_NONE; proto_id < PROTO_MAX; ++proto_id) {
        q = &obj->proto_stat_data[proto_id];
 
        p->object_count += q->object_count;
@@ -81,7 +179,7 @@ void stat_utilization_get(obj, sentry)
     }
 
     /* dump it */
-    for (proto_id = 0; proto_id <= PROTO_MAX; ++proto_id) {
+    for (proto_id = PROTO_NONE; proto_id <= PROTO_MAX; ++proto_id) {
        p = &obj->proto_stat_data[proto_id];
        if (p->hit != 0) {
            p->hitratio =
@@ -89,7 +187,7 @@ void stat_utilization_get(obj, sentry)
                ((float) p->hit +
                (float) p->miss);
        }
-       storeAppendPrintf(sentry, "{%s %d %d %d %d %4.2f %d %d %d}\n",
+       storeAppendPrintf(sentry, "{%8.8s %d %d %d %d %4.2f %d %d %d}\n",
            p->protoname,
            p->object_count,
            p->kb.max,
@@ -101,7 +199,45 @@ void stat_utilization_get(obj, sentry)
            p->transferbyte);
     }
 
-    storeAppendPrintf(sentry, "}\n");
+    storeAppendPrintf(sentry, close_bracket);
+}
+
+void stat_io_get(sentry)
+     StoreEntry *sentry;
+{
+    int i;
+
+    storeAppendPrintf(sentry, open_bracket);
+    storeAppendPrintf(sentry, "{HTTP I/O}\n");
+    storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Http.reads);
+    storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
+       IOStats.Http.reads_deferred,
+       percent(IOStats.Http.reads_deferred, IOStats.Http.reads));
+    storeAppendPrintf(sentry, "{Read Histogram:}\n");
+    for (i = 0; i < 16; i++) {
+       storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
+           i ? (1 << (i - 1)) + 1 : 1,
+           1 << i,
+           IOStats.Http.read_hist[i],
+           percent(IOStats.Http.read_hist[i], IOStats.Http.reads));
+    }
+
+    storeAppendPrintf(sentry, "{}\n");
+    storeAppendPrintf(sentry, "{FTP I/O}\n");
+    storeAppendPrintf(sentry, "{number of reads: %d}\n", IOStats.Ftp.reads);
+    storeAppendPrintf(sentry, "{deferred reads: %d (%d%%)}\n",
+       IOStats.Ftp.reads_deferred,
+       percent(IOStats.Ftp.reads_deferred, IOStats.Ftp.reads));
+    storeAppendPrintf(sentry, "{Read Histogram:}\n");
+    for (i = 0; i < 16; i++) {
+       storeAppendPrintf(sentry, "{%5d-%5d: %9d %2d%%}\n",
+           i ? (1 << (i - 1)) + 1 : 1,
+           1 << i,
+           IOStats.Ftp.read_hist[i],
+           percent(IOStats.Ftp.read_hist[i], IOStats.Ftp.reads));
+    }
+
+    storeAppendPrintf(sentry, close_bracket);
 }
 
 
@@ -114,22 +250,11 @@ int cache_size_get(obj)
     int size = 0;
     protocol_t proto_id;
     /* sum all size, exclude total */
-    for (proto_id = 0; proto_id < PROTO_MAX; proto_id++)
+    for (proto_id = PROTO_NONE; proto_id < PROTO_MAX; proto_id++)
        size += obj->proto_stat_data[proto_id].kb.now;
     return size;
 }
 
-/* process general IP cache information */
-void stat_general_get(obj, sentry)
-     cacheinfo *obj;
-     StoreEntry *sentry;
-{
-    /* have to use old method for this guy, 
-     * otherwise we have to make ipcache know about StoreEntry */
-    stat_ipcache_get(sentry, obj);
-}
-
-
 /* process objects list */
 void stat_objects_get(obj, sentry, vm_or_not)
      cacheinfo *obj;
@@ -143,7 +268,7 @@ void stat_objects_get(obj, sentry, vm_or_not)
     int N = 0;
     int obj_size;
 
-    storeAppendPrintf(sentry, "{\n");
+    storeAppendPrintf(sentry, open_bracket);
 
     for (entry = storeGetFirst();
        entry != NULL;
@@ -171,7 +296,7 @@ void stat_objects_get(obj, sentry, vm_or_not)
            mem_describe(entry),
            stat_describe(entry));
     }
-    storeAppendPrintf(sentry, "}\n");
+    storeAppendPrintf(sentry, close_bracket);
 }
 
 
@@ -182,14 +307,20 @@ void stat_get(obj, req, sentry)
      StoreEntry *sentry;
 {
 
-    if (strncmp(req, "objects", strlen("objects")) == 0) {
+    if (strcmp(req, "objects") == 0) {
        stat_objects_get(obj, sentry, 0);
-    } else if (strncmp(req, "vm_objects", strlen("vm_objects")) == 0) {
+    } else if (strcmp(req, "vm_objects") == 0) {
        stat_objects_get(obj, sentry, 1);
-    } else if (strncmp(req, "general", strlen("general")) == 0) {
-       stat_general_get(obj, sentry);
-    } else if (strncmp(req, "utilization", strlen("utilization")) == 0) {
+    } else if (strcmp(req, "general") == 0) {
+       stat_ipcache_get(sentry);
+    } else if (strcmp(req, "general") == 0) {
+       stat_ipcache_get(sentry);
+    } else if (strcmp(req, "utilization") == 0) {
        stat_utilization_get(obj, sentry);
+    } else if (strcmp(req, "io") == 0) {
+       stat_io_get(sentry);
+    } else if (strcmp(req, "reply_headers") == 0) {
+       httpReplyHeaderStats(sentry);
     }
 }
 
@@ -228,7 +359,7 @@ void logReadEndHandler(fd_unused, errflag_unused, data)
      int errflag_unused;
      log_read_data_t *data;
 {
-    storeAppendPrintf(data->sentry, "}\n");
+    storeAppendPrintf(data->sentry, close_bracket);
     storeComplete(data->sentry);
     safe_free(data);
 }
@@ -248,8 +379,7 @@ void log_get_start(obj, sentry)
        storeComplete(sentry);
        return;
     }
-    data = (log_read_data_t *) xmalloc(sizeof(log_read_data_t));
-    memset(data, '\0', sizeof(log_read_data_t));
+    data = xcalloc(1, sizeof(log_read_data_t));
     data->sentry = sentry;
     storeAppendPrintf(sentry, "{\n");
     file_walk(obj->logfile_fd, (FILE_WALK_HD) logReadEndHandler,
@@ -266,8 +396,6 @@ int squidReadHandler(fd_unused, buf, size_unused, data)
      int size_unused;
      squid_read_data_t *data;
 {
-    static char tempbuf[MAX_LINELEN];
-    tempbuf[0] = '\0';
     storeAppendPrintf(data->sentry, "{\"%s\"}\n", buf);
     return 0;
 }
@@ -279,7 +407,7 @@ void squidReadEndHandler(fd_unused, errflag_unused, data)
      int errflag_unused;
      squid_read_data_t *data;
 {
-    storeAppendPrintf(data->sentry, "}\n");
+    storeAppendPrintf(data->sentry, close_bracket);
     storeComplete(data->sentry);
     file_close(data->fd);
     safe_free(data);
@@ -293,11 +421,10 @@ void squid_get_start(obj, sentry)
 {
     squid_read_data_t *data;
 
-    data = (squid_read_data_t *) xmalloc(sizeof(squid_read_data_t));
-    memset(data, '\0', sizeof(squid_read_data_t));
+    data = xcalloc(1, sizeof(squid_read_data_t));
     data->sentry = sentry;
     data->fd = file_open((char *) ConfigFile, NULL, O_RDONLY);
-    storeAppendPrintf(sentry, "{\n");
+    storeAppendPrintf(sentry, open_bracket);
     file_walk(data->fd, (FILE_WALK_HD) squidReadEndHandler, (void *) data,
        (FILE_WALK_LHD) squidReadHandler, (void *) data);
 }
@@ -316,25 +443,41 @@ void server_list(obj, sentry)
 {
     edge *e = NULL;
     dom_list *d = NULL;
+    icp_opcode op;
 
-    storeAppendPrintf(sentry, "{\n");
+    storeAppendPrintf(sentry, open_bracket);
 
-    if (getFirstEdge() == (edge *) NULL) {
+    if (getFirstEdge() == NULL)
        storeAppendPrintf(sentry, "{There are no neighbors installed.}\n");
-    }
     for (e = getFirstEdge(); e; e = getNextEdge(e)) {
        if (e->host == NULL)
            fatal_dump("Found an edge without a hostname!");
-       storeAppendPrintf(sentry, "\n{Hostname:    %s}\n", e->host);
-       storeAppendPrintf(sentry, "{Edge type:   %s}\n",
-           e->type == EDGE_PARENT ? "parent" : "neighbor");
-       storeAppendPrintf(sentry, "{Status:      %s}\n",
+       storeAppendPrintf(sentry, "\n{%-11.11s: %s/%d/%d}\n",
+           e->type == EDGE_PARENT ? "Parent" : "Sibling",
+           e->host,
+           e->http_port,
+           e->icp_port);
+       storeAppendPrintf(sentry, "{Status     : %s}\n",
            e->neighbor_up ? "Up" : "Down");
-       storeAppendPrintf(sentry, "{UDP PORT:    %d}\n", e->udp_port);
-       storeAppendPrintf(sentry, "{ASCII PORT:  %d}\n", e->ascii_port);
-       storeAppendPrintf(sentry, "{ACK DEFICIT: %d}\n", e->ack_deficit);
-       storeAppendPrintf(sentry, "{PINGS SENT:  %d}\n", e->num_pings);
-       storeAppendPrintf(sentry, "{PINGS ACKED: %d}\n", e->pings_acked);
+       storeAppendPrintf(sentry, "{AVG RTT    : %d msec}\n", e->stats.rtt);
+       storeAppendPrintf(sentry, "{ACK DEFICIT: %8d}\n", e->stats.ack_deficit);
+       storeAppendPrintf(sentry, "{PINGS SENT : %8d}\n", e->stats.pings_sent);
+       storeAppendPrintf(sentry, "{PINGS ACKED: %8d %3d%%}\n",
+           e->stats.pings_acked,
+           percent(e->stats.pings_acked, e->stats.pings_sent));
+       storeAppendPrintf(sentry, "{Histogram of PINGS ACKED:}\n");
+       for (op = ICP_OP_INVALID; op < ICP_OP_END; op++) {
+           if (e->stats.counts[op] == 0)
+               continue;
+           storeAppendPrintf(sentry, "{%-10.10s : %8d %3d%%}\n",
+               IcpOpcodeStr[op],
+               e->stats.counts[op],
+               percent(e->stats.counts[op], e->stats.pings_acked));
+       }
+       storeAppendPrintf(sentry, "{FETCHES    : %8d %3d%%}\n",
+           e->stats.fetches,
+           percent(e->stats.fetches, e->stats.pings_acked));
+
        if (e->last_fail_time) {
            storeAppendPrintf(sentry, "{Last failed connect() at: %s}\n",
                mkhttpdlogtime(&(e->last_fail_time)));
@@ -346,11 +489,21 @@ void server_list(obj, sentry)
            else
                storeAppendPrintf(sentry, "!%s ", d->domain);
        }
-       storeAppendPrintf(sentry, "}\n");
+       storeAppendPrintf(sentry, close_bracket);       /* } */
     }
-    storeAppendPrintf(sentry, "}\n");
+    storeAppendPrintf(sentry, close_bracket);
 }
 
+#if XMALLOC_STATISTICS
+void info_get_mallstat(size, number, sentry)
+     int size, number;
+     StoreEntry *sentry;
+{
+    static char line[MAX_LINELEN];
+    if (number > 0)
+       storeAppendPrintf(sentry, "{\t%d = %d}\n", size, number);
+}
+#endif
 
 
 void info_get(obj, sentry)
@@ -360,6 +513,9 @@ void info_get(obj, sentry)
     char *tod = NULL;
     static char line[MAX_LINELEN];
     wordlist *p = NULL;
+#ifdef HAVE_MALLINFO
+    int t;
+#endif
 
 #if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
     struct rusage rusage;
@@ -371,84 +527,79 @@ void info_get(obj, sentry)
 
     memset(line, '\0', SM_PAGE_SIZE);
 
-    storeAppendPrintf(sentry, "{\n");
-
+    storeAppendPrintf(sentry, open_bracket);
     storeAppendPrintf(sentry, "{Squid Object Cache: Version %s}\n", version_string);
-
     tod = mkrfc850(&squid_starttime);
-
     storeAppendPrintf(sentry, "{Start Time:\t%s}\n", tod);
-
     tod = mkrfc850(&squid_curtime);
     storeAppendPrintf(sentry, "{Current Time:\t%s}\n", tod);
 
     /* -------------------------------------------------- */
 
-    storeAppendPrintf(sentry, "{Connection information for %s:}\n",
-       appname);
-    storeAppendPrintf(sentry, "{\tNumber of TCP connections:\t%lu}\n",
-       ntcpconn);
-    storeAppendPrintf(sentry, "{\tNumber of UDP connections:\t%lu}\n",
-       nudpconn);
+    storeAppendPrintf(sentry, "{Connection information for %s:}\n", appname);
+
+    storeAppendPrintf(sentry, "{\tNumber of TCP connections:\t%lu}\n", ntcpconn);
+
+    storeAppendPrintf(sentry, "{\tNumber of UDP connections:\t%lu}\n", nudpconn);
 
     {
        float f;
        f = squid_curtime - squid_starttime;
-       storeAppendPrintf(sentry, "{\tConnections per hour:\t%.1f}\n",
-           f == 0.0 ? 0.0 :
+       storeAppendPrintf(sentry, "{\tConnections per hour:\t%.1f}\n", f == 0.0 ? 0.0 :
            ((ntcpconn + nudpconn) / (f / 3600)));
     }
 
     /* -------------------------------------------------- */
 
-    storeAppendPrintf(sentry, "{Cache information for %s:}\n", appname);
-
-    storeAppendPrintf(sentry, "{\tStorage Swap size:\t%d MB}\n", storeGetSwapSize() >> 10);
-
-    storeAppendPrintf(sentry, "{\tStorage Mem size:\t%d KB}\n", storeGetMemSize() >> 10);
 
+    storeAppendPrintf(sentry, "{Cache information for %s:}\n",
+       appname);
+    storeAppendPrintf(sentry, "{\tStorage Swap size:\t%d MB}\n",
+       storeGetSwapSize() >> 10);
+    storeAppendPrintf(sentry, "{\tStorage Mem size:\t%d KB}\n",
+       storeGetMemSize() >> 10);
     tod = mkrfc850(&next_cleaning);
     storeAppendPrintf(sentry, "{\tStorage Expiration at:\t%s}\n", tod);
 
-#if defined(HAVE_GETRUSAGE) && defined(RUSAGE_SELF)
+#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
     storeAppendPrintf(sentry, "{Resource usage for %s:}\n", appname);
-
     getrusage(RUSAGE_SELF, &rusage);
-    storeAppendPrintf(sentry, "{\tCPU Usage: user %d sys %d}\n{\tProcess Size: rss %d KB}\n",
-       rusage.ru_utime.tv_sec, rusage.ru_stime.tv_sec,
+    storeAppendPrintf(sentry, "{\tCPU Usage: user %d sys %d}\n",
+       (int) rusage.ru_utime.tv_sec, (int) rusage.ru_stime.tv_sec);
+    storeAppendPrintf(sentry, "{\tProcess Size: rss %ld KB}\n",
        rusage.ru_maxrss * getpagesize() >> 10);
 
-    storeAppendPrintf(sentry, "{\tPage faults with physical i/o:\t%d}\n",
+    storeAppendPrintf(sentry, "{\tPage faults with physical i/o: %ld}\n",
        rusage.ru_majflt);
 
 #endif
 
 #if HAVE_MALLINFO
     mp = mallinfo();
-
-    storeAppendPrintf(sentry, "{Memory usage for %s via mallinfo():}\n", appname);
-
-    storeAppendPrintf(sentry, "{\ttotal space in arena:\t%d KB}\n", mp.arena >> 10);
-    storeAppendPrintf(sentry, "{\tnumber of ordinary blocks:\t%d}\n", mp.ordblks);
-    storeAppendPrintf(sentry, "{\tnumber of small blocks:\t%d}\n", mp.smblks);
-    if (mp.hblks) {
-       storeAppendPrintf(sentry, "{\tnumber of holding blocks:\t%d}\n", mp.hblks);
-    }
-    if (mp.hblkhd) {
-       storeAppendPrintf(sentry, "{\tspace in holding block headers:\t%d}\n", mp.hblkhd);
-    }
-    if (mp.usmblks) {
-       storeAppendPrintf(sentry, "{\tspace in small blocks in use:\t%d}\n", mp.usmblks);
-    }
-    if (mp.fsmblks) {
-       storeAppendPrintf(sentry, "{\tspace in free blocks:\t%d}\n", mp.fsmblks);
-    }
-    storeAppendPrintf(sentry, "{\tspace in ordinary blocks in use:\t%d KB}\n",
-       mp.uordblks >> 10);
-    storeAppendPrintf(sentry, "{\tspace in free ordinary blocks:\t%d KB}\n", mp.fordblks >> 10);
-    if (mp.keepcost) {
-       storeAppendPrintf(sentry, "{\tcost of enabling keep option:\t%d}\n", mp.keepcost);
-    }
+    storeAppendPrintf(sentry, "{Memory usage for %s via mallinfo():}\n", appname
+);
+    storeAppendPrintf(sentry, "{\tTotal space in arena:  %6d KB}\n",
+        mp.arena >> 10);
+    storeAppendPrintf(sentry, "{\tOrdinary blocks:       %6d KB %6d blks}\n",
+       mp.uordblks >> 10, mp.ordblks);
+    storeAppendPrintf(sentry, "{\tSmall blocks:          %6d KB %6d blks}\n",
+       mp.usmblks >> 10, mp.smblks);
+    storeAppendPrintf(sentry, "{\tHolding blocks:        %6d KB %6d blks}\n",
+       mp.hblkhd >> 10, mp.hblks);
+    storeAppendPrintf(sentry, "{\tFree Small blocks:     %6d KB}\n",
+       mp.fsmblks >> 10);
+    storeAppendPrintf(sentry, "{\tFree Ordinary blocks:  %6d KB}\n",
+       mp.fordblks >> 10);
+    t = mp.uordblks + mp.usmblks + mp.hblkhd;
+    storeAppendPrintf(sentry, "{\tTotal in use:          %6d KB %d%%}\n",
+       t >> 10, percent(t, mp.arena));
+    t = mp.fsmblks + mp.fordblks;
+    storeAppendPrintf(sentry, "{\tTotal free:            %6d KB %d%%}\n",
+       t >> 10, percent(t, mp.arena));
+#ifdef WE_DONT_USE_KEEP
+    storeAppendPrintf(sentry, "{\tKeep option:           %6d KB}\n",
+       mp.keepcost >> 10);
+#endif
 #if HAVE_EXT_MALLINFO
     storeAppendPrintf(sentry, "{\tmax size of small blocks:\t%d}\n", mp.mxfast);
     storeAppendPrintf(sentry, "{\tnumber of small blocks in a holding block:\t%d}\n",
@@ -460,37 +611,32 @@ void info_get(obj, sentry)
        mp.allocated);
     storeAppendPrintf(sentry, "{\tbytes used in maintaining the free tree:\t%d}\n",
        mp.treeoverhead);
-
 #endif /* HAVE_EXT_MALLINFO */
-
 #endif /* HAVE_MALLINFO */
 
     storeAppendPrintf(sentry, "{File descriptor usage for %s:}\n", appname);
-
-    storeAppendPrintf(sentry, "{\tMax number of file desc available:\t%d}\n", getMaxFD());
-
-    storeAppendPrintf(sentry, "{\tLargest file desc currently in use:\t%d}\n",
+    storeAppendPrintf(sentry, "{\tMax number of file desc available:    %4d}\n",
+       FD_SETSIZE);
+    storeAppendPrintf(sentry, "{\tLargest file desc currently in use:   %4d}\n",
        fdstat_biggest_fd());
-
-    storeAppendPrintf(sentry, "{\tAvailable number of file descriptors :\t%d}\n",
+    storeAppendPrintf(sentry, "{\tAvailable number of file descriptors: %4d}\n",
        fdstat_are_n_free_fd(0));
-
-    storeAppendPrintf(sentry, "{\tReserved number of file descriptors :\t%d}\n",
+    storeAppendPrintf(sentry, "{\tReserved number of file descriptors:  %4d}\n",
        RESERVED_FD);
 
     {
-       int i, max_fd = getMaxFD();
+       int i;
        char *s = NULL;
 
        storeAppendPrintf(sentry, "{\tActive file descriptors:}\n");
 
-       for (i = 0; i < max_fd; i++) {
+       for (i = 0; i < FD_SETSIZE; i++) {
            int lft, to;
            if (!fdstat_isopen(i))
                continue;
            line[0] = '\0';
            switch (fdstat_type(i)) {
-           case Socket:
+           case FD_SOCKET:
                /* the lifetime should be greater than curtime */
                lft = comm_get_fd_lifetime(i);
                to = comm_get_fd_timeout(i);
@@ -500,17 +646,17 @@ void info_get(obj, sentry)
                    (int) max((to - squid_curtime), 0),
                    fd_note(i, NULL));
                break;
-           case File:
+           case FD_FILE:
                storeAppendPrintf(sentry, "{\t\t(%3d = FILE) %s}\n", i,
                    (s = diskFileName(i)) ? s : "Unknown");
                break;
-           case Pipe:
+           case FD_PIPE:
                storeAppendPrintf(sentry, "{\t\t(%3d = PIPE) %s}\n", i, fd_note(i, NULL));
                break;
-           case LOG:
+           case FD_LOG:
                storeAppendPrintf(sentry, "{\t\t(%3d = LOG) %s}\n", i, fd_note(i, NULL));
                break;
-           case Unknown:
+           case FD_UNKNOWN:
            default:
                storeAppendPrintf(sentry, "{\t\t(%3d = UNKNOWN) %s}\n", i, fd_note(i, NULL));
                break;
@@ -542,51 +688,85 @@ void info_get(obj, sentry)
        }
     }
     storeAppendPrintf(sentry, "{Internal Data Structures:}\n");
+    storeAppendPrintf(sentry, "{\tHot Object Cache Items %d}\n",
+       meta_data.hot_vm);
+    storeAppendPrintf(sentry, "{\tStoreEntries with MemObjects %d}\n",
+       meta_data.store_in_mem_objects);
+
     storeAppendPrintf(sentry, "{Meta Data:}\n");
 
-    storeAppendPrintf(sentry, "{\t\tStoreEntry %d x %d bytes = %d KB}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
+       "StoreEntry",
        meta_data.store_entries,
        (int) sizeof(StoreEntry),
        (int) (meta_data.store_entries * sizeof(StoreEntry) >> 10));
 
-    storeAppendPrintf(sentry, "{\t\tStoreMemObject %d x %d bytes = %d KB}\n",
-       meta_data.store_in_mem_objects,
-       (int) sizeof(MemObject),
-       (int) (meta_data.store_in_mem_objects * sizeof(MemObject) >> 10));
-
-    storeAppendPrintf(sentry, "{\t\tIPCacheEntry %d x %d bytes = %d KB}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
+       "IPCacheEntry",
        meta_data.ipcache_count,
        (int) sizeof(ipcache_entry),
        (int) (meta_data.ipcache_count * sizeof(ipcache_entry) >> 10));
 
-    storeAppendPrintf(sentry, "{\t\tHash link  %d x %d bytes = %d KB}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB}\n",
+       "Hash link",
        meta_data.hash_links = hash_links_allocated,
        (int) sizeof(hash_link),
        (int) (meta_data.hash_links * sizeof(hash_link) >> 10));
 
-    storeAppendPrintf(sentry, "{\t\tURL strings %d KB}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s                      = %6d KB}\n",
+       "URL strings",
        meta_data.url_strings >> 10);
 
-    storeAppendPrintf(sentry, "{\t\tHot Object Cache Items %d}\n", meta_data.hot_vm);
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
+       "Pool MemObject structures",
+       mem_obj_pool.total_pages_allocated,
+       mem_obj_pool.page_size,
+       mem_obj_pool.total_pages_allocated * mem_obj_pool.page_size >> 10,
+       (mem_obj_pool.total_pages_allocated - mem_obj_pool.n_pages_in_use) * mem_obj_pool.page_size >> 10);
+
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
+       "Pool for Request structures",
+       request_pool.total_pages_allocated,
+       request_pool.page_size,
+       request_pool.total_pages_allocated * request_pool.page_size >> 10,
+       (request_pool.total_pages_allocated - request_pool.n_pages_in_use) * request_pool.page_size >> 10);
+
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
+       "Pool for in-memory object data",
+       sm_stats.total_pages_allocated,
+       sm_stats.page_size,
+       sm_stats.total_pages_allocated * sm_stats.page_size >> 10,
+       (sm_stats.total_pages_allocated - sm_stats.n_pages_in_use) * sm_stats.page_size >> 10);
 
-    storeAppendPrintf(sentry, "{\t\tPool for disk I/O %d KB (Free %d KB)}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s %7d x %4d bytes = %6d KB (%6d free)}\n",
+       "Pool for disk I/O",
+       disk_stats.total_pages_allocated,
+       disk_stats.page_size,
        disk_stats.total_pages_allocated * disk_stats.page_size >> 10,
        (disk_stats.total_pages_allocated - disk_stats.n_pages_in_use) * disk_stats.page_size >> 10);
 
-    storeAppendPrintf(sentry, "{\t\tPool for in-memory objects %d KB (Free %d KB)}\n",
-       sm_stats.total_pages_allocated * sm_stats.page_size >> 10,
-       (sm_stats.total_pages_allocated - sm_stats.n_pages_in_use) * sm_stats.page_size >> 10);
+    storeAppendPrintf(sentry, "{\t%-25.25s                      = %6d KB}\n",
+       "Miscellaneous",
+       meta_data.misc >> 10);
 
-    storeAppendPrintf(sentry, "{\tTotal Accounted %d KB}\n",
+    storeAppendPrintf(sentry, "{\t%-25.25s                      = %6d KB}\n",
+       "Total Accounted",
        (int) (meta_data.store_entries * sizeof(StoreEntry) +
-           meta_data.store_in_mem_objects * sizeof(MemObject) +
            meta_data.ipcache_count * sizeof(ipcache_entry) +
            meta_data.hash_links * sizeof(hash_link) +
            sm_stats.total_pages_allocated * sm_stats.page_size +
            disk_stats.total_pages_allocated * disk_stats.page_size +
-           meta_data.url_strings) >> 10);
+           request_pool.total_pages_allocated * request_pool.page_size +
+           mem_obj_pool.total_pages_allocated * mem_obj_pool.page_size +
+           meta_data.url_strings +
+           meta_data.misc) >> 10);
+
+#if XMALLOC_STATISTICS
+    storeAppendPrintf(sentry, "{Memory allocation statistics}\n");
+    malloc_statistics(info_get_mallstat, sentry);
+#endif
 
-    storeAppendPrintf(sentry, "}\n");
+    storeAppendPrintf(sentry, close_bracket);
 }
 
 
@@ -601,7 +781,7 @@ void parameter_get(obj, sentry)
 
     memset(line, '\0', MAX_LINELEN);
 
-    storeAppendPrintf(sentry, "{\n");
+    storeAppendPrintf(sentry, open_bracket);
 
     storeAppendPrintf(sentry, "{VM-Max %d \"# Maximum hot-vm cache (MB)\"}\n",
        getCacheMemMax() / (1 << 20));
@@ -641,7 +821,7 @@ void parameter_get(obj, sentry)
 
     storeAppendPrintf(sentry, "{ReadTimeout %d \"# Maximum idle connection (s)\"}\n", getReadTimeout());
 
-    storeAppendPrintf(sentry, "{ClientLifetime %d \"# Lifetime for incoming ascii port requests or outgoing clients (s)\"}\n", getClientLifetime());
+    storeAppendPrintf(sentry, "{ClientLifetime %d \"# Lifetime for incoming HTTP requests or outgoing clients (s)\"}\n", getClientLifetime());
 
     storeAppendPrintf(sentry, "{CleanRate %d \"# Rate for periodic object expiring\"}\n",
        getCleanRate());
@@ -651,11 +831,11 @@ void parameter_get(obj, sentry)
        httpd_accel_mode);
 
     /* end of stats */
-    storeAppendPrintf(sentry, "}\n");
+    storeAppendPrintf(sentry, close_bracket);
 }
 
 
-void log_append(obj, url, id, size, action, method, http_code, msec, ident)
+void log_append(obj, url, id, size, action, method, http_code, msec, ident, hier)
      cacheinfo *obj;
      char *url;
      char *id;
@@ -665,6 +845,7 @@ void log_append(obj, url, id, size, action, method, http_code, msec, ident)
      int http_code;
      int msec;
      char *ident;
+     hier_code hier;
 {
     static char tmp[6000];     /* MAX_URL is 4096 */
     char *buf = NULL;
@@ -705,19 +886,18 @@ void log_append(obj, url, id, size, action, method, http_code, msec, ident)
                action,
                size);
        else
-           sprintf(tmp, "%9d.%03d %6d %s %s/%03d %d %s %s %s\n",
+           sprintf(tmp, "%9d.%03d %6d %s %s/%03d/%s %d %s %s %s\n",
                (int) current_time.tv_sec,
                (int) current_time.tv_usec / 1000,
                msec,
                id,
                action,
                http_code,
+               hier_strings[hier],
                size,
                method,
                url,
                ident);
-
-
        if (file_write(obj->logfile_fd, buf = xstrdup(tmp), strlen(tmp),
                obj->logfile_access, NULL, NULL) != DISK_OK) {
            debug(18, 1, "log_append: File write failed.\n");
@@ -730,8 +910,6 @@ void log_enable(obj, sentry)
      cacheinfo *obj;
      StoreEntry *sentry;
 {
-    static char tempbuf[MAX_LINELEN];
-
     if (obj->logfile_status == LOG_DISABLE) {
        obj->logfile_status = LOG_ENABLE;
 
@@ -746,7 +924,6 @@ void log_enable(obj, sentry)
     }
     /* at the moment, store one char to make a storage manager happy */
     storeAppendPrintf(sentry, " ");
-    storeAppend(sentry, tempbuf, strlen(tempbuf));
 }
 
 void log_disable(obj, sentry)
@@ -767,12 +944,7 @@ void log_clear(obj, sentry)
      cacheinfo *obj;
      StoreEntry *sentry;
 {
-    static char tempbuf[MAX_LINELEN];
-
-
-    /* what should be done here. Erase file ??? or move it to another name */
-    /* At the moment, just erase it. */
-    /* bug here need to be fixed. what if there are still data in memory. Need flush here */
+    /* what should be done here. Erase file ??? or move it to another name?  At the moment, just erase it.  bug here need to be fixed. what if there are still data in memory. Need flush here */
     if (obj->logfile_status == LOG_ENABLE)
        file_close(obj->logfile_fd);
 
@@ -786,7 +958,6 @@ void log_clear(obj, sentry)
     }
     /* at the moment, store one char to make a storage manager happy */
     storeAppendPrintf(sentry, " ");
-    storeAppend(sentry, tempbuf, strlen(tempbuf));
 }
 
 
@@ -859,13 +1030,10 @@ void stat_init(object, logfilename)
     cacheinfo *obj = NULL;
     int i;
 
-    obj = (cacheinfo *) xmalloc(sizeof(cacheinfo));
-    memset(obj, '\0', sizeof(cacheinfo));
-
+    obj = xcalloc(1, sizeof(cacheinfo));
     obj->stat_get = stat_get;
     obj->info_get = info_get;
     obj->cache_size_get = cache_size_get;
-
     obj->log_get_start = log_get_start;
     obj->log_status_get = log_status_get;
     obj->log_append = log_append;
@@ -873,13 +1041,11 @@ void stat_init(object, logfilename)
     obj->log_enable = log_enable;
     obj->log_disable = log_disable;
     obj->logfile_status = LOG_ENABLE;
-
     obj->squid_get_start = squid_get_start;
-
     obj->parameter_get = parameter_get;
     obj->server_list = server_list;
 
-    memcpy(obj->logfilename, logfilename, (int) (strlen(logfilename) + 1) % 256);
+    xmemcpy(obj->logfilename, logfilename, (int) (strlen(logfilename) + 1) % 256);
     obj->logfile_fd = file_open(obj->logfilename, NULL, O_RDWR | O_CREAT);
     if (obj->logfile_fd == DISK_ERROR) {
        debug(18, 0, "%s: %s\n", obj->logfilename, xstrerror());
@@ -895,7 +1061,7 @@ void stat_init(object, logfilename)
     obj->proto_miss = proto_miss;
     obj->NotImplement = dummyhandler;
 
-    for (i = 0; i <= PROTO_MAX; i++) {
+    for (i = PROTO_NONE; i <= PROTO_MAX; i++) {
        switch (i) {
        case PROTO_HTTP:
            strcpy(obj->proto_stat_data[i].protoname, "HTTP");
@@ -961,20 +1127,20 @@ char *stat_describe(entry)
     strncat(state, "/", sizeof(state));
 
     switch (entry->ping_status) {
-    case WAITING:
+    case PING_WAITING:
        strncat(state, "PING-WAIT", sizeof(state));
        break;
-    case TIMEOUT:
+    case PING_TIMEOUT:
        strncat(state, "PING-TIMEOUT", sizeof(state));
        break;
-    case DONE:
+    case PING_DONE:
        strncat(state, "PING-DONE", sizeof(state));
        break;
-    case NOPING:
+    case PING_NONE:
        strncat(state, "NO-PING", sizeof(state));
        break;
     default:
-       strncat(state, "YEEHAH", sizeof(state));
+       strncat(state, "HELP!!", sizeof(state));
        break;
     }
     return (state);
@@ -1115,7 +1281,7 @@ void stat_rotate_log()
     file_close(CacheInfo->logfile_fd);
     CacheInfo->logfile_fd = file_open(fname, NULL, O_RDWR | O_CREAT | O_APPEND);
     if (CacheInfo->logfile_fd == DISK_ERROR) {
-       debug(18, 0, "rotate_logs: Cannot open logfile: %s\n", fname);
+       debug(18, 0, "stat_rotate_log: Cannot open logfile: %s\n", fname);
        CacheInfo->logfile_status = LOG_DISABLE;
        fatal("Cannot open logfile.");
     }
index 9dab8c647d20c4db3314b3d1a8ebfadcd3863323..331cb07b779f11ba2d15aa0b630fdaa7effc0fcf 100644 (file)
-/* $Id: stmem.cc,v 1.9 1996/04/12 21:41:40 wessels Exp $ */
+/*
+ * $Id: stmem.cc,v 1.10 1996/07/09 03:41:42 wessels Exp $
+ *
+ * DEBUG: section 19    Memory Primitives
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
-/* 
- * DEBUG: Section 19          stmem:
+/*
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
 stmem_stats sm_stats;
 stmem_stats disk_stats;
+stmem_stats request_pool;
+stmem_stats mem_obj_pool;
 
 #define min(x,y) ((x)<(y)? (x) : (y))
 
@@ -117,7 +218,7 @@ int memAppend(mem, data, len)
     if (mem->head && mem->tail && (mem->tail->len < SM_PAGE_SIZE)) {
        avail_len = SM_PAGE_SIZE - (mem->tail->len);
        len_to_copy = min(avail_len, len);
-       memcpy((mem->tail->data + mem->tail->len), data, len_to_copy);
+       xmemcpy((mem->tail->data + mem->tail->len), data, len_to_copy);
        /* Adjust the ptr and len according to what was deposited in the page */
        data += len_to_copy;
        len -= len_to_copy;
@@ -125,11 +226,11 @@ int memAppend(mem, data, len)
     }
     while (len > 0) {
        len_to_copy = min(len, SM_PAGE_SIZE);
-       p = (mem_node) xcalloc(1, sizeof(Mem_Node));
+       p = xcalloc(1, sizeof(Mem_Node));
        p->next = NULL;
        p->len = len_to_copy;
        p->data = get_free_4k_page();
-       memcpy(p->data, data, len_to_copy);
+       xmemcpy(p->data, data, len_to_copy);
 
        if (!mem->head) {
            /* The chain is empty */
@@ -205,12 +306,15 @@ int memCopy(mem, offset, buf, size)
     mem_node p = mem->head;
     int t_off = mem->origin_offset;
     int bytes_to_go = size;
-    char *ptr_to_buf;
+    char *ptr_to_buf = NULL;
     int bytes_from_this_packet = 0;
     int bytes_into_this_packet = 0;
 
     debug(19, 6, "memCopy: offset %d: size %d\n", offset, size);
 
+    if (p == NULL)
+       fatal_dump("memCopy: NULL mem_node");
+
     if (size <= 0)
        return size;
 
@@ -232,18 +336,18 @@ int memCopy(mem, offset, buf, size)
     bytes_from_this_packet = min(bytes_to_go,
        p->len - bytes_into_this_packet);
 
-    memcpy(buf, p->data + bytes_into_this_packet, bytes_from_this_packet);
+    xmemcpy(buf, p->data + bytes_into_this_packet, bytes_from_this_packet);
     bytes_to_go -= bytes_from_this_packet;
     ptr_to_buf = buf + bytes_from_this_packet;
     p = p->next;
 
     while (p && bytes_to_go > 0) {
        if (bytes_to_go > p->len) {
-           memcpy(ptr_to_buf, p->data, p->len);
+           xmemcpy(ptr_to_buf, p->data, p->len);
            ptr_to_buf += p->len;
            bytes_to_go -= p->len;
        } else {
-           memcpy(ptr_to_buf, p->data, bytes_to_go);
+           xmemcpy(ptr_to_buf, p->data, bytes_to_go);
            bytes_to_go -= bytes_to_go;
        }
        p = p->next;
@@ -256,36 +360,82 @@ int memCopy(mem, offset, buf, size)
 /* Do whatever is necessary to begin storage of new object */
 mem_ptr memInit()
 {
-    mem_ptr new = (mem_ptr) xcalloc(1, sizeof(Mem_Hdr));
-
+    mem_ptr new = xcalloc(1, sizeof(Mem_Hdr));
     new->tail = new->head = NULL;
-
     new->mem_free = memFree;
     new->mem_free_data = memFreeData;
     new->mem_free_data_upto = memFreeDataUpto;
     new->mem_append = memAppend;
     new->mem_copy = memCopy;
     new->mem_grep = memGrep;
-
     return new;
 }
 
+void *get_free_request_t()
+{
+    void *req = NULL;
+    if (!empty_stack(&request_pool.free_page_stack)) {
+       req = pop(&request_pool.free_page_stack);
+    } else {
+       req = xmalloc(sizeof(request_t));
+       request_pool.total_pages_allocated++;
+    }
+    request_pool.n_pages_in_use++;
+    if (req == NULL)
+       fatal_dump("get_free_request_t: Null pointer?");
+    memset(req, '\0', sizeof(request_t));
+    return (req);
+}
+
+void put_free_request_t(req)
+     void *req;
+{
+    if (full_stack(&request_pool.free_page_stack))
+       request_pool.total_pages_allocated--;
+    request_pool.n_pages_in_use--;
+    push(&request_pool.free_page_stack, req);
+}
+
+void *get_free_mem_obj()
+{
+    void *mem = NULL;
+    if (!empty_stack(&mem_obj_pool.free_page_stack)) {
+       mem = pop(&mem_obj_pool.free_page_stack);
+    } else {
+       mem = xmalloc(sizeof(MemObject));
+       mem_obj_pool.total_pages_allocated++;
+    }
+    mem_obj_pool.n_pages_in_use++;
+    if (mem == NULL)
+       fatal_dump("get_free_mem_obj: Null pointer?");
+    memset(mem, '\0', sizeof(MemObject));
+    return (mem);
+}
+
+void put_free_mem_obj(mem)
+     void *mem;
+{
+    if (full_stack(&mem_obj_pool.free_page_stack))
+       mem_obj_pool.total_pages_allocated--;
+    mem_obj_pool.n_pages_in_use--;
+    push(&mem_obj_pool.free_page_stack, mem);
+}
+
 
 /* PBD 12/95: Memory allocator routines for saving and reallocating fixed 
  * size blocks rather than mallocing and freeing them */
 char *get_free_4k_page()
 {
     char *page = NULL;
-
     if (!empty_stack(&sm_stats.free_page_stack)) {
        page = pop(&sm_stats.free_page_stack);
     } else {
 #if USE_MEMALIGN
-       page = (char *) memalign(SM_PAGE_SIZE, SM_PAGE_SIZE);
+       page = memalign(SM_PAGE_SIZE, SM_PAGE_SIZE);
        if (!page)
            fatal_dump(NULL);
 #else
-       page = (char *) xmalloc(SM_PAGE_SIZE);
+       page = xmalloc(SM_PAGE_SIZE);
 #endif
        sm_stats.total_pages_allocated++;
     }
@@ -298,38 +448,28 @@ char *get_free_4k_page()
 void put_free_4k_page(page)
      char *page;
 {
-    static stack_overflow_warning_toggle;
-
 #if USE_MEMALIGN
     if ((int) page % SM_PAGE_SIZE)
        fatal_dump("Someone tossed a string into the 4k page pool");
 #endif
-    if (full_stack(&sm_stats.free_page_stack)) {
+    if (full_stack(&sm_stats.free_page_stack))
        sm_stats.total_pages_allocated--;
-       if (!stack_overflow_warning_toggle) {
-           debug(19, 0, "Stack of free stmem pages overflowed.  Resize it?");
-           stack_overflow_warning_toggle++;
-       }
-    }
     sm_stats.n_pages_in_use--;
-    /* Call push regardless if it's full, cause it's just going to release the
-     * page if stack is full */
     push(&sm_stats.free_page_stack, page);
 }
 
 char *get_free_8k_page()
 {
     char *page = NULL;
-
     if (!empty_stack(&disk_stats.free_page_stack)) {
        page = pop(&disk_stats.free_page_stack);
     } else {
 #if USE_MEMALIGN
-       page = (char *) memalign(DISK_PAGE_SIZE, DISK_PAGE_SIZE);
+       page = memalign(DISK_PAGE_SIZE, DISK_PAGE_SIZE);
        if (!page)
            fatal_dump(NULL);
 #else
-       page = (char *) xmalloc(DISK_PAGE_SIZE);
+       page = xmalloc(DISK_PAGE_SIZE);
 #endif
        disk_stats.total_pages_allocated++;
     }
@@ -342,23 +482,13 @@ char *get_free_8k_page()
 void put_free_8k_page(page)
      char *page;
 {
-    static stack_overflow_warning_toggle;
-
 #if USE_MEMALIGN
     if ((int) page % DISK_PAGE_SIZE)
        fatal_dump("Someone tossed a string into the 8k page pool");
 #endif
-
-    if (full_stack(&disk_stats.free_page_stack)) {
+    if (full_stack(&disk_stats.free_page_stack))
        disk_stats.total_pages_allocated--;
-       if (!stack_overflow_warning_toggle) {
-           debug(19, 0, "Stack of free disk pages overflowed.  Resize it?");
-           stack_overflow_warning_toggle++;
-       }
-    }
     disk_stats.n_pages_in_use--;
-    /* Call push regardless if it's full, cause it's just going to release the
-     * page if stack is full */
     push(&disk_stats.free_page_stack, page);
 }
 
@@ -374,18 +504,29 @@ void stmemInit()
     disk_stats.n_pages_free = 0;
     disk_stats.n_pages_in_use = 0;
 
+    request_pool.page_size = sizeof(request_t);
+    request_pool.total_pages_allocated = 0;
+    request_pool.n_pages_free = 0;
+    request_pool.n_pages_in_use = 0;
+
+    mem_obj_pool.page_size = sizeof(MemObject);
+    mem_obj_pool.total_pages_allocated = 0;
+    mem_obj_pool.n_pages_free = 0;
+    mem_obj_pool.n_pages_in_use = 0;
+
 /* use -DPURIFY=1 on the compile line to enable Purify checks */
 
 #if !PURIFY
-    /* 4096 * 10000 pages = 40MB + CacheMemMax in pages */
-    init_stack(&sm_stats.free_page_stack, 10000 + (getCacheMemMax() / SM_PAGE_SIZE));
-    /* 8096 * 1000 pages = 8MB */
+    init_stack(&sm_stats.free_page_stack, (getCacheMemMax() / SM_PAGE_SIZE) >> 1);
     init_stack(&disk_stats.free_page_stack, 1000);
-#else
+    init_stack(&request_pool.free_page_stack, FD_SETSIZE >> 3);
+    init_stack(&mem_obj_pool.free_page_stack, FD_SETSIZE >> 3);
+#else /* !PURIFY */
     /* Declare a zero size page stack so that purify checks for 
-     * FMRs/UMRs etc.
-     */
+     * FMRs/UMRs etc.  */
     init_stack(&sm_stats.free_page_stack, 0);
     init_stack(&disk_stats.free_page_stack, 0);
-#endif
+    init_stack(&request_pool.free_page_stack, 0);
+    init_stack(&mem_obj_pool.free_page_stack, 0);
+#endif /* !PURIFY */
 }
index f55c298e3eb1ccd355132d4a51b4135b2b616283..6d95f34b231586970b8bb5510241f329ff4d66f6 100644 (file)
@@ -1,8 +1,106 @@
-
-/* $Id: store.cc,v 1.65 1996/05/03 22:56:33 wessels Exp $ */
+/*
+ * $Id: store.cc,v 1.66 1996/07/09 03:41:43 wessels Exp $
+ *
+ * DEBUG: section 20    Storeage Manager
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 20          store
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 /* 
 #define WITHOUT_MEMOBJ 0
 
 /* rate of checking expired objects in main loop */
-#define STORE_MAINTAIN_RATE    (20)
+#define STORE_MAINTAIN_RATE    (10)
 
 #define STORE_BUCKETS          (7921)
 #define STORE_IN_MEM_BUCKETS           (143)
@@ -67,19 +165,30 @@ struct storeRebuild_data {
     int clashcount;            /* # swapfile clashes avoided */
     int dupcount;              /* # duplicates purged */
     time_t start, stop;
-    int fast_mode;
+    int speed;                 /* # Objects per run */
     char line_in[4096];
 };
 
+/* initializtion flag */
+int store_rebuilding = STORE_REBUILDING_SLOW;
+
+/* Static Functions */
+static int storeSwapInStart _PARAMS((StoreEntry *, SIH, void *));
+static void destroy_MemObject _PARAMS((MemObject *));
+static void destroy_MemObjectData _PARAMS((MemObject *));
+static void destroy_StoreEntry _PARAMS((StoreEntry *));
+static MemObject *new_MemObject _PARAMS((void));
+static mem_ptr new_MemObjectData _PARAMS((void));
+static StoreEntry *new_StoreEntry _PARAMS((int mem_obj_flag));
+static int storeCheckPurgeMem _PARAMS((StoreEntry * e));
+
+
 /* Now, this table is inaccessible to outsider. They have to use a method
  * to access a value in internal storage data structure. */
 HashID table = 0;
 /* hash table for in-memory-only objects */
 HashID in_mem_table = 0;
 
-/* initializtion flag */
-static int ok_write_clean_log = 0;
-
 /* current memory storage size */
 static unsigned long store_mem_size = 0;
 static unsigned long store_mem_high = 0;
@@ -112,12 +221,12 @@ int ncache_dirs = 0;
 
 static MemObject *new_MemObject()
 {
-    MemObject *m = NULL;
-    m = (MemObject *) xcalloc(1, sizeof(MemObject));
-    m->reply = (struct _http_reply *) xcalloc(1, sizeof(struct _http_reply));
+    MemObject *mem = get_free_mem_obj();
+    mem->reply = xcalloc(1, sizeof(struct _http_reply));
     meta_data.store_in_mem_objects++;
-    debug(20, 3, "new_MemObject: returning %p\n", m);
-    return m;
+    meta_data.misc += sizeof(struct _http_reply);
+    debug(20, 3, "new_MemObject: returning %p\n", mem);
+    return mem;
 }
 
 static StoreEntry *new_StoreEntry(mem_obj_flag)
@@ -125,7 +234,7 @@ static StoreEntry *new_StoreEntry(mem_obj_flag)
 {
     StoreEntry *e = NULL;
 
-    e = (StoreEntry *) xcalloc(1, sizeof(StoreEntry));
+    e = xcalloc(1, sizeof(StoreEntry));
     meta_data.store_entries++;
     if (mem_obj_flag)
        e->mem_obj = new_MemObject();
@@ -133,14 +242,28 @@ static StoreEntry *new_StoreEntry(mem_obj_flag)
     return e;
 }
 
-static void destroy_MemObject(m)
-     MemObject *m;
+static void destroy_MemObject(mem)
+     MemObject *mem;
 {
-    debug(20, 3, "destroy_MemObject: destroying %p\n", m);
-    safe_free(m->mime_hdr);
-    safe_free(m->reply);
-    xfree(m);
+    int i;
+    debug(20, 3, "destroy_MemObject: destroying %p\n", mem);
+    destroy_MemObjectData(mem);
+    safe_free(mem->pending);
+    if (mem->client_list) {
+       for (i = 0; i < mem->client_list_size; ++i) {
+           if (mem->client_list[i])
+               safe_free(mem->client_list[i]);
+       }
+       safe_free(mem->client_list);
+    }
+    safe_free(mem->mime_hdr);
+    safe_free(mem->reply);
+    safe_free(mem->e_abort_msg);
+    requestUnlink(mem->request);
+    mem->request = NULL;
+    put_free_mem_obj(mem);
     meta_data.store_in_mem_objects--;
+    meta_data.misc -= sizeof(struct _http_reply);
 }
 
 static void destroy_StoreEntry(e)
@@ -151,6 +274,16 @@ static void destroy_StoreEntry(e)
        fatal_dump("destroy_StoreEntry: NULL Entry");
     if (e->mem_obj)
        destroy_MemObject(e->mem_obj);
+    if (e->url) {
+       meta_data.url_strings -= strlen(e->url);
+       safe_free(e->url);
+    } else {
+       debug(20, 3, "destroy_StoreEntry: WARNING!  Entry without URL string!\n");
+    }
+    if (BIT_TEST(e->flag, KEY_URL))
+       e->key = NULL;
+    else
+       safe_free(e->key);
     xfree(e);
     meta_data.store_entries--;
 }
@@ -162,21 +295,21 @@ static mem_ptr new_MemObjectData()
     return memInit();
 }
 
-static void destroy_MemObjectData(m)
-     MemObject *m;
+static void destroy_MemObjectData(mem)
+     MemObject *mem;
 {
-    debug(20, 3, "destroy_MemObjectData: destroying %p\n", m->data);
-    store_mem_size -= m->e_current_len - m->e_lowest_offset;
+    debug(20, 3, "destroy_MemObjectData: destroying %p\n", mem->data);
+    store_mem_size -= mem->e_current_len - mem->e_lowest_offset;
     debug(20, 8, "destroy_MemObjectData: Freeing %d in-memory bytes\n",
-       m->e_current_len);
+       mem->e_current_len);
     debug(20, 8, "destroy_MemObjectData: store_mem_size = %d\n",
        store_mem_size);
-    if (m->data) {
-       m->data->mem_free(m->data);
-       m->data = NULL;
+    if (mem->data) {
+       mem->data->mem_free(mem->data);
+       mem->data = NULL;
        meta_data.hot_vm--;
     }
-    m->e_current_len = 0;
+    mem->e_current_len = 0;
 }
 
 /* ----- INTERFACE BETWEEN STORAGE MANAGER AND HASH TABLE FUNCTIONS --------- */
@@ -233,7 +366,7 @@ int storeHashDelete(hash_ptr)
 
 void storeSetMemStatus(e, status)
      StoreEntry *e;
-     int status;
+     mem_status_t status;
 {
     hash_link *ptr = NULL;
 
@@ -251,42 +384,6 @@ void storeSetMemStatus(e, status)
 
 /* -------------------------------------------------------------------------- */
 
-/* free whole entry */
-void storeFreeEntry(e)
-     StoreEntry *e;
-{
-    int i;
-
-    if (!e)
-       fatal_dump("storeFreeEntry: NULL Entry");
-
-    debug(20, 3, "storeFreeEntry: Freeing %s\n", e->key);
-
-    if (e->mem_obj) {
-       destroy_MemObjectData(e->mem_obj);
-       e->mem_obj->data = NULL;
-    }
-    meta_data.url_strings -= strlen(e->url);
-    safe_free(e->url);
-    if (BIT_TEST(e->flag, KEY_URL))
-       e->key = NULL;
-    else
-       safe_free(e->key);
-    if (e->mem_obj) {
-       safe_free(e->mem_obj->mime_hdr);
-       /* Leave an unzeroed pointer to the abort msg for posterity */
-       safe_free(e->mem_obj->e_abort_msg);
-       safe_free(e->mem_obj->pending);
-       /* look up to free client_list */
-       if (e->mem_obj->client_list) {
-           for (i = 0; i < e->mem_obj->client_list_size; ++i)
-               safe_free(e->mem_obj->client_list[i]);
-           safe_free(e->mem_obj->client_list);
-       }
-    }
-    destroy_StoreEntry(e);
-}
-
 static char *time_describe(t)
      time_t t;
 {
@@ -352,38 +449,26 @@ void storePurgeMem(e)
     debug(20, 3, "storePurgeMem: Freeing memory-copy of %s\n", e->key);
     if (e->mem_obj == NULL)
        return;
-
     if (storeEntryLocked(e)) {
-       debug(20, 0, "storePurgeMem: someone (storeGetMemSpace?) is purging a locked object?\n");
+       debug(20, 0, "storePurgeMem: someone is purging a locked object?\n");
        debug(20, 0, "%s", storeToString(e));
        fatal_dump(NULL);
     }
-    destroy_MemObjectData(e->mem_obj);
-    e->mem_obj->data = NULL;
-    debug(20, 8, "storePurgeMem: Freeing %d in-memory bytes\n",
-       e->object_len);
-    debug(20, 8, "storePurgeMem: store_mem_size = %d\n", store_mem_size);
     storeSetMemStatus(e, NOT_IN_MEMORY);
-    e->mem_obj->e_current_len = 0;
-    /* free up pending list table */
-    safe_free(e->mem_obj->pending);
-    e->mem_obj->pending_list_size = 0;
-    /* free up client list table and entries */
-    if (e->mem_obj->client_list) {
-       int i;
-       for (i = 0; i < e->mem_obj->client_list_size; ++i) {
-           if (e->mem_obj->client_list[i])
-               safe_free(e->mem_obj->client_list[i]);
-       }
-       safe_free(e->mem_obj->client_list);
-    }
     destroy_MemObject(e->mem_obj);
     e->mem_obj = NULL;
 }
 
 /* lock the object for reading, start swapping in if necessary */
-int storeLockObject(e)
+/* Called by:
+ * icp_hit_or_miss()
+ * storeAbort()
+ * {http,ftp,gopher,wais}Start()
+ */
+int storeLockObject(e, handler, data)
      StoreEntry *e;
+     SIH handler;
+     void *data;
 {
     int swap_in_stat = 0;
     int status = 0;
@@ -401,11 +486,10 @@ int storeLockObject(e)
     }
     e->lastref = squid_curtime;
 
-    /* StoreLockObject() is called during icp_hit_or_miss and once by storeAbort 
-     * If the object is NOT_IN_MEMORY, fault it in. */
+    /* If the object is NOT_IN_MEMORY, fault it in. */
     if ((e->mem_status == NOT_IN_MEMORY) && (e->swap_status == SWAP_OK)) {
        /* object is in disk and no swapping daemon running. Bring it in. */
-       if ((swap_in_stat = storeSwapInStart(e)) < 0) {
+       if ((swap_in_stat = storeSwapInStart(e, handler, data)) < 0) {
            /*
             * We couldn't find or couldn't open object's swapfile.
             * So, return a -1 here, indicating that we will treat
@@ -414,6 +498,14 @@ int storeLockObject(e)
            e->lock_count--;
        }
        status = swap_in_stat;
+    } else if (e->mem_status == IN_MEMORY && handler) {
+       /* its already in memory, so call the handler */
+       (*handler) (0, data);
+    } else if (handler) {
+       /* The object is probably in state SWAPPING_IN, not much we can do.
+        * Instead of returning failure here, we should have a list of complete
+        * handlers which we could append to... */
+       (*handler) (1, data);
     }
     return status;
 }
@@ -423,18 +515,18 @@ void storeReleaseRequest(e)
 {
     if (e->flag & RELEASE_REQUEST)
        return;
+    if (!storeEntryLocked(e))
+       fatal_dump("Somebody called storeReleaseRequest on an unlocked entry");
     debug(20, 3, "storeReleaseRequest: FOR '%s'\n", e->key ? e->key : e->url);
     e->flag |= RELEASE_REQUEST;
 }
 
 /* unlock object, return -1 if object get released after unlock
  * otherwise lock_count */
-
 int storeUnlockObject(e)
      StoreEntry *e;
 {
-    int e_lock_count;
-
+    int lock_count;
 
     if ((int) e->lock_count > 0)
        e->lock_count--;
@@ -443,28 +535,30 @@ int storeUnlockObject(e)
     }
     debug(20, 3, "storeUnlockObject: key '%s' count=%d\n", e->key, e->lock_count);
 
+    if (e->lock_count)
+       return e->lock_count;
+
     /* Prevent UMR if we end up freeing the entry */
-    e_lock_count = (int) e->lock_count;
+    lock_count = (int) e->lock_count;
 
-    if (e->lock_count == 0) {
-       if (e->flag & RELEASE_REQUEST) {
-           storeRelease(e);
-       } else if (e->flag & ABORT_MSG_PENDING) {
-           /* This is where the negative cache gets storeAppended */
-           /* Briefly lock to replace content with abort message */
-           e->lock_count++;
-           destroy_MemObjectData(e->mem_obj);
-           e->object_len = 0;
-           e->mem_obj->data = new_MemObjectData();
-           storeAppend(e, e->mem_obj->e_abort_msg, strlen(e->mem_obj->e_abort_msg));
-           e->object_len = e->mem_obj->e_current_len
-               = strlen(e->mem_obj->e_abort_msg);
-           BIT_RESET(e->flag, ABORT_MSG_PENDING);
-           e->lock_count--;
-       }
+    if (e->flag & RELEASE_REQUEST) {
+       storeRelease(e);
+    } else if (e->flag & ABORT_MSG_PENDING) {
+       /* This is where the negative cache gets storeAppended */
+       /* Briefly lock to replace content with abort message */
+       e->lock_count++;
+       destroy_MemObjectData(e->mem_obj);
+       e->object_len = 0;
+       e->mem_obj->data = new_MemObjectData();
+       storeAppend(e, e->mem_obj->e_abort_msg, strlen(e->mem_obj->e_abort_msg));
+       e->object_len = e->mem_obj->e_current_len
+           = strlen(e->mem_obj->e_abort_msg);
+       BIT_RESET(e->flag, ABORT_MSG_PENDING);
+       e->lock_count--;
+    } else if (storeCheckPurgeMem(e)) {
+       storePurgeMem(e);
     }
-    return e_lock_count;
-
+    return lock_count;
 }
 
 /* Lookup an object in the cache. 
@@ -491,7 +585,7 @@ unsigned int getKeyCounter()
 
 char *storeGeneratePrivateKey(url, method, num)
      char *url;
-     int method;
+     method_t method;
      int num;
 {
     if (num == 0)
@@ -507,7 +601,7 @@ char *storeGeneratePrivateKey(url, method, num)
 
 char *storeGeneratePublicKey(url, method)
      char *url;
-     int method;
+     method_t method;
 {
     debug(20, 3, "storeGeneratePublicKey: type=%d %s\n", method, url);
     switch (method) {
@@ -520,6 +614,11 @@ char *storeGeneratePublicKey(url, method)
        return key_temp_buffer;
        /* NOTREACHED */
        break;
+    case METHOD_PUT:
+       sprintf(key_temp_buffer, "/put/%s", url);
+       return key_temp_buffer;
+       /* NOTREACHED */
+       break;
     case METHOD_HEAD:
        sprintf(key_temp_buffer, "/head/%s", url);
        return key_temp_buffer;
@@ -579,10 +678,10 @@ void storeSetPublicKey(e)
 
     newkey = storeGeneratePublicKey(e->url, e->method);
     while ((table_entry = hash_lookup(table, newkey))) {
-       debug(20, 0, "storeSetPublicKey: Making old '%s' private.\n", newkey);
+       debug(20, 3, "storeSetPublicKey: Making old '%s' private.\n", newkey);
        e2 = (StoreEntry *) table_entry;
        storeSetPrivateKey(e2);
-       storeReleaseRequest(e2);
+       storeRelease(e2);
        if (loop_detect++ == 10)
            fatal_dump("storeSetPublicKey() is looping!!");
        newkey = storeGeneratePublicKey(e->url, e->method);
@@ -608,21 +707,22 @@ StoreEntry *storeCreateEntry(url, req_hdr, flags, method)
      char *url;
      char *req_hdr;
      int flags;
-     int method;
+     method_t method;
 {
     StoreEntry *e = NULL;
-    MemObject *m = NULL;
+    MemObject *mem = NULL;
     debug(20, 3, "storeCreateEntry: '%s' icp flags=%x\n", url, flags);
 
     if (meta_data.hot_vm > store_hotobj_high)
        storeGetMemSpace(0, 1);
     e = new_StoreEntry(WITH_MEMOBJ);
-    m = e->mem_obj;
+    e->lock_count = 1;         /* Note lock here w/o calling storeLock() */
+    mem = e->mem_obj;
     e->url = xstrdup(url);
     meta_data.url_strings += strlen(url);
     e->method = method;
     if (req_hdr)
-       m->mime_hdr = xstrdup(req_hdr);
+       mem->mime_hdr = xstrdup(req_hdr);
     if (BIT_TEST(flags, REQ_NOCACHE))
        BIT_SET(e->flag, REFRESH_REQUEST);
     if (BIT_TEST(flags, REQ_CACHABLE)) {
@@ -647,22 +747,21 @@ StoreEntry *storeCreateEntry(url, req_hdr, flags, method)
     storeSetMemStatus(e, NOT_IN_MEMORY);
     e->swap_status = NO_SWAP;
     e->swap_file_number = -1;
-    e->lock_count = 0;
-    m->data = new_MemObjectData();
+    mem->data = new_MemObjectData();
     e->refcount = 0;
     e->lastref = squid_curtime;
     e->timestamp = 0;          /* set in storeSwapOutHandle() */
-    e->ping_status = NOPING;
+    e->ping_status = PING_NONE;
 
     /* allocate pending list */
-    m->pending_list_size = MIN_PENDING;
-    m->pending = (struct pentry **)
-       xcalloc(m->pending_list_size, sizeof(struct pentry *));
+    mem->pending_list_size = MIN_PENDING;
+    mem->pending = (struct pentry **)
+       xcalloc(mem->pending_list_size, sizeof(struct pentry *));
 
     /* allocate client list */
-    m->client_list_size = MIN_CLIENT;
-    m->client_list = (ClientStatusEntry **)
-       xcalloc(m->client_list_size, sizeof(ClientStatusEntry *));
+    mem->client_list_size = MIN_CLIENT;
+    mem->client_list = (ClientStatusEntry **)
+       xcalloc(mem->client_list_size, sizeof(ClientStatusEntry *));
     /* storeLog(STORE_LOG_CREATE, e); */
     return e;
 
@@ -685,7 +784,6 @@ StoreEntry *storeAddDiskRestore(url, file_number, size, expires, timestamp)
     /* if you call this you'd better be sure file_number is not 
      * already in use! */
 
-    meta_data.store_entries++;
     meta_data.url_strings += strlen(url);
 
     e = new_StoreEntry(WITHOUT_MEMOBJ);
@@ -707,7 +805,7 @@ StoreEntry *storeAddDiskRestore(url, file_number, size, expires, timestamp)
     e->lastref = squid_curtime;
     e->timestamp = (u_num32) timestamp;
     e->expires = (u_num32) expires;
-    e->ping_status = NOPING;
+    e->ping_status = PING_NONE;
     return e;
 }
 
@@ -725,7 +823,7 @@ int storeRegister(e, fd, handler, data)
 
     debug(20, 3, "storeRegister: FD %d '%s'\n", fd, e->key);
 
-    pe = (PendingEntry *) xcalloc(1, sizeof(PendingEntry));
+    pe = xcalloc(1, sizeof(PendingEntry));
     pe->fd = fd;
     pe->handler = handler;
     pe->data = data;
@@ -752,7 +850,7 @@ int storeRegister(e, fd, handler, data)
        e->mem_obj->pending_list_size += MIN_PENDING;
 
        /* allocate, and copy old pending list over to the new one */
-       tmp = (struct pentry **) xcalloc(e->mem_obj->pending_list_size,
+       tmp = xcalloc(e->mem_obj->pending_list_size,
            sizeof(struct pentry *));
        for (j = 0; j < old_size; j++)
            tmp[j] = e->mem_obj->pending[j];
@@ -808,43 +906,42 @@ int storeUnregister(e, fd)
 int storeGetLowestReaderOffset(entry)
      StoreEntry *entry;
 {
-    MemObject *m = entry->mem_obj;
-    int lowest = m->e_current_len;
+    MemObject *mem = entry->mem_obj;
+    int lowest = mem->e_current_len;
     int i;
-    for (i = 0; i < m->client_list_size; i++) {
-       if (m->client_list[i] == NULL)
+    for (i = 0; i < mem->client_list_size; i++) {
+       if (mem->client_list[i] == NULL)
            continue;
-       if (m->client_list[i]->last_offset < lowest)
-           lowest = m->client_list[i]->last_offset;
+       if (mem->client_list[i]->last_offset < lowest)
+           lowest = mem->client_list[i]->last_offset;
     }
     return lowest;
 }
 
-
 /* Call to delete behind upto "target lowest offset"
  * also, update e_lowest_offset  */
 void storeDeleteBehind(e)
      StoreEntry *e;
 {
-    MemObject *m = e->mem_obj;
+    MemObject *mem = e->mem_obj;
     int free_up_to;
     int target_offset;
 
     debug(20, 3, "storeDeleteBehind: Object: %s\n", e->key);
     debug(20, 3, "storeDeleteBehind: Original Lowest Offset: %d\n",
-       m->e_lowest_offset);
+       mem->e_lowest_offset);
 
-    free_up_to = m->e_lowest_offset;
+    free_up_to = mem->e_lowest_offset;
     target_offset = storeGetLowestReaderOffset(e);
 
     debug(20, 3, "storeDeleteBehind: target offset: %d\n", target_offset);
     if (target_offset) {
-       free_up_to = (int) m->data->mem_free_data_upto(m->data, target_offset);
+       free_up_to = (int) mem->data->mem_free_data_upto(mem->data, target_offset);
        debug(20, 3, "--> Object is freed upto : %d\n", free_up_to);
-       store_mem_size -= free_up_to - m->e_lowest_offset;
+       store_mem_size -= free_up_to - mem->e_lowest_offset;
     }
     debug(20, 3, "storeDeleteBehind: New lowest offset: %d\n", free_up_to);
-    m->e_lowest_offset = free_up_to;
+    mem->e_lowest_offset = free_up_to;
 }
 
 /* Call handlers waiting for  data to be appended to E. */
@@ -954,7 +1051,6 @@ void storeAppendPrintf(va_alist)
     va_end(args);
 }
 
-
 /* add directory to swap disk */
 int storeAddSwapDisk(path)
      char *path;
@@ -1006,52 +1102,59 @@ int storeSwapInHandle(fd_notused, buf, len, flag, e, offset_notused)
      StoreEntry *e;
      int offset_notused;
 {
+    MemObject *mem = e->mem_obj;
     debug(20, 2, "storeSwapInHandle: '%s'\n", e->key);
 
     if ((flag < 0) && (flag != DISK_EOF)) {
        debug(20, 0, "storeSwapInHandle: SwapIn failure (err code = %d).\n", flag);
-       put_free_8k_page(e->mem_obj->e_swap_buf);
+       put_free_8k_page(mem->e_swap_buf);
        storeSetMemStatus(e, NOT_IN_MEMORY);
-       file_close(e->mem_obj->swap_fd);
+       file_close(mem->swap_fd);
        swapInError(-1, e);     /* Invokes storeAbort() and completes the I/O */
+       if (mem->swapin_complete_handler) {
+           (*mem->swapin_complete_handler) (2, mem->swapin_complete_data);
+           mem->swapin_complete_handler = NULL;
+           mem->swapin_complete_data = NULL;
+       }
        return -1;
     }
-    debug(20, 5, "storeSwapInHandle: e->swap_offset   = %d\n",
-       e->mem_obj->swap_offset);
-    debug(20, 5, "storeSwapInHandle: len              = %d\n",
-       len);
-    debug(20, 5, "storeSwapInHandle: e->e_current_len = %d\n",
-       e->mem_obj->e_current_len);
-    debug(20, 5, "storeSwapInHandle: e->object_len    = %d\n",
-       e->object_len);
+    debug(20, 5, "storeSwapInHandle: e->swap_offset   = %d\n", mem->swap_offset);
+    debug(20, 5, "storeSwapInHandle: len              = %d\n", len);
+    debug(20, 5, "storeSwapInHandle: e->e_current_len = %d\n", mem->e_current_len);
+    debug(20, 5, "storeSwapInHandle: e->object_len    = %d\n", e->object_len);
 
     /* always call these, even if len == 0 */
-    e->mem_obj->swap_offset += len;
+    mem->swap_offset += len;
     storeAppend(e, buf, len);
 
-    if (e->mem_obj->e_current_len < e->object_len && flag != DISK_EOF) {
+    if (mem->e_current_len < e->object_len && flag != DISK_EOF) {
        /* some more data to swap in, reschedule */
-       file_read(e->mem_obj->swap_fd,
-           e->mem_obj->e_swap_buf,
+       file_read(mem->swap_fd,
+           mem->e_swap_buf,
            SWAP_BUF,
-           e->mem_obj->swap_offset,
+           mem->swap_offset,
            (FILE_READ_HD) storeSwapInHandle,
            (void *) e);
     } else {
        /* complete swapping in */
        storeSetMemStatus(e, IN_MEMORY);
-       put_free_8k_page(e->mem_obj->e_swap_buf);
-       file_close(e->mem_obj->swap_fd);
+       put_free_8k_page(mem->e_swap_buf);
+       file_close(mem->swap_fd);
        storeLog(STORE_LOG_SWAPIN, e);
        debug(20, 5, "storeSwapInHandle: SwapIn complete: <URL:%s> from %s.\n",
            e->url, storeSwapFullPath(e->swap_file_number, NULL));
-       if (e->mem_obj->e_current_len != e->object_len) {
+       if (mem->e_current_len != e->object_len) {
            debug(20, 0, "storeSwapInHandle: WARNING! Object size mismatch.\n");
            debug(20, 0, "  --> <URL:%s>\n", e->url);
            debug(20, 0, "  --> Expecting %d bytes from file: %s\n", e->object_len,
                storeSwapFullPath(e->swap_file_number, NULL));
            debug(20, 0, "  --> Only read %d bytes\n",
-               e->mem_obj->e_current_len);
+               mem->e_current_len);
+       }
+       if (mem->swapin_complete_handler) {
+           (*mem->swapin_complete_handler) (0, mem->swapin_complete_data);
+           mem->swapin_complete_handler = NULL;
+           mem->swapin_complete_data = NULL;
        }
        if (e->flag & RELEASE_REQUEST)
            storeRelease(e);
@@ -1060,8 +1163,10 @@ int storeSwapInHandle(fd_notused, buf, len, flag, e, offset_notused)
 }
 
 /* start swapping in */
-int storeSwapInStart(e)
+static int storeSwapInStart(e, swapin_complete_handler, swapin_complete_data)
      StoreEntry *e;
+     SIH swapin_complete_handler;
+     void *swapin_complete_data;
 {
     int fd;
     char *path = NULL;
@@ -1079,10 +1184,7 @@ int storeSwapInStart(e)
 
     path = storeSwapFullPath(e->swap_file_number, NULL);
     if ((fd = file_open(path, NULL, O_RDONLY)) < 0) {
-       debug(20, 0, "storeSwapInStart: Unable to open swapfile: %s\n",
-           path);
-       debug(20, 0, "storeSwapInStart: --> for <URL:%s>\n",
-           e->url);
+       debug(20, 0, "storeSwapInStart: Failed for '%s'\n", e->url);
        storeSetMemStatus(e, NOT_IN_MEMORY);
        /* Invoke a store abort that should free the memory object */
        return -1;
@@ -1103,6 +1205,8 @@ int storeSwapInStart(e)
        e->mem_obj->swap_offset,
        (FILE_READ_HD) storeSwapInHandle,
        (void *) e);
+    e->mem_obj->swapin_complete_handler = swapin_complete_handler;
+    e->mem_obj->swapin_complete_data = swapin_complete_data;
     return 0;
 }
 
@@ -1126,7 +1230,7 @@ void storeSwapOutHandle(fd, flag, e)
        e->swap_status = NO_SWAP;
        put_free_8k_page(page_ptr);
        file_close(fd);
-       storeReleaseRequest(e);
+       storeRelease(e);
        if (e->swap_file_number != -1) {
            file_map_bit_reset(e->swap_file_number);
            safeunlink(filename, 0);    /* remove it */
@@ -1175,9 +1279,15 @@ void storeSwapOutHandle(fd, flag, e)
            swaplog_lock,
            NULL,
            NULL);
+       CacheInfo->proto_newobject(CacheInfo,
+           CacheInfo->proto_id(e->url),
+           e->object_len,
+           FALSE);
        /* check if it's request to be released. */
        if (e->flag & RELEASE_REQUEST)
            storeRelease(e);
+       else if (storeCheckPurgeMem(e))
+           storePurgeMem(e);
        return;
     }
     /* write some more data, reschedule itself. */
@@ -1269,138 +1379,142 @@ static int storeDoRebuildFromDisk(data)
     off_t size;
     int delta;
     int sfileno = 0;
-
-    if (!fgets(data->line_in, 4095, data->log))
-       return 0;
-
-    if ((++data->linecount & 0xFFF) == 0)
-       debug(20, 1, "  %7d Lines read so far.\n", data->linecount);
-
-    debug(20, 10, "line_in: %s", data->line_in);
-    if ((data->line_in[0] == '\0') || (data->line_in[0] == '\n') ||
-       (data->line_in[0] == '#'))
-       return 1;               /* skip bad lines */
-
-    url[0] = log_swapfile[0] = '\0';
-    expires = squid_curtime;
-
-    scan3 = 0;
-    size = 0;
-    if (sscanf(data->line_in, "%s %s %d %d %d",
-           log_swapfile, url, &scan1, &scan2, &scan3) != 5) {
-       if (opt_unlink_on_reload && log_swapfile[0])
-           safeunlink(log_swapfile, 0);
-       return 1;
-    }
-    expires = (time_t) scan1;
-    timestamp = (time_t) scan2;
-    size = (off_t) scan3;
-    if ((t = strrchr(log_swapfile, '/')))
-       sfileno = atoi(t + 1);
-    else
-       sfileno = atoi(log_swapfile);
-    storeSwapFullPath(sfileno, swapfile);
-
-    /*
-     * Note that swapfile may be different than log_swapfile if
-     * another cache_dir is added.
-     */
-
-    if (!data->fast_mode) {
-       if (stat(swapfile, &sb) < 0) {
-           if (expires < squid_curtime) {
-               debug(20, 3, "storeRebuildFromDisk: Expired: <URL:%s>\n", url);
-               if (opt_unlink_on_reload)
-                   safeunlink(swapfile, 1);
-               data->expcount++;
-           } else {
-               debug(20, 3, "storeRebuildFromDisk: Swap file missing: <URL:%s>: %s: %s.\n", url, swapfile, xstrerror());
+    int count;
+
+    /* load a number of objects per invocation */
+    for (count = 0; count < data->speed; count++) {
+       if (!fgets(data->line_in, 4095, data->log))
+           return 0;           /* We are done */
+
+       if ((++data->linecount & 0xFFF) == 0)
+           debug(20, 1, "  %7d Lines read so far.\n", data->linecount);
+
+       debug(20, 10, "line_in: %s", data->line_in);
+       if ((data->line_in[0] == '\0') || (data->line_in[0] == '\n') ||
+           (data->line_in[0] == '#'))
+           continue;           /* skip bad lines */
+
+       url[0] = log_swapfile[0] = '\0';
+       expires = squid_curtime;
+
+       scan3 = 0;
+       size = 0;
+       if (sscanf(data->line_in, "%s %s %d %d %d",
+               log_swapfile, url, &scan1, &scan2, &scan3) != 5) {
+           if (opt_unlink_on_reload && log_swapfile[0])
+               safeunlink(log_swapfile, 0);
+           continue;
+       }
+       expires = (time_t) scan1;
+       timestamp = (time_t) scan2;
+       size = (off_t) scan3;
+       if ((t = strrchr(log_swapfile, '/')))
+           sfileno = atoi(t + 1);
+       else
+           sfileno = atoi(log_swapfile);
+       storeSwapFullPath(sfileno, swapfile);
+
+       /*
+        * Note that swapfile may be different than log_swapfile if
+        * another cache_dir is added.
+        */
+
+       if (store_rebuilding != STORE_REBUILDING_FAST) {
+           if (stat(swapfile, &sb) < 0) {
+               if (expires < squid_curtime) {
+                   debug(20, 3, "storeRebuildFromDisk: Expired: <URL:%s>\n", url);
+                   if (opt_unlink_on_reload)
+                       safeunlink(swapfile, 1);
+                   data->expcount++;
+               } else {
+                   debug(20, 3, "storeRebuildFromDisk: Swap file missing: <URL:%s>: %s: %s.\n", url, swapfile, xstrerror());
+                   if (opt_unlink_on_reload)
+                       safeunlink(log_swapfile, 1);
+               }
+               continue;
+           }
+           /* Empty swap file? */
+           if (sb.st_size == 0) {
                if (opt_unlink_on_reload)
                    safeunlink(log_swapfile, 1);
+               continue;
            }
-           return 1;
-       }
-       /* Empty swap file? */
-       if (sb.st_size == 0) {
-           if (opt_unlink_on_reload)
-               safeunlink(log_swapfile, 1);
-           return 1;
-       }
-       /* timestamp might be a little bigger than sb.st_mtime */
-       delta = (int) (timestamp - sb.st_mtime);
-       if (delta > REBUILD_TIMESTAMP_DELTA_MAX || delta < 0) {
-           /* this log entry doesn't correspond to this file */
-           data->clashcount++;
-           return 1;
+           /* timestamp might be a little bigger than sb.st_mtime */
+           delta = (int) (timestamp - sb.st_mtime);
+           if (delta > REBUILD_TIMESTAMP_DELTA_MAX || delta < 0) {
+               /* this log entry doesn't correspond to this file */
+               data->clashcount++;
+               continue;
+           }
+           /* Wrong size? */
+           if (sb.st_size != size) {
+               /* this log entry doesn't correspond to this file */
+               data->clashcount++;
+               continue;
+           }
+           timestamp = sb.st_mtime;
+           debug(20, 10, "storeRebuildFromDisk: swap file exists: <URL:%s>: %s\n",
+               url, swapfile);
        }
-       /* Wrong size? */
-       if (sb.st_size != size) {
-           /* this log entry doesn't correspond to this file */
-           data->clashcount++;
-           return 1;
+       if ((e = storeGet(url))) {
+           if (e->timestamp > timestamp) {
+               /* already have a newer object in memory, throw old one away */
+               debug(20, 3, "storeRebuildFromDisk: Replaced: %s\n", url);
+               if (opt_unlink_on_reload)
+                   safeunlink(swapfile, 1);
+               data->dupcount++;
+               continue;
+           }
+           debug(20, 6, "storeRebuildFromDisk: Duplicate: <URL:%s>\n", url);
+           storeRelease(e);
+           data->objcount--;
+           data->dupcount++;
        }
-       timestamp = sb.st_mtime;
-       debug(20, 10, "storeRebuildFromDisk: swap file exists: <URL:%s>: %s\n",
-           url, swapfile);
-    }
-    if ((e = storeGet(url))) {
-       if (e->timestamp > timestamp) {
-           /* already have a newer object in memory, throw old one away */
-           debug(20, 3, "storeRebuildFromDisk: Replaced: %s\n", url);
+       if (expires < squid_curtime) {
+           debug(20, 3, "storeRebuildFromDisk: Expired: <URL:%s>\n", url);
            if (opt_unlink_on_reload)
                safeunlink(swapfile, 1);
-           data->dupcount++;
-           return 1;
+           data->expcount++;
+           continue;
        }
-       debug(20, 6, "storeRebuildFromDisk: Duplicate: <URL:%s>\n", url);
-       storeRelease(e);
-       data->objcount--;
-       data->dupcount++;
-    }
-    if (expires < squid_curtime) {
-       debug(20, 3, "storeRebuildFromDisk: Expired: <URL:%s>\n", url);
-       if (opt_unlink_on_reload)
-           safeunlink(swapfile, 1);
-       data->expcount++;
-       return 1;
-    }
-    /* Is the swap file number already taken? */
-    if (file_map_bit_test(sfileno)) {
-       /* Yes is is, we can't use this swapfile */
-       debug(20, 1, "storeRebuildFromDisk: Line %d Active clash: file #%d\n",
-           data->linecount,
-           sfileno);
-       debug(20, 3, "storeRebuildFromDisk: --> <URL:%s>\n", url);
-       /* don't unlink the file!  just skip this log entry */
-       data->clashcount++;
-       return 1;
+       /* Is the swap file number already taken? */
+       if (file_map_bit_test(sfileno)) {
+           /* Yes it is, we can't use this swapfile */
+           debug(20, 2, "storeRebuildFromDisk: Line %d Active clash: file #%d\n",
+               data->linecount,
+               sfileno);
+           debug(20, 3, "storeRebuildFromDisk: --> <URL:%s>\n", url);
+           /* don't unlink the file!  just skip this log entry */
+           data->clashcount++;
+           continue;
+       }
+       /* update store_swap_size */
+       store_swap_size += (int) ((size + 1023) >> 10);
+       data->objcount++;
+
+       sprintf(logmsg, "%s %s %d %d %d\n",
+           swapfile,
+           url,
+           (int) expires,
+           (int) timestamp,
+           (int) size);
+       /* Automatically freed by file_write because no-handlers */
+       file_write(swaplog_fd,
+           xstrdup(logmsg),
+           strlen(logmsg),
+           swaplog_lock,
+           NULL,
+           NULL);
+       storeAddDiskRestore(url,
+           sfileno,
+           (int) size,
+           expires,
+           timestamp);
+       CacheInfo->proto_newobject(CacheInfo,
+           CacheInfo->proto_id(url),
+           (int) size,
+           TRUE);
     }
-    /* update store_swap_size */
-    store_swap_size += (int) ((size + 1023) >> 10);
-    data->objcount++;
-
-    sprintf(logmsg, "%s %s %d %d %d\n",
-       swapfile,
-       url,
-       (int) expires,
-       (int) timestamp,
-       (int) size);
-    /* Automatically freed by file_write because no-handlers */
-    file_write(swaplog_fd,
-       xstrdup(logmsg),
-       strlen(logmsg),
-       swaplog_lock,
-       NULL,
-       NULL);
-    storeAddDiskRestore(url,
-       sfileno,
-       (int) size,
-       expires,
-       timestamp);
-    CacheInfo->proto_newobject(CacheInfo,
-       CacheInfo->proto_id(url),
-       (int) size,
-       TRUE);
 
     return 1;
 }
@@ -1424,7 +1538,7 @@ static void storeRebuiltFromDisk(data)
        r > 0 ? r : 0, (double) data->objcount / (r > 0 ? r : 1));
     debug(20, 1, "  store_swap_size = %dk\n", store_swap_size);
 
-    ok_write_clean_log = 1;
+    store_rebuilding = STORE_NOT_REBUILDING;
 
     fclose(data->log);
     safe_free(data);
@@ -1451,7 +1565,7 @@ void storeStartRebuildFromDisk()
 
     if (stat(swaplog_file, &sb) < 0) {
        debug(20, 1, "storeRebuildFromDisk: No log file\n");
-       ok_write_clean_log = 1;
+       store_rebuilding = STORE_NOT_REBUILDING;
        return;
     }
     data = xcalloc(1, sizeof(*data));
@@ -1465,8 +1579,11 @@ void storeStartRebuildFromDisk()
     if (stat(tmp_filename, &sb) >= 0) {
        last_clean = sb.st_mtime;
        if (stat(swaplog_file, &sb) >= 0)
-           data->fast_mode = (sb.st_mtime <= last_clean) ? 1 : 0;
+           store_rebuilding = (sb.st_mtime <= last_clean) ?
+               STORE_REBUILDING_FAST : STORE_REBUILDING_SLOW;
     }
+    /* Remove timestamp in case we crash during rebuild */
+    safeunlink(tmp_filename, 1);
     /* close the existing write-only swaplog, and open a temporary
      * write-only swaplog  */
     if (file_write_unlock(swaplog_fd, swaplog_lock) != DISK_OK)
@@ -1474,7 +1591,8 @@ void storeStartRebuildFromDisk()
     if (swaplog_fd > -1)
        file_close(swaplog_fd);
     sprintf(tmp_filename, "%s.new", swaplog_file);
-    swaplog_fd = file_open(tmp_filename, NULL, O_WRONLY | O_CREAT | O_APPEND);
+    swaplog_fd = file_open(tmp_filename, NULL,
+       O_WRONLY | O_CREAT | O_APPEND | O_TRUNC);
     debug(20, 3, "swaplog_fd %d is now '%s'\n", swaplog_fd, tmp_filename);
     if (swaplog_fd < 0) {
        debug(20, 0, "storeStartRebuildFromDisk: %s: %s\n",
@@ -1489,16 +1607,22 @@ void storeStartRebuildFromDisk()
        fatal(tmp_error_buf);
     }
     debug(20, 3, "data->log %d is now '%s'\n", fileno(data->log), swaplog_file);
-    if (data->fast_mode)
+    if (store_rebuilding == STORE_REBUILDING_FAST)
        debug(20, 1, "Rebuilding in FAST MODE.\n");
 
     memset(data->line_in, '\0', 4096);
+    data->speed = store_rebuilding == STORE_REBUILDING_FAST ? 50 : 5;
 
     /* Start reading the log file */
-    runInBackground("storeRebuild",
-       (int (*)(void *)) storeDoRebuildFromDisk,
-       data,
-       (void (*)(void *)) storeRebuiltFromDisk);
+    if (opt_foreground_rebuild) {
+       while (storeDoRebuildFromDisk(data));
+       storeRebuiltFromDisk(data);
+    } else {
+       runInBackground("storeRebuild",
+           (int (*)(void *)) storeDoRebuildFromDisk,
+           data,
+           (void (*)(void *)) storeRebuiltFromDisk);
+    }
 }
 
 /* return current swap size in kilo-bytes */
@@ -1553,8 +1677,6 @@ void storeComplete(e)
        storeSwapOutStart(e);
     /* free up incoming MIME */
     safe_free(e->mem_obj->mime_hdr);
-    CacheInfo->proto_newobject(CacheInfo, CacheInfo->proto_id(e->url),
-       e->object_len, FALSE);
     if (e->flag & RELEASE_REQUEST)
        storeRelease(e);
 }
@@ -1583,7 +1705,7 @@ int storeAbort(e, msg)
      */
     BIT_SET(e->flag, ENTRY_DISPATCHED);
 
-    storeLockObject(e);
+    storeLockObject(e, NULL, NULL);
 
     /* Count bytes faulted through cache but not moved to disk */
     CacheInfo->proto_touchobject(CacheInfo, CacheInfo->proto_id(e->url),
@@ -2054,17 +2176,31 @@ int storeGetSwapSpace(size)
            break;
     }                          /* for */
 
+#ifdef LOTSA_DEBUGGING
     /* end of candidate selection */
-    debug(20, 2, "storeGetSwapSpace: Current Size:   %7d kbytes\n", store_swap_size);
-    debug(20, 2, "storeGetSwapSpace: High W Mark:    %7d kbytes\n", store_swap_high);
-    debug(20, 2, "storeGetSwapSpace: Low W Mark:     %7d kbytes\n", store_swap_low);
-    debug(20, 2, "storeGetSwapSpace: Entry count:    %7d items\n", meta_data.store_entries);
-    debug(20, 2, "storeGetSwapSpace: Scanned:        %7d items\n", scanned);
-    debug(20, 2, "storeGetSwapSpace: Expired:        %7d items\n", expired);
-    debug(20, 2, "storeGetSwapSpace: Locked:         %7d items\n", locked);
-    debug(20, 2, "storeGetSwapSpace: Locked Space:   %7d bytes\n", locked_size);
-    debug(20, 2, "storeGetSwapSpace: Scan in array:  %7d bytes\n", scan_in_objs);
-    debug(20, 2, "storeGetSwapSpace: LRU candidate:  %7d items\n", LRU_list->index);
+    debug(20, 2, "storeGetSwapSpace: Current Size:   %7d kbytes\n",
+       store_swap_size);
+    debug(20, 2, "storeGetSwapSpace: High W Mark:    %7d kbytes\n",
+       store_swap_high);
+    debug(20, 2, "storeGetSwapSpace: Low W Mark:     %7d kbytes\n",
+       store_swap_low);
+    debug(20, 2, "storeGetSwapSpace: Entry count:    %7d items\n",
+       meta_data.store_entries);
+    debug(20, 2, "storeGetSwapSpace: Visited:        %7d buckets\n",
+       i + 1);
+    debug(20, 2, "storeGetSwapSpace: Scanned:        %7d items\n",
+       scanned);
+    debug(20, 2, "storeGetSwapSpace: Expired:        %7d items\n",
+       expired);
+    debug(20, 2, "storeGetSwapSpace: Locked:         %7d items\n",
+       locked);
+    debug(20, 2, "storeGetSwapSpace: Locked Space:   %7d bytes\n",
+       locked_size);
+    debug(20, 2, "storeGetSwapSpace: Scan in array:  %7d bytes\n",
+       scan_in_objs);
+    debug(20, 2, "storeGetSwapSpace: LRU candidate:  %7d items\n",
+       LRU_list->index);
+#endif /* LOTSA_DEBUGGING */
 
     /* Although all expired objects removed, still didn't recover enough */
     /* space.  Kick LRU out until we have enough swap space */
@@ -2104,7 +2240,8 @@ int storeGetSwapSpace(size)
        swap_help = 0;
     }
 
-    debug(20, 2, "storeGetSwapSpace: Finished, %d objects removed.\n", removed);
+    getCurrentTime();          /* we may have taken more than one second */
+    debug(20, 2, "Removed %d objects\n", removed);
     return 0;
 }
 
@@ -2156,25 +2293,31 @@ int storeRelease(e)
            }
        }
     }
+    if (store_rebuilding == STORE_REBUILDING_FAST) {
+       debug(20, 2, "storeRelease: Delaying release until store is rebuilt: '%s'\n",
+           e->key ? e->key : e->url ? e->url : "NO URL");
+       storeExpireNow(e);
+       storeSetPrivateKey(e);
+       return -1;
+    }
     if (e->key)
        debug(20, 5, "storeRelease: Release object key: %s\n", e->key);
     else
        debug(20, 5, "storeRelease: Release anonymous object\n");
 
     if (e->swap_status == SWAP_OK && (e->swap_file_number > -1)) {
-       (void) safeunlink(storeSwapFullPath(e->swap_file_number, NULL), 0);
+       (void) safeunlink(storeSwapFullPath(e->swap_file_number, NULL), 1);
        file_map_bit_reset(e->swap_file_number);
        e->swap_file_number = -1;
        store_swap_size -= (e->object_len + 1023) >> 10;
+       CacheInfo->proto_purgeobject(CacheInfo,
+           CacheInfo->proto_id(e->url),
+           e->object_len);
     }
-    /* Discard byte count */
-    CacheInfo->proto_purgeobject(CacheInfo,
-       CacheInfo->proto_id(e->url),
-       e->object_len);
     if (hptr)
        storeHashDelete(hptr);
     storeLog(STORE_LOG_RELEASE, e);
-    storeFreeEntry(e);
+    destroy_StoreEntry(e);
     return 0;
 }
 
@@ -2197,11 +2340,13 @@ int storeEntryLocked(e)
        debug(20, 0, "%s", storeToString(e));
        fatal_dump(NULL);
     }
-    return ((e->lock_count) ||
-       (e->store_status == STORE_PENDING) ||
-       (e->swap_status == SWAPPING_OUT) ||
-       (e->mem_status == SWAPPING_IN)
-       );
+    if (e->lock_count)
+       return 1;
+    if (e->swap_status == SWAPPING_OUT)
+       return 1;
+    if (e->mem_status == SWAPPING_IN)
+       return 1;
+    return 0;
 }
 
 /*  use this for internal call only */
@@ -2291,15 +2436,15 @@ void storeClientListAdd(e, fd, last_offset)
        if (i == e->mem_obj->client_list_size) {
            /* have to expand client_list */
            e->mem_obj->client_list_size += MIN_CLIENT;
-           e->mem_obj->client_list = (ClientStatusEntry **) xrealloc(e->mem_obj->client_list, e->mem_obj->client_list_size * sizeof(ClientStatusEntry *));
+           e->mem_obj->client_list = xrealloc(e->mem_obj->client_list, e->mem_obj->client_list_size * sizeof(ClientStatusEntry *));
        }
     } else {
        e->mem_obj->client_list_size += MIN_CLIENT;
-       e->mem_obj->client_list = (ClientStatusEntry **) xcalloc(e->mem_obj->client_list_size, sizeof(ClientStatusEntry *));
+       e->mem_obj->client_list = xcalloc(e->mem_obj->client_list_size, sizeof(ClientStatusEntry *));
        i = 0;
     }
 
-    e->mem_obj->client_list[i] = (ClientStatusEntry *) xcalloc(1, sizeof(ClientStatusEntry));
+    e->mem_obj->client_list[i] = xcalloc(1, sizeof(ClientStatusEntry));
     e->mem_obj->client_list[i]->fd = fd;
     e->mem_obj->client_list[i]->last_offset = last_offset;
 }
@@ -2356,9 +2501,20 @@ int storeClientCopy(e, stateoffset, maxSize, buf, size, fd)
 int storeEntryValidToSend(e)
      StoreEntry *e;
 {
+    /* XXX I think this is not needed since storeCheckPurgeMem() has
+     * been added.  If we never see output from this, lets delete it
+     * in a future version -DW */
+    if ((e->mem_status == NOT_IN_MEMORY) &&    /* Not in memory */
+       (e->swap_status != SWAP_OK) &&  /* Not on disk */
+       (e->store_status != STORE_PENDING)      /* Not being fetched */
+       ) {
+       debug(20, 0, "storeEntryValidToSend: Invalid object detected!\n");
+       debug(20, 0, "storeEntryValidToSend: Entry Dump:\n%s\n", storeToString(e));
+       return 0;
+    }
     if (squid_curtime < e->expires)
        return 1;
-    if (e->expires == 0 && e->store_status == STORE_PENDING)
+    if (e->expires == 0 && e->store_status == STORE_PENDING && e->mem_status != NOT_IN_MEMORY)
        return 1;
     return 0;
 }
@@ -2497,12 +2653,10 @@ int storeInit()
     }
     swaplog_lock = file_write_lock(swaplog_fd);
 
-    if (!zap_disk_store) {
-       ok_write_clean_log = 0;
+    if (!zap_disk_store)
        storeStartRebuildFromDisk();
-    } else {
-       ok_write_clean_log = 1;
-    }
+    else
+       store_rebuilding = STORE_NOT_REBUILDING;
 
     if (dir_created || zap_disk_store)
        storeCreateSwapSubDirs();
@@ -2569,21 +2723,6 @@ int urlcmp(url1, url2)
     return (strcmp(url1, url2));
 }
 
-int parse_file_number(s)
-     char *s;
-{
-    int len;
-
-
-    for (len = strlen(s); (len >= 0); --len) {
-       if (s[len] == '/') {
-           return (atoi(&s[len + 1]));
-       }
-    }
-    debug(20, 1, "parse_file_number: Could not determine the swap file number from %s.\n", s);
-    return (0);
-}
-
 /* 
  * This routine is to be called by main loop in main.c.
  * It removes expired objects on only one bucket for each time called.
@@ -2593,19 +2732,23 @@ int parse_file_number(s)
  */
 int storeMaintainSwapSpace()
 {
-    static int loop_count = 0;
+    static time_t last_time = 0;
     static unsigned int bucket = 0;
     hash_link *link_ptr = NULL, *next = NULL;
     StoreEntry *e = NULL;
     int rm_obj = 0;
 
+    /* We can't delete objects while rebuilding swap */
+    if (store_rebuilding == STORE_REBUILDING_FAST)
+       return -1;
+
     /* Scan row of hash table each second and free storage if we're
      * over the high-water mark */
     storeGetSwapSpace(0);
 
     /* Purges expired objects, check one bucket on each calling */
-    if (loop_count++ >= STORE_MAINTAIN_RATE) {
-       loop_count = 0;
+    if (squid_curtime - last_time >= STORE_MAINTAIN_RATE) {
+       last_time = squid_curtime;
        if (bucket >= STORE_BUCKETS)
            bucket = 0;
        link_ptr = hash_get_bucket(table, bucket++);
@@ -2625,6 +2768,7 @@ int storeMaintainSwapSpace()
            link_ptr = next;
        }
     }
+    debug(20, rm_obj ? 2 : 3, "Removed %d expired objects\n", rm_obj);
     return rm_obj;
 }
 
@@ -2640,9 +2784,10 @@ int storeWriteCleanLog()
     static char swapfilename[MAX_FILE_NAME_LEN];
     FILE *fp = NULL;
     int n = 0;
+    int x = 0;
     time_t start, stop, r;
 
-    if (!ok_write_clean_log) {
+    if (store_rebuilding) {
        debug(20, 1, "storeWriteCleanLog: Not currently OK to rewrite swap log.\n");
        debug(20, 1, "storeWriteCleanLog: Operation aborted.\n");
        return 0;
@@ -2663,16 +2808,27 @@ int storeWriteCleanLog()
        if (e->object_len <= 0)
            continue;
        storeSwapFullPath(e->swap_file_number, swapfilename);
-       fprintf(fp, "%s %s %d %d %d\n",
+       x = fprintf(fp, "%s %s %d %d %d\n",
            swapfilename, e->url, (int) e->expires, (int) e->timestamp,
            e->object_len);
+       if (x < 0) {
+           debug(20, 0, "storeWriteCleanLog: %s: %s", tmp_filename, xstrerror());
+           debug(20, 0, "storeWriteCleanLog: Current swap logfile not replaced.\n");
+           fclose(fp);
+           safeunlink(tmp_filename, 0);
+           return 0;
+       }
        if ((++n & 0xFFF) == 0) {
            getCurrentTime();
            debug(20, 1, "  %7d lines written so far.\n", n);
        }
     }
-    fclose(fp);
-
+    if (fclose(fp) < 0) {
+       debug(20, 0, "storeWriteCleanLog: %s: %s", tmp_filename, xstrerror());
+       debug(20, 0, "storeWriteCleanLog: Current swap logfile not replaced.\n");
+       safeunlink(tmp_filename, 0);
+       return 0;
+    }
     if (file_write_unlock(swaplog_fd, swaplog_lock) != DISK_OK) {
        debug(20, 0, "storeWriteCleanLog: Failed to unlock swaplog!\n");
        debug(20, 0, "storeWriteCleanLog: Current swap logfile not replaced.\n");
@@ -2763,3 +2919,20 @@ void storeRotateLog()
        debug(20, 1, "Store logging disabled\n");
     }
 }
+
+/*
+ * Check if its okay to remove the memory data for this object, but 
+ * leave the StoreEntry around.  Designed to be called from
+ * storeUnlockObject() and storeSwapOutHandle().
+ */
+static int storeCheckPurgeMem(e)
+     StoreEntry *e;
+{
+    if (storeEntryLocked(e))
+       return 0;
+    if (e->store_status != STORE_OK)
+       return 0;
+    if (store_hotobj_high)
+       return 0;
+    return 1;
+}
index 1e2c2a36340e4def89d53588f1af19536c1fc552..9656af14e2f7edbe3c102469e93646a0bac60cd4 100644 (file)
@@ -1,8 +1,106 @@
-
-/* $Id: tools.cc,v 1.42 1996/05/01 22:36:41 wessels Exp $ */
+/*
+ * $Id: tools.cc,v 1.43 1996/07/09 03:41:45 wessels Exp $
+ *
+ * DEBUG: section 21    Misc Functions
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 21          tools
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
@@ -11,8 +109,6 @@ int do_mallinfo = 0;         /* don't do mallinfo() unless this gets set */
 time_t squid_curtime;
 struct timeval current_time;
 
-extern void serverConnectionsClose _PARAMS((void));
-
 #define DEAD_MSG "\
 The Squid Cache (version %s) died.\n\
 \n\
@@ -63,52 +159,65 @@ static void dumpMallocStats(f)
 {
 #if HAVE_MALLINFO
     struct mallinfo mp;
-
+    int t;
     if (!do_mallinfo)
        return;
-
     mp = mallinfo();
-
-    fprintf(f, "Malloc Instrumentation via mallinfo(): \n");
-    fprintf(f, "   total space in arena  %d\n", mp.arena);
-    fprintf(f, "   number of ordinary blocks  %d\n", mp.ordblks);
-    fprintf(f, "   number of small blocks  %d\n", mp.smblks);
-    fprintf(f, "   number of holding blocks  %d\n", mp.hblks);
-    fprintf(f, "   space in holding block headers  %d\n", mp.hblkhd);
-    fprintf(f, "   space in small blocks in use  %d\n", mp.usmblks);
-    fprintf(f, "   space in free blocks  %d\n", mp.fsmblks);
-    fprintf(f, "   space in ordinary blocks in use  %d\n", mp.uordblks);
-    fprintf(f, "   space in free ordinary blocks  %d\n", mp.fordblks);
-    fprintf(f, "   cost of enabling keep option  %d\n", mp.keepcost);
+    fprintf(f, "Memory usage for %s via mallinfo():\n", appname);
+    fprintf(f, "\ttotal space in arena:  %6d KB\n",
+       mp.arena >> 10);
+    fprintf(f, "\tOrdinary blocks:       %6d KB %6d blks\n",
+       mp.uordblks >> 10, mp.ordblks);
+    fprintf(f, "\tSmall blocks:          %6d KB %6d blks\n",
+       mp.usmblks >> 10, mp.smblks);
+    fprintf(f, "\tHolding blocks:        %6d KB %6d blks\n",
+       mp.hblkhd >> 10, mp.hblks);
+    fprintf(f, "\tFree Small blocks:     %6d KB\n",
+       mp.fsmblks >> 10);
+    fprintf(f, "\tFree Ordinary blocks:  %6d KB\n",
+       mp.fordblks >> 10);
+    t = mp.uordblks + mp.usmblks + mp.hblkhd;
+    fprintf(f, "\tTotal in use:          %6d KB %d%%\n",
+       t >> 10, percent(t, mp.arena));
+    t = mp.fsmblks + mp.fordblks;
+    fprintf(f, "\tTotal free:            %6d KB %d%%\n",
+       t >> 10, percent(t, mp.arena));
+#ifdef WE_DONT_USE_KEEP
+    fprintf(f, "\tKeep option:           %6d KB\n",
+       mp.keepcost >> 10);
+#endif
 #if HAVE_EXT_MALLINFO
-    fprintf(f, "   max size of small blocks  %d\n", mp.mxfast);
-    fprintf(f, "   number of small blocks in a holding block  %d\n",
+    fprintf(f, "\tmax size of small blocks:\t%d\n",
+       mp.mxfast);
+    fprintf(f, "\tnumber of small blocks in a holding block:\t%d\n",
        mp.nlblks);
-    fprintf(f, "   small block rounding factor  %d\n", mp.grain);
-    fprintf(f, "   space (including overhead) allocated in ord. blks  %d\n",
+    fprintf(f, "\tsmall block rounding factor:\t%d\n",
+       mp.grain);
+    fprintf(f, "\tspace (including overhead) allocated in ord. blks:\t%d\n",
        mp.uordbytes);
-    fprintf(f, "   number of ordinary blocks allocated  %d\n",
+    fprintf(f, "\tnumber of ordinary blocks allocated:\t%d\n",
        mp.allocated);
-    fprintf(f, "   bytes used in maintaining the free tree  %d\n",
+    fprintf(f, "\tbytes used in maintaining the free tree:\t%d\n",
        mp.treeoverhead);
 #endif /* HAVE_EXT_MALLINFO */
-
 #if PRINT_MMAP
     mallocmap();
 #endif /* PRINT_MMAP */
 #endif /* HAVE_MALLINFO */
 }
+
 static int PrintRusage(f, lf)
      void (*f) ();
      FILE *lf;
 {
-#if HAVE_RUSAGE && defined(RUSAGE_SELF)
+#if HAVE_GETRUSAGE && defined(RUSAGE_SELF)
     struct rusage rusage;
     getrusage(RUSAGE_SELF, &rusage);
-    fprintf(lf, "CPU Usage: user %d sys %d\nMemory Usage: rss %d KB\n",
-       rusage.ru_utime.tv_sec, rusage.ru_stime.tv_sec,
-       rusage.ru_maxrss * getpagesize() / 1000);
-    fprintf(lf, "Page faults with physical i/o: %d\n",
+    fprintf(lf, "CPU Usage: user %d sys %d\n",
+       (int) rusage.ru_utime.tv_sec, (int) rusage.ru_stime.tv_sec);
+    fprintf(lf, "Memory Usage: rss %ld KB\n",
+       rusage.ru_maxrss * getpagesize() >> 10);
+    fprintf(lf, "Page faults with physical i/o: %ld\n",
        rusage.ru_majflt);
 #endif
     dumpMallocStats(lf);
@@ -126,9 +235,11 @@ void death(sig)
        fprintf(debug_log, "FATAL: Received bus error...dying.\n");
     else
        fprintf(debug_log, "FATAL: Received signal %d...dying.\n", sig);
+#if !HAVE_SIGACTION
     signal(SIGSEGV, SIG_DFL);
     signal(SIGBUS, SIG_DFL);
     signal(sig, SIG_DFL);
+#endif
     storeWriteCleanLog();
     PrintRusage(NULL, debug_log);
     print_warranty();
@@ -136,28 +247,49 @@ void death(sig)
 }
 
 
-void rotate_logs(sig)
+void sigusr2_handle(sig)
      int sig;
 {
-    debug(21, 1, "rotate_logs: SIGUSR1 received.\n");
-
-    storeWriteCleanLog();
-    storeRotateLog();
-    neighbors_rotate_log();
-    stat_rotate_log();
-    _db_rotate_log();
-#if RESET_SIGNAL_HANDLER
-    signal(sig, rotate_logs);
+    static int state = 0;
+    debug(21, 1, "sigusr2_handle: SIGUSR2 received.\n");
+    if (state == 0) {
+       _db_init(getCacheLogFile(), "ALL,10");
+       state = 1;
+    } else {
+       _db_init(getCacheLogFile(), getDebugOptions());
+       state = 0;
+    }
+#if !HAVE_SIGACTION
+    signal(sig, sigusr2_handle);       /* reinstall */
 #endif
 }
 
+void setSocketShutdownLifetimes()
+{
+    FD_ENTRY *f = NULL;
+    int lft = getShutdownLifetime();
+    int cur;
+    int i;
+    for (i = fdstat_biggest_fd(); i >= 0; i--) {
+       f = &fd_table[i];
+       if (!f->read_handler && !f->write_handler && !f->except_handler)
+           continue;
+       if (fdstatGetType(i) != FD_SOCKET)
+           continue;
+       cur = comm_get_fd_lifetime(i);
+       if (cur > 0 && (cur - squid_curtime) <= lft)
+           continue;
+       comm_set_fd_lifetime(i, lft);
+    }
+}
+
 void normal_shutdown()
 {
     debug(21, 1, "Shutting down...\n");
     if (getPidFilename()) {
-       get_suid();
+       enter_suid();
        safeunlink(getPidFilename(), 0);
-       check_suid();
+       leave_suid();
     }
     storeWriteCleanLog();
     PrintRusage(NULL, debug_log);
@@ -165,26 +297,6 @@ void normal_shutdown()
        version_string);
     exit(0);
 }
-void shut_down(sig)
-     int sig;
-{
-    int i;
-    int lft = getShutdownLifetime();
-    FD_ENTRY *f;
-    debug(21, 1, "Preparing for shutdown after %d connections\n",
-       ntcpconn + nudpconn);
-    serverConnectionsClose();
-    ipcacheShutdownServers();
-    ftpServerClose();
-    for (i = fdstat_biggest_fd(); i >= 0; i--) {
-       f = &fd_table[i];
-       if (f->read_handler || f->write_handler || f->except_handler)
-           if (fdstatGetType(i) == Socket)
-               comm_set_fd_lifetime(i, lft);
-    }
-    shutdown_pending = 1;
-    /* reinstall signal handler? */
-}
 
 void fatal_common(message)
      char *message;
@@ -219,66 +331,30 @@ void fatal_dump(message)
     abort();
 }
 
-
-int getHeapSize()
-{
-#if HAVE_MALLINFO
-    struct mallinfo mp;
-
-    mp = mallinfo();
-
-    return (mp.arena);
-#else
-    return (0);
-#endif
-}
-
 void sig_child(sig)
      int sig;
 {
+#ifdef _SQUID_NEXT_
+    union wait status;
+#else
     int status;
-    int pid;
-
-    if ((pid = waitpid(-1, &status, WNOHANG)) > 0)
-       debug(21, 3, "sig_child: Ate pid %d\n", pid);
-
-#if RESET_SIGNAL_HANDLER
-    signal(sig, sig_child);
 #endif
-}
+    int pid;
 
-#ifdef OLD_CODE
-/*
- *  getMaxFD - returns the file descriptor table size
- */
-int getMaxFD()
-{
-    static int i = -1;
-
-    if (i == -1) {
-#if HAVE_SYSCONF && defined(_SC_OPEN_MAX)
-       i = sysconf(_SC_OPEN_MAX);      /* prefered method */
-#elif HAVE_GETDTABLESIZE
-       i = getdtablesize();    /* the BSD way */
-#elif defined(OPEN_MAX)
-       i = OPEN_MAX;
-#elif defined(NOFILE)
-       i = NOFILE;
-#elif defined(_NFILE)
-       i = _NFILE;
+    do {
+#ifdef _SQUID_NEXT_
+       pid = wait3(&status, WNOHANG, NULL);
 #else
-       i = 64;                 /* 64 is a safe default */
+       pid = waitpid(-1, &status, WNOHANG);
 #endif
-       debug(21, 10, "getMaxFD set MaxFD at %d\n", i);
-    }
-    return (i);
-}
+       debug(21, 3, "sig_child: Ate pid %d\n", pid);
+#if HAVE_SIGACTION
+    } while (pid > 0);
 #else
-int getMaxFD()
-{
-    return FD_SETSIZE;
-}
+    } while (pid > 0 || (pid < 0 && errno == EINTR));
+    signal(sig, sig_child);
 #endif
+}
 
 char *getMyHostname()
 {
@@ -298,7 +374,7 @@ char *getMyHostname()
                xstrerror());
            return NULL;
        } else {
-           if ((h = ipcache_gethostbyname(host)) != NULL) {
+           if ((h = ipcache_gethostbyname(host, IP_BLOCKING_LOOKUP)) != NULL) {
                /* DNS lookup successful */
                /* use the official name from DNS lookup */
                strcpy(host, h->h_name);
@@ -320,31 +396,16 @@ int safeunlink(s, quiet)
     return (err);
 }
 
-/* 
- * Daemonize a process according to guidlines in "Advanced Programming
- * For The UNIX Environment", W.R. Stevens ( Addison Wesley, 1992) - Ch. 13
+/* leave a privilegied section. (Give up any privilegies)
+ * Routines that need privilegies can rap themselves in enter_suid()
+ * and leave_suid()
+ * To give upp all posibilites to gain privilegies use no_suid()
  */
-int daemonize()
-{
-    int n_openf, i;
-    pid_t pid;
-    if ((pid = fork()) < 0)
-       return -1;
-    else if (pid != 0)
-       exit(0);
-    /* Child continues */
-    setsid();                  /* Become session leader */
-    n_openf = getMaxFD();      /* Close any inherited files */
-    for (i = 0; i < n_openf; i++)
-       close(i);
-    umask(0);                  /* Clear file mode creation mask */
-    return 0;
-}
-
-void check_suid()
+void leave_suid()
 {
     struct passwd *pwd = NULL;
     struct group *grp = NULL;
+    debug(21, 3, "leave_suid: PID %d called\n", getpid());
     if (geteuid() != 0)
        return;
     /* Started as a root, check suid option */
@@ -357,6 +418,8 @@ void check_suid()
     } else {
        setgid(pwd->pw_gid);
     }
+    debug(21, 3, "leave_suid: PID %d giving up root, becoming '%s'\n",
+       getpid(), pwd->pw_name);
 #if HAVE_SETRESUID
     setresuid(pwd->pw_uid, pwd->pw_uid, 0);
 #elif HAVE_SETEUID
@@ -366,8 +429,10 @@ void check_suid()
 #endif
 }
 
-void get_suid()
+/* Enter a privilegied section */
+void enter_suid()
 {
+    debug(21, 3, "enter_suid: PID %d taking root priveleges\n", getpid());
 #if HAVE_SETRESUID
     setresuid(-1, 0, -1);
 #else
@@ -375,11 +440,15 @@ void get_suid()
 #endif
 }
 
+/* Give up the posibility to gain privilegies.
+ * this should be used before starting a sub process
+ */
 void no_suid()
 {
     uid_t uid;
-    check_suid();
+    leave_suid();
     uid = geteuid();
+    debug(21, 3, "leave_suid: PID %d giving up root priveleges forever\n", getpid());
 #if HAVE_SETRESUID
     setresuid(uid, uid, uid);
 #else
@@ -395,13 +464,16 @@ void writePidFile()
 
     if ((f = getPidFilename()) == NULL)
        return;
-    if ((pid_fp = fopen(f, "w")) == NULL) {
+    enter_suid();
+    pid_fp = fopen(f, "w");
+    leave_suid();
+    if (pid_fp != NULL) {
+       fprintf(pid_fp, "%d\n", (int) getpid());
+       fclose(pid_fp);
+    } else {
        debug(21, 0, "WARNING: Could not write pid file\n");
        debug(21, 0, "         %s: %s\n", f, xstrerror());
-       return;
     }
-    fprintf(pid_fp, "%d\n", (int) getpid());
-    fclose(pid_fp);
 }
 
 
@@ -416,6 +488,8 @@ void setMaxFD()
        debug(21, 0, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
     } else {
        rl.rlim_cur = FD_SETSIZE;
+       if (rl.rlim_cur > rl.rlim_max)
+           rl.rlim_cur = rl.rlim_max;
        if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
            sprintf(tmp_error_buf, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
            fatal_dump(tmp_error_buf);
@@ -426,6 +500,8 @@ void setMaxFD()
        debug(21, 0, "setrlimit: RLIMIT_NOFILE: %s", xstrerror());
     } else {
        rl.rlim_cur = FD_SETSIZE;
+       if (rl.rlim_cur > rl.rlim_max)
+           rl.rlim_cur = rl.rlim_max;
        if (setrlimit(RLIMIT_OFILE, &rl) < 0) {
            sprintf(tmp_error_buf, "setrlimit: RLIMIT_OFILE: %s", xstrerror());
            fatal_dump(tmp_error_buf);
@@ -434,36 +510,29 @@ void setMaxFD()
 #endif
 #else /* HAVE_SETRLIMIT */
     debug(21, 1, "setMaxFD: Cannot increase: setrlimit() not supported on this system");
-#endif
+#endif /* HAVE_SETRLIMIT */
+
+#if HAVE_SETRLIMIT && defined(RLIMIT_DATA)
+    if (getrlimit(RLIMIT_DATA, &rl) < 0) {
+       debug(21, 0, "getrlimit: RLIMIT_DATA: %s", xstrerror());
+    } else {
+       rl.rlim_cur = rl.rlim_max;      /* set it to the max */
+       if (setrlimit(RLIMIT_DATA, &rl) < 0) {
+           sprintf(tmp_error_buf, "setrlimit: RLIMIT_DATA: %s", xstrerror());
+           fatal_dump(tmp_error_buf);
+       }
+    }
+#endif /* RLIMIT_DATA */
 }
 
 time_t getCurrentTime()
 {
+#if defined(_SQUID_MOTOROLA_)
+    gettimeofday(&current_time);
+#else
     gettimeofday(&current_time, NULL);
-    return squid_curtime = current_time.tv_sec;
-}
-
-
-void reconfigure(sig)
-     int sig;
-{
-    int i;
-    int lft = getShutdownLifetime();
-    FD_ENTRY *f;
-    debug(21, 1, "reconfigure: SIGHUP received.\n");
-    serverConnectionsClose();
-    ipcacheShutdownServers();
-    ftpServerClose();
-    reread_pending = 1;
-    for (i = fdstat_biggest_fd(); i >= 0; i--) {
-       f = &fd_table[i];
-       if (f->read_handler || f->write_handler || f->except_handler)
-           if (fdstatGetType(i) == Socket)
-               comm_set_fd_lifetime(i, lft);
-    }
-#if RESET_SIGNAL_HANDLER
-    signal(sig, reconfigure);
 #endif
+    return squid_curtime = current_time.tv_sec;
 }
 
 int tvSubMsec(t1, t2)
@@ -473,3 +542,27 @@ int tvSubMsec(t1, t2)
     return (t2.tv_sec - t1.tv_sec) * 1000 +
        (t2.tv_usec - t1.tv_usec) / 1000;
 }
+
+int percent(a, b)
+     int a;
+     int b;
+{
+    return b ? ((int) (100.0 * a / b + 0.5)) : 0;
+}
+
+void squid_signal(sig, func, flags)
+     int sig;
+     void (*func) ();
+     int flags;
+{
+#if HAVE_SIGACTION
+    struct sigaction sa;
+    sa.sa_handler = func;
+    sa.sa_flags = flags;
+    sigemptyset(&sa.sa_mask);
+    if (sigaction(sig, &sa, NULL) < 0)
+       debug(1, 0, "sigaction: sig=%d func=%p: %s\n", sig, func, xstrerror());
+#else
+    (void) signal(sig, func);
+#endif
+}
index 17ef2c064527ddfd9cbf6b7df2f6d04474d73b7a..a400a3e5dabd36238f02fab3ef8ae90b1f89309e 100644 (file)
@@ -1,11 +1,34 @@
 /*
- *  $Id: tunnel.cc,v 1.2 1996/05/03 22:56:31 wessels Exp $ 
+ * $Id: tunnel.cc,v 1.3 1996/07/09 03:41:39 wessels Exp $
  *
- * DEBUG: Section 26                    ssl
+ * DEBUG: section 26    Secure Sockets Layer Proxy
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
-#include "squid.h"
 
-#define SSL_BUFSIZ (1<<14)
+#include "squid.h"
 
 typedef struct {
     char *url;
@@ -30,7 +53,40 @@ static void sslReadClient _PARAMS((int fd, SslStateData * sslState));
 static void sslWriteServer _PARAMS((int fd, SslStateData * sslState));
 static void sslWriteClient _PARAMS((int fd, SslStateData * sslState));
 static void sslConnected _PARAMS((int fd, SslStateData * sslState));
+static int sslConnect _PARAMS((int fd, struct hostent *, SslStateData *));
 static void sslConnInProgress _PARAMS((int fd, SslStateData * sslState));
+static void sslErrorComplete _PARAMS((int, char *, int, int, void *));
+static void sslClose _PARAMS((SslStateData * sslState));
+static int sslClientClosed _PARAMS((int fd, SslStateData * sslState));
+
+static void sslClose(sslState)
+     SslStateData *sslState;
+{
+    if (sslState->client.fd > -1) {
+       /* remove the "unexpected" client close handler */
+       comm_remove_close_handler(sslState->client.fd,
+           (PF) sslClientClosed,
+           (void *) sslState);
+       comm_close(sslState->client.fd);
+       sslState->client.fd = -1;
+    }
+    if (sslState->server.fd > -1) {
+       comm_close(sslState->server.fd);
+    }
+}
+
+/* This is called only if the client connect closes unexpectedly,
+ * ie from icpDetectClientClose() */
+static int sslClientClosed(fd, sslState)
+     int fd;
+     SslStateData *sslState;
+{
+    debug(26, 3, "sslClientClosed: FD %d\n", fd);
+    /* we have been called from comm_close for the client side, so
+     * just need to clean up the server side */
+    comm_close(sslState->server.fd);
+    return 0;
+}
 
 static int sslStateFree(fd, sslState)
      int fd;
@@ -48,6 +104,7 @@ static int sslStateFree(fd, sslState)
     safe_free(sslState->server.buf);
     safe_free(sslState->client.buf);
     xfree(sslState->url);
+    requestUnlink(sslState->request);
     memset(sslState, '\0', sizeof(SslStateData));
     safe_free(sslState);
     return 0;
@@ -60,8 +117,7 @@ static void sslLifetimeExpire(fd, sslState)
 {
     debug(26, 4, "sslLifeTimeExpire: FD %d: URL '%s'>\n",
        fd, sslState->url);
-    comm_close(sslState->client.fd);   /* close client first */
-    comm_close(sslState->server.fd);
+    sslClose(sslState);
 }
 
 /* Read from server side and queue it for writing to the client */
@@ -70,7 +126,7 @@ static void sslReadServer(fd, sslState)
      SslStateData *sslState;
 {
     int len;
-    len = read(sslState->server.fd, sslState->server.buf, 4096);
+    len = read(sslState->server.fd, sslState->server.buf, SQUID_TCP_SO_RCVBUF);
     debug(26, 5, "sslReadServer FD %d, read %d bytes\n", fd, len);
     if (len < 0) {
        debug(26, 1, "sslReadServer: FD %d: read failure: %s\n",
@@ -88,13 +144,11 @@ static void sslReadServer(fd, sslState)
                (void *) sslState,
                sslState->timeout);
        } else {
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           sslClose(sslState);
        }
     } else if (len == 0) {
        /* Connection closed; retrieval done. */
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
     } else {
        sslState->server.offset = 0;
        sslState->server.len = len;
@@ -120,7 +174,7 @@ static void sslReadClient(fd, sslState)
      SslStateData *sslState;
 {
     int len;
-    len = read(sslState->client.fd, sslState->client.buf, 4096);
+    len = read(sslState->client.fd, sslState->client.buf, SQUID_TCP_SO_RCVBUF);
     debug(26, 5, "sslReadClient FD %d, read %d bytes\n",
        sslState->client.fd, len);
     if (len < 0) {
@@ -139,13 +193,11 @@ static void sslReadClient(fd, sslState)
                (void *) sslState,
                sslState->timeout);
        } else {
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           sslClose(sslState);
        }
     } else if (len == 0) {
        /* Connection closed; retrieval done. */
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
     } else {
        sslState->client.offset = 0;
        sslState->client.len = len;
@@ -177,8 +229,7 @@ static void sslWriteServer(fd, sslState)
     if (len < 0) {
        debug(26, 2, "sslWriteServer: FD %d: write failure: %s.\n",
            sslState->server.fd, xstrerror());
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
        return;
     }
     if ((sslState->client.offset += len) >= sslState->client.len) {
@@ -213,8 +264,7 @@ static void sslWriteClient(fd, sslState)
     if (len < 0) {
        debug(26, 2, "sslWriteClient: FD %d: write failure: %s.\n",
            sslState->client.fd, xstrerror());
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       sslClose(sslState);
        return;
     }
     if (sslState->size_ptr)
@@ -238,11 +288,8 @@ static void sslReadTimeout(fd, sslState)
      int fd;
      SslStateData *sslState;
 {
-    if (fd != sslState->server.fd)
-       fatal_dump("sslReadTimeout: FD mismatch!\n");
     debug(26, 3, "sslReadTimeout: FD %d\n", fd);
-    comm_close(sslState->client.fd);
-    comm_close(sslState->server.fd);
+    sslClose(sslState);
 }
 
 static void sslConnected(fd, sslState)
@@ -257,7 +304,7 @@ static void sslConnected(fd, sslState)
        COMM_SELECT_WRITE,
        (PF) sslWriteClient,
        (void *) sslState);
-    comm_set_fd_lifetime(fd, -1);      /* disable lifetime */
+    comm_set_fd_lifetime(fd, 86400);   /* extend lifetime */
     comm_set_select_handler_plus_timeout(sslState->server.fd,
        COMM_SELECT_TIMEOUT,
        (PF) sslReadTimeout,
@@ -273,16 +320,28 @@ static void sslConnected(fd, sslState)
        (void *) sslState);
 }
 
+static void sslErrorComplete(fd, buf, size, errflag, sslState)
+     int fd;
+     char *buf;
+     int size;
+     int errflag;
+     void *sslState;
+{
+    safe_free(buf);
+    sslClose(sslState);
+}
+
 
 static void sslConnInProgress(fd, sslState)
      int fd;
      SslStateData *sslState;
 {
     request_t *req = sslState->request;
+    char *buf = NULL;
     debug(26, 5, "sslConnInProgress: FD %d sslState=%p\n", fd, sslState);
 
     if (comm_connect(fd, req->host, req->port) != COMM_OK) {
-       debug(26, 5, "sslConnInProgress: FD %d: %s", fd, xstrerror());
+       debug(26, 5, "sslConnInProgress: FD %d: %s\n", fd, xstrerror());
        switch (errno) {
 #if EINPROGRESS != EALREADY
        case EINPROGRESS:
@@ -294,8 +353,18 @@ static void sslConnInProgress(fd, sslState)
                (void *) sslState);
            return;
        default:
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           buf = squid_error_url(sslState->url,
+               METHOD_CONNECT,
+               ERR_CONNECT_FAIL,
+               NULL,
+               500,
+               xstrerror());
+           comm_write(sslState->client.fd,
+               xstrdup(buf),
+               strlen(buf),
+               30,
+               sslErrorComplete,
+               sslState);
            return;
        }
     }
@@ -304,64 +373,31 @@ static void sslConnInProgress(fd, sslState)
     return;
 }
 
-
-int sslStart(fd, url, request, mime_hdr, size_ptr)
+static int sslConnect(fd, hp, sslState)
      int fd;
-     char *url;
-     request_t *request;
-     char *mime_hdr;
-     int *size_ptr;
+     struct hostent *hp;
+     SslStateData *sslState;
 {
-    /* Create state structure. */
-    int sock, status;
-    SslStateData *sslState = NULL;
-
-    debug(26, 3, "sslStart: '%s %s'\n",
-       RequestMethodStr[request->method], url);
-
-    /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
-    if (sock == COMM_ERROR) {
-       debug(26, 4, "sslStart: Failed because we're out of sockets.\n");
-       squid_error_url(url,
-           request->method,
-           ERR_NO_FDS,
-           fd_table[fd].ipaddr,
-           500,
-           xstrerror());
-       return COMM_ERROR;
-    }
-    sslState = (SslStateData *) xcalloc(1, sizeof(SslStateData));
-    sslState->url = xstrdup(url);
-    sslState->request = request;
-    sslState->mime_hdr = mime_hdr;
-    sslState->timeout = getReadTimeout();
-    sslState->size_ptr = size_ptr;
-    sslState->client.fd = fd;
-    sslState->server.fd = sock;
-    sslState->server.buf = xmalloc(SSL_BUFSIZ);
-    sslState->client.buf = xmalloc(SSL_BUFSIZ);
-    comm_set_select_handler(sslState->server.fd,
-       COMM_SELECT_CLOSE,
-       (PF) sslStateFree,
-       (void *) sslState);
-
-    /* check if IP is already in cache. It must be. 
-     * It should be done before this route is called. 
-     * Otherwise, we cannot check return code for ssl. */
-    if (!ipcache_gethostbyname(request->host)) {
-       debug(26, 4, "sslstart: Called without IP entry in ipcache. OR lookup failed.\n");
-       squid_error_url(url,
+    request_t *request = sslState->request;
+    int status;
+    char *buf = NULL;
+    if (!ipcache_gethostbyname(request->host, 0)) {
+       debug(26, 4, "sslConnect: Unknown host: %s\n", request->host);
+       buf = squid_error_url(sslState->url,
            request->method,
            ERR_DNS_FAIL,
            fd_table[fd].ipaddr,
            500,
            dns_error_message);
-       comm_close(sslState->client.fd);
-       comm_close(sslState->server.fd);
+       comm_write(sslState->client.fd,
+           xstrdup(buf),
+           strlen(buf),
+           30,
+           sslErrorComplete,
+           (void *) sslState);
        return COMM_ERROR;
     }
-    debug(26, 5, "sslStart: client=%d server=%d\n",
+    debug(26, 5, "sslConnect: client=%d server=%d\n",
        sslState->client.fd,
        sslState->server.fd);
     /* Install lifetime handler */
@@ -378,19 +414,23 @@ int sslStart(fd, url, request, mime_hdr, size_ptr)
        (PF) sslLifetimeExpire,
        (void *) sslState);
     /* Open connection. */
-    if ((status = comm_connect(sock, request->host, request->port))) {
+    if ((status = comm_connect(fd, request->host, request->port))) {
        if (status != EINPROGRESS) {
-           squid_error_url(url,
+           buf = squid_error_url(sslState->url,
                request->method,
                ERR_CONNECT_FAIL,
                fd_table[fd].ipaddr,
                500,
                xstrerror());
-           comm_close(sslState->client.fd);
-           comm_close(sslState->server.fd);
+           comm_write(sslState->client.fd,
+               xstrdup(buf),
+               strlen(buf),
+               30,
+               sslErrorComplete,
+               (void *) sslState);
            return COMM_ERROR;
        } else {
-           debug(26, 5, "sslStart: conn %d EINPROGRESS\n", sock);
+           debug(26, 5, "sslConnect: conn %d EINPROGRESS\n", fd);
            /* The connection is in progress, install ssl handler */
            comm_set_select_handler(sslState->server.fd,
                COMM_SELECT_WRITE,
@@ -399,7 +439,62 @@ int sslStart(fd, url, request, mime_hdr, size_ptr)
            return COMM_OK;
        }
     }
-    /* We got immediately connected. (can this happen?) */
     sslConnected(sslState->server.fd, sslState);
     return COMM_OK;
 }
+
+int sslStart(fd, url, request, mime_hdr, size_ptr)
+     int fd;
+     char *url;
+     request_t *request;
+     char *mime_hdr;
+     int *size_ptr;
+{
+    /* Create state structure. */
+    SslStateData *sslState = NULL;
+    int sock;
+    char *buf = NULL;
+
+    debug(26, 3, "sslStart: '%s %s'\n",
+       RequestMethodStr[request->method], url);
+
+    /* Create socket. */
+    sock = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
+    if (sock == COMM_ERROR) {
+       debug(26, 4, "sslStart: Failed because we're out of sockets.\n");
+       buf = squid_error_url(url,
+           request->method,
+           ERR_NO_FDS,
+           fd_table[fd].ipaddr,
+           500,
+           xstrerror());
+       comm_write(sslState->client.fd,
+           xstrdup(buf),
+           strlen(buf),
+           30,
+           sslErrorComplete,
+           (void *) sslState);
+       return COMM_ERROR;
+    }
+    sslState = xcalloc(1, sizeof(SslStateData));
+    sslState->url = xstrdup(url);
+    sslState->request = requestLink(request);
+    sslState->mime_hdr = mime_hdr;
+    sslState->timeout = getReadTimeout();
+    sslState->size_ptr = size_ptr;
+    sslState->client.fd = fd;
+    sslState->server.fd = sock;
+    sslState->server.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
+    sslState->client.buf = xmalloc(SQUID_TCP_SO_RCVBUF);
+    comm_add_close_handler(sslState->server.fd,
+       (PF) sslStateFree,
+       (void *) sslState);
+    comm_add_close_handler(sslState->client.fd,
+       (PF) sslClientClosed,
+       (void *) sslState);
+    ipcache_nbgethostbyname(request->host,
+       sslState->server.fd,
+       (IPH) sslConnect,
+       sslState);
+    return COMM_OK;
+}
index e0a68a892daf25661a12ab7005a1663c0e63438c..a01a6cbbedfc4d09552020f8d7533feb7d927360 100644 (file)
@@ -1,7 +1,31 @@
-/* $Id: url.cc,v 1.21 1996/05/03 22:56:33 wessels Exp $ */
-
-/* 
- * DEBUG: Section 23          url
+/*
+ * $Id: url.cc,v 1.22 1996/07/09 03:41:46 wessels Exp $
+ *
+ * DEBUG: section 23    URL Parsing
+ * AUTHOR: Duane Wessels
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
  */
 
 #include "squid.h"
@@ -11,6 +35,7 @@ char *RequestMethodStr[] =
     "NONE",
     "GET",
     "POST",
+    "PUT",
     "HEAD",
     "CONNECT"
 };
@@ -43,7 +68,7 @@ char *url_convert_hex(org_url, allocate)
 
     url = allocate ? (char *) xstrdup(org_url) : org_url;
 
-    if (strlen(url) < 3 || !strchr(url, '%'))
+    if ((int) strlen(url) < 3 || !strchr(url, '%'))
        return url;
 
     for (s = t = url; *(s + 2); s++) {
@@ -105,6 +130,8 @@ method_t urlParseMethod(s)
        return METHOD_GET;
     } else if (strcasecmp(s, "POST") == 0) {
        return METHOD_POST;
+    } else if (strcasecmp(s, "PUT") == 0) {
+       return METHOD_PUT;
     } else if (strcasecmp(s, "HEAD") == 0) {
        return METHOD_HEAD;
     } else if (strcasecmp(s, "CONNECT") == 0) {
@@ -186,9 +213,10 @@ request_t *urlParse(method, url)
            *t = 0;
            strcpy(host, t + 1);
        }
-       if ((t = strrchr(host, ':')) && *(t + 1) != '\0') {
-           *t = '\0';
-           port = atoi(t + 1);
+       if ((t = strrchr(host, ':'))) {
+           *t++ = '\0';
+           if (*t != '\0')
+               port = atoi(t);
        }
     }
     for (t = host; *t; t++)
@@ -197,7 +225,7 @@ request_t *urlParse(method, url)
        debug(23, 0, "urlParse: Invalid port == 0\n");
        return NULL;
     }
-    request = (request_t *) xcalloc(1, sizeof(request_t));
+    request = get_free_request_t();
     request->method = method;
     request->protocol = protocol;
     strncpy(request->host, host, SQUIDHOSTNAMELEN);
@@ -234,3 +262,38 @@ char *urlCanonical(request, buf)
     }
     return buf;
 }
+
+request_t *requestLink(request)
+     request_t *request;
+{
+    request->link_count++;
+    return request;
+}
+
+void requestUnlink(request)
+     request_t *request;
+{
+    if (request == NULL)
+       return;
+    request->link_count--;
+    if (request->link_count == 0)
+       put_free_request_t(request);
+}
+
+int matchDomainName(domain, host)
+     char *domain;
+     char *host;
+{
+    int offset;
+    if ((offset = strlen(host) - strlen(domain)) < 0)
+       return 0;               /* host too short */
+    if (strcasecmp(domain, host + offset) != 0)
+       return 0;               /* no match at all */
+    if (*domain == '.')
+       return 1;
+    if (*(host + offset - 1) == '.')
+       return 1;
+    if (offset == 0)
+       return 1;
+    return 0;
+}
index 3a133c4ef4dcc3feca62f6587f2d346b0f5e3642..070f538ece0cb2e5f4f4b0c34a23920ab9439b94 100644 (file)
-/* $Id: wais.cc,v 1.30 1996/05/03 22:56:34 wessels Exp $ */
+/*
+ * $Id: wais.cc,v 1.31 1996/07/09 03:41:47 wessels Exp $
+ *
+ * DEBUG: section 24    WAIS Relay
+ * AUTHOR: Harvest Derived
+ *
+ * SQUID Internet Object Cache  http://www.nlanr.net/Squid/
+ * --------------------------------------------------------
+ *
+ *  Squid is the result of efforts by numerous individuals from the
+ *  Internet community.  Development is led by Duane Wessels of the
+ *  National Laboratory for Applied Network Research and funded by
+ *  the National Science Foundation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  
+ */
 
 /*
- * DEBUG: Section 24          wais
+ * Copyright (c) 1994, 1995.  All rights reserved.
+ *  
+ *   The Harvest software was developed by the Internet Research Task
+ *   Force Research Group on Resource Discovery (IRTF-RD):
+ *  
+ *         Mic Bowman of Transarc Corporation.
+ *         Peter Danzig of the University of Southern California.
+ *         Darren R. Hardy of the University of Colorado at Boulder.
+ *         Udi Manber of the University of Arizona.
+ *         Michael F. Schwartz of the University of Colorado at Boulder.
+ *         Duane Wessels of the University of Colorado at Boulder.
+ *  
+ *   This copyright notice applies to software in the Harvest
+ *   ``src/'' directory only.  Users should consult the individual
+ *   copyright notices in the ``components/'' subdirectories for
+ *   copyright information about other software bundled with the
+ *   Harvest source code distribution.
+ *  
+ * TERMS OF USE
+ *   
+ *   The Harvest software may be used and re-distributed without
+ *   charge, provided that the software origin and research team are
+ *   cited in any use of the system.  Most commonly this is
+ *   accomplished by including a link to the Harvest Home Page
+ *   (http://harvest.cs.colorado.edu/) from the query page of any
+ *   Broker you deploy, as well as in the query result pages.  These
+ *   links are generated automatically by the standard Broker
+ *   software distribution.
+ *   
+ *   The Harvest software is provided ``as is'', without express or
+ *   implied warranty, and with no support nor obligation to assist
+ *   in its use, correction, modification or enhancement.  We assume
+ *   no liability with respect to the infringement of copyrights,
+ *   trade secrets, or any patents, and are not responsible for
+ *   consequential damages.  Proper use of the Harvest software is
+ *   entirely the responsibility of the user.
+ *  
+ * DERIVATIVE WORKS
+ *  
+ *   Users may make derivative works from the Harvest software, subject 
+ *   to the following constraints:
+ *  
+ *     - You must include the above copyright notice and these 
+ *       accompanying paragraphs in all forms of derivative works, 
+ *       and any documentation and other materials related to such 
+ *       distribution and use acknowledge that the software was 
+ *       developed at the above institutions.
+ *  
+ *     - You must notify IRTF-RD regarding your distribution of 
+ *       the derivative work.
+ *  
+ *     - You must clearly notify users that your are distributing 
+ *       a modified version and not the original Harvest software.
+ *  
+ *     - Any derivative product is also subject to these copyright 
+ *       and use restrictions.
+ *  
+ *   Note that the Harvest software is NOT in the public domain.  We
+ *   retain copyright, as specified above.
+ *  
+ * HISTORY OF FREE SOFTWARE STATUS
+ *  
+ *   Originally we required sites to license the software in cases
+ *   where they were going to build commercial products/services
+ *   around Harvest.  In June 1995 we changed this policy.  We now
+ *   allow people to use the core Harvest software (the code found in
+ *   the Harvest ``src/'' directory) for free.  We made this change
+ *   in the interest of encouraging the widest possible deployment of
+ *   the technology.  The Harvest software is really a reference
+ *   implementation of a set of protocols and formats, some of which
+ *   we intend to standardize.  We encourage commercial
+ *   re-implementations of code complying to this set of standards.  
  */
 
 #include "squid.h"
 
 #define  WAIS_DELETE_GAP  (64*1024)
 
-typedef struct _waisdata {
+typedef struct {
+    int fd;
     StoreEntry *entry;
     method_t method;
     char *relayhost;
     int relayport;
     char *mime_hdr;
     char request[MAX_URL];
-} WAISData;
+} WaisStateData;
+
+static int waisStateFree _PARAMS((int, WaisStateData *));
+static void waisReadReplyTimeout _PARAMS((int, WaisStateData *));
+static void waisLifetimeExpire _PARAMS((int, WaisStateData *));
+static void waisReadReply _PARAMS((int, WaisStateData *));
+static void waisSendComplete _PARAMS((int, char *, int, int, void *));
+static void waisSendRequest _PARAMS((int, WaisStateData *));
+static void waisConnInProgress _PARAMS((int, WaisStateData *));
+static int waisConnect _PARAMS((int, struct hostent *, WaisStateData *));
 
 static int waisStateFree(fd, waisState)
      int fd;
-     WAISData *waisState;
+     WaisStateData *waisState;
 {
     if (waisState == NULL)
        return 1;
+    storeUnlockObject(waisState->entry);
     xfree(waisState);
     return 0;
 }
 
 /* This will be called when timeout on read. */
-static void waisReadReplyTimeout(fd, data)
+static void waisReadReplyTimeout(fd, waisState)
      int fd;
-     WAISData *data;
+     WaisStateData *waisState;
 {
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = waisState->entry;
     debug(24, 4, "waisReadReplyTimeout: Timeout on %d\n url: %s\n", fd, entry->url);
     squid_error_entry(entry, ERR_READ_TIMEOUT, NULL);
     comm_set_select_handler(fd, COMM_SELECT_READ, 0, 0);
@@ -42,13 +152,13 @@ static void waisReadReplyTimeout(fd, data)
 }
 
 /* This will be called when socket lifetime is expired. */
-void waisLifetimeExpire(fd, data)
+static void waisLifetimeExpire(fd, waisState)
      int fd;
-     WAISData *data;
+     WaisStateData *waisState;
 {
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = waisState->entry;
     debug(24, 4, "waisLifeTimeExpire: FD %d: <URL:%s>\n", fd, entry->url);
     squid_error_entry(entry, ERR_LIFETIME_EXP, NULL);
     comm_set_select_handler(fd, COMM_SELECT_READ | COMM_SELECT_WRITE, 0, 0);
@@ -60,15 +170,15 @@ void waisLifetimeExpire(fd, data)
 
 /* This will be called when data is ready to be read from fd.  Read until
  * error or connection closed. */
-void waisReadReply(fd, data)
+static void waisReadReply(fd, waisState)
      int fd;
-     WAISData *data;
+     WaisStateData *waisState;
 {
     static char buf[4096];
     int len;
     StoreEntry *entry = NULL;
 
-    entry = data->entry;
+    entry = waisState->entry;
     if (entry->flag & DELETE_BEHIND) {
        if (storeClientWaiting(entry)) {
            /* check if we want to defer reading */
@@ -84,7 +194,7 @@ void waisReadReply(fd, data)
                comm_set_select_handler(fd,
                    COMM_SELECT_READ,
                    (PF) waisReadReply,
-                   (void *) data);
+                   (void *) waisState);
                /* don't install read handler while we're above the gap */
                comm_set_select_handler_plus_timeout(fd,
                    COMM_SELECT_TIMEOUT,
@@ -111,9 +221,9 @@ void waisReadReply(fd, data)
            /* reinstall handlers */
            /* XXX This may loop forever */
            comm_set_select_handler(fd, COMM_SELECT_READ,
-               (PF) waisReadReply, (void *) data);
+               (PF) waisReadReply, (void *) waisState);
            comm_set_select_handler_plus_timeout(fd, COMM_SELECT_TIMEOUT,
-               (PF) waisReadReplyTimeout, (void *) data, getReadTimeout());
+               (PF) waisReadReplyTimeout, (void *) waisState, getReadTimeout());
        } else {
            BIT_RESET(entry->flag, CACHABLE);
            storeReleaseRequest(entry);
@@ -138,37 +248,38 @@ void waisReadReply(fd, data)
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) waisReadReply,
-           (void *) data);
+           (void *) waisState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) waisReadReplyTimeout,
-           (void *) data,
+           (void *) waisState,
            getReadTimeout());
     } else {
        storeAppend(entry, buf, len);
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) waisReadReply,
-           (void *) data);
+           (void *) waisState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) waisReadReplyTimeout,
-           (void *) data,
+           (void *) waisState,
            getReadTimeout());
     }
 }
 
 /* This will be called when request write is complete. Schedule read of
  * reply. */
-void waisSendComplete(fd, buf, size, errflag, data)
+static void waisSendComplete(fd, buf, size, errflag, data)
      int fd;
      char *buf;
      int size;
      int errflag;
-     WAISData *data;
+     void *data;
 {
     StoreEntry *entry = NULL;
-    entry = data->entry;
+    WaisStateData *waisState = data;
+    entry = waisState->entry;
     debug(24, 5, "waisSendComplete - fd: %d size: %d errflag: %d\n",
        fd, size, errflag);
     if (errflag) {
@@ -179,48 +290,78 @@ void waisSendComplete(fd, buf, size, errflag, data)
        comm_set_select_handler(fd,
            COMM_SELECT_READ,
            (PF) waisReadReply,
-           (void *) data);
+           (void *) waisState);
        comm_set_select_handler_plus_timeout(fd,
            COMM_SELECT_TIMEOUT,
            (PF) waisReadReplyTimeout,
-           (void *) data,
+           (void *) waisState,
            getReadTimeout());
     }
     safe_free(buf);            /* Allocated by waisSendRequest. */
 }
 
 /* This will be called when connect completes. Write request. */
-void waisSendRequest(fd, data)
+static void waisSendRequest(fd, waisState)
      int fd;
-     WAISData *data;
+     WaisStateData *waisState;
 {
-    int len = strlen(data->request) + 4;
+    int len = strlen(waisState->request) + 4;
     char *buf = NULL;
-    char *Method = RequestMethodStr[data->method];
+    char *Method = RequestMethodStr[waisState->method];
 
     debug(24, 5, "waisSendRequest - fd: %d\n", fd);
 
     if (Method)
        len += strlen(Method);
-    if (data->mime_hdr)
-       len += strlen(data->mime_hdr);
+    if (waisState->mime_hdr)
+       len += strlen(waisState->mime_hdr);
 
-    buf = (char *) xcalloc(1, len + 1);
+    buf = xcalloc(1, len + 1);
 
-    if (data->mime_hdr)
-       sprintf(buf, "%s %s %s\r\n", Method, data->request,
-           data->mime_hdr);
+    if (waisState->mime_hdr)
+       sprintf(buf, "%s %s %s\r\n", Method, waisState->request,
+           waisState->mime_hdr);
     else
-       sprintf(buf, "%s %s\r\n", Method, data->request);
+       sprintf(buf, "%s %s\r\n", Method, waisState->request);
     debug(24, 6, "waisSendRequest - buf:%s\n", buf);
-    icpWrite(fd,
+    comm_write(fd,
        buf,
        len,
        30,
        waisSendComplete,
-       (void *) data);
-    if (BIT_TEST(data->entry->flag, CACHABLE))
-       storeSetPublicKey(data->entry);         /* Make it public */
+       (void *) waisState);
+    if (BIT_TEST(waisState->entry->flag, CACHABLE))
+       storeSetPublicKey(waisState->entry);    /* Make it public */
+}
+
+static void waisConnInProgress(fd, waisState)
+     int fd;
+     WaisStateData *waisState;
+{
+    StoreEntry *entry = waisState->entry;
+
+    debug(11, 5, "waisConnInProgress: FD %d waisState=%p\n", fd, waisState);
+
+    if (comm_connect(fd, waisState->relayhost, waisState->relayport) != COMM_OK) {
+       debug(11, 5, "waisConnInProgress: FD %d: %s\n", fd, xstrerror());
+       switch (errno) {
+       case EINPROGRESS:
+       case EALREADY:
+           /* schedule this handler again */
+           comm_set_select_handler(fd,
+               COMM_SELECT_WRITE,
+               (PF) waisConnInProgress,
+               (void *) waisState);
+           return;
+       default:
+           squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
+           comm_close(fd);
+           return;
+       }
+    }
+    /* Call the real write handler, now that we're fully connected */
+    comm_set_select_handler(fd, COMM_SELECT_WRITE,
+       (PF) waisSendRequest, (void *) waisState);
 }
 
 int waisStart(unusedfd, url, method, mime_hdr, entry)
@@ -230,60 +371,82 @@ int waisStart(unusedfd, url, method, mime_hdr, entry)
      char *mime_hdr;
      StoreEntry *entry;
 {
-    /* Create state structure. */
-    int sock, status;
-    WAISData *data = NULL;
+    WaisStateData *waisState = NULL;
+    int fd;
 
-    debug(24, 3, "waisStart: \"%s %s\"\n",
-       RequestMethodStr[method], url);
+    debug(24, 3, "waisStart: \"%s %s\"\n", RequestMethodStr[method], url);
     debug(24, 4, "            header: %s\n", mime_hdr);
-
     if (!getWaisRelayHost()) {
        debug(24, 0, "waisStart: Failed because no relay host defined!\n");
        squid_error_entry(entry, ERR_NO_RELAY, NULL);
        return COMM_ERROR;
     }
-    /* Create socket. */
-    sock = comm_open(COMM_NONBLOCKING, 0, 0, url);
-    if (sock == COMM_ERROR) {
+    fd = comm_open(COMM_NONBLOCKING, getTcpOutgoingAddr(), 0, url);
+    if (fd == COMM_ERROR) {
        debug(24, 4, "waisStart: Failed because we're out of sockets.\n");
        squid_error_entry(entry, ERR_NO_FDS, xstrerror());
        return COMM_ERROR;
     }
-    data = (WAISData *) xcalloc(1, sizeof(WAISData));
-    data->entry = entry;
-    data->method = method;
-    data->relayhost = getWaisRelayHost();
-    data->relayport = getWaisRelayPort();
-    data->mime_hdr = mime_hdr;
-    comm_set_select_handler(sock,
-       COMM_SELECT_CLOSE,
+    waisState = xcalloc(1, sizeof(WaisStateData));
+    storeLockObject(waisState->entry = entry, NULL, NULL);
+    waisState->method = method;
+    waisState->relayhost = getWaisRelayHost();
+    waisState->relayport = getWaisRelayPort();
+    waisState->mime_hdr = mime_hdr;
+    waisState->fd = fd;
+    strncpy(waisState->request, url, MAX_URL);
+    comm_add_close_handler(waisState->fd,
        (PF) waisStateFree,
-       (void *) data);
+       (void *) waisState);
+    ipcache_nbgethostbyname(waisState->relayhost,
+       waisState->fd,
+       (IPH) waisConnect,
+       waisState);
+    return COMM_OK;
+}
 
-    /* check if IP is already in cache. It must be. 
-     * It should be done before this route is called. 
-     * Otherwise, we cannot check return code for connect. */
-    if (!ipcache_gethostbyname(data->relayhost)) {
-       debug(24, 4, "waisstart: Called without IP entry in ipcache. OR lookup failed.\n");
-       squid_error_entry(entry, ERR_DNS_FAIL, dns_error_message);
-       comm_close(sock);
+
+static int waisConnect(fd, hp, waisState)
+     int fd;
+     struct hostent *hp;
+     WaisStateData *waisState;
+{
+    int status;
+    char *host = waisState->relayhost;
+    u_short port = waisState->relayport;
+    if (!ipcache_gethostbyname(waisState->relayhost, 0)) {
+       debug(24, 4, "waisstart: Unknown host: %s\n", waisState->relayhost);
+       squid_error_entry(waisState->entry, ERR_DNS_FAIL, dns_error_message);
+       comm_close(waisState->fd);
        return COMM_ERROR;
     }
     /* Open connection. */
-    if ((status = comm_connect(sock, data->relayhost, data->relayport))) {
+    if ((status = comm_connect(fd, host, port))) {
        if (status != EINPROGRESS) {
-           squid_error_entry(entry, ERR_CONNECT_FAIL, xstrerror());
-           comm_close(sock);
+           squid_error_entry(waisState->entry, ERR_CONNECT_FAIL, xstrerror());
+           comm_close(fd);
            return COMM_ERROR;
        } else {
-           debug(24, 5, "waisStart: FD %d EINPROGRESS\n", sock);
+           debug(24, 5, "waisStart: FD %d EINPROGRESS\n", fd);
+           comm_set_select_handler(fd,
+               COMM_SELECT_LIFETIME,
+               (PF) waisLifetimeExpire,
+               (void *) waisState);
+           comm_set_select_handler(fd,
+               COMM_SELECT_WRITE,
+               (PF) waisConnInProgress,
+               (void *) waisState);
+           return COMM_OK;
        }
     }
     /* Install connection complete handler. */
-    comm_set_select_handler(sock, COMM_SELECT_LIFETIME,
-       (PF) waisLifetimeExpire, (void *) data);
-    comm_set_select_handler(sock, COMM_SELECT_WRITE,
-       (PF) waisSendRequest, (void *) data);
+    comm_set_select_handler(fd,
+       COMM_SELECT_LIFETIME,
+       (PF) waisLifetimeExpire,
+       (void *) waisState);
+    comm_set_select_handler(fd,
+       COMM_SELECT_WRITE,
+       (PF) waisSendRequest,
+       (void *) waisState);
     return COMM_OK;
 }