]>
Commit | Line | Data |
---|---|---|
090089c4 | 1 | #!/usr/local/bin/perl |
a151895d | 2 | # |
bde978a6 | 3 | ## Copyright (C) 1996-2015 The Squid Software Foundation and contributors |
a151895d AJ |
4 | ## |
5 | ## Squid software is distributed under GPLv2+ license and includes | |
6 | ## contributions from numerous individuals and organizations. | |
7 | ## Please see the COPYING and CONTRIBUTORS files for details. | |
8 | ## | |
090089c4 | 9 | |
10 | # parse and answer ICP type 1 requests via unicast/multicast UDP | |
11 | # cf. <URL:http://excalibur.usc.edu/icpdoc/icp.html> | |
12 | # | |
13 | # returns ICP response code, e.g. 2 == HIT, 3 == MISS, 4 == ERROR | |
14 | # by looking at CERN or Netscape style cache directory $cachedir | |
15 | # | |
16 | # martin hamilton <m.t.hamilton@lut.ac.uk> | |
17 | # Id: icpserver,v 1.11 1995/11/24 16:20:13 martin Exp martin | |
18 | ||
19 | # usage: icpserver [-c cachedir] [-n] [-p port] [multicast_group] | |
20 | # | |
21 | # -c -> set cache directory | |
22 | # -n -> use Netscape cache format (default is CERN) | |
23 | # -p -> port number to listen on (default 3130) | |
24 | # -v -> verbose - writes activitiy log to stderr | |
25 | # | |
26 | # group -> multicast group to listen on | |
27 | ||
28 | require "getopts.pl"; | |
29 | &Getopts("c:np:v"); | |
30 | ||
31 | @CODES=("xxx", "QUERY", "HIT", "MISS", "ERROR"); | |
32 | ||
33 | $CACHEDIR=$opt_c||"/usr/local/www/cache"; | |
34 | $PORT=$opt_p||3130; | |
35 | $SERVER=$ARGV[0]||"0.0.0.0"; | |
36 | $SERVERIP= ($SERVER =~ m!\d+.\d+.\d+.\d+!) ? | |
37 | pack("C4", split(/\./, $SERVER)) : (gethostbyname($SERVER))[4]; # lazy! | |
38 | ||
39 | $SOCKADDR = 'S n a4 x8'; | |
40 | ||
41 | socket(S, 2, 2, 17) || socket(S, 2, 1, 17) || die "Couldn't get socket: $!"; | |
42 | $us1 = pack($SOCKADDR, 2, $PORT, $SERVERIP); | |
43 | $us2 = pack($SOCKADDR, 2, $PORT, pack("C4", 0,0,0,0)); | |
44 | bind(S, $us1) || bind(S, $us2) || die "Couldn't bind socket: $!"; | |
45 | #bind(S, $us2) || die "Couldn't bind socket: $!"; | |
46 | ||
47 | if ($SERVER ne "0.0.0.0") { # i.e. multicast | |
48 | $whoami = (`uname -a`)[0]; | |
49 | $IP_ADD_MEMBERSHIP=5; | |
50 | $whoami =~ /SunOS [^\s]+ 5/ && ($IP_MULTICAST_TTL=19); | |
51 | $whoami =~ /IRIX [^\s]+ 5/ && ($IP_MULTICAST_TTL=23); | |
52 | $whoami =~ /OSF1/ && ($IP_MULTICAST_TTL=12); | |
53 | # any more funnies ? | |
54 | ||
55 | setsockopt(S, 0, $IP_ADD_MEMBERSHIP, $SERVERIP."\0\0\0\0") | |
56 | || die "Couldn't join multicast group $SERVER: $!"; | |
57 | } | |
58 | ||
59 | # Common header for ICP datagrams ... (size in bytes - total 20) | |
60 | # opcode 1 Numeric code indicating type of message | |
61 | # version 1 Version of the protocol being used | |
62 | # length 2 Total length of packet | |
63 | # reqnum 4 Request number assigned by client | |
64 | # authenticator 8 Authentication information (future) | |
65 | # senderid 4 Identification (host id) of sender | |
66 | ||
67 | # Type 1 query ... | |
68 | # requester 4 Host id of original requester URL | |
69 | # url variable URL whose status is to be checked | |
70 | ||
71 | # Type 2 and 3 responses just contain URL, don't return anything else | |
72 | ||
73 | # Might be fast enough to get away without forking or non-blocking I/O ... ? | |
74 | while(1) { | |
75 | $theiraddr = recv(S, $ICP_request, 1024, 0); | |
76 | ($junk, $junk, $sourceaddr, $junk) = unpack($SOCKADDR, $theiraddr); | |
77 | @theirip = unpack('C4', $sourceaddr); | |
78 | ||
79 | $URL_length = length($ICP_request) - 24; | |
80 | $request_template = 'CCnx4x8x4a4a' . $URL_length; | |
81 | ($type, $version, $length, $requester, $URL) = | |
82 | unpack($request_template, $ICP_request); | |
83 | ||
84 | $URL =~ s/\.\.\///g; # be cautious - any others to watch out for ? | |
85 | ||
86 | # lookup object in cache | |
87 | $hitmisserr = 3; | |
88 | if ($type eq 1 && $URL =~ m!^([^:]+):/?/?([^/]+)/(.*)!) { | |
89 | $scheme = $1; $hostport = $2; $path = $3; | |
90 | if ($path eq "") { $path = "index.html"; } | |
91 | ||
92 | if ($opt_n) { | |
93 | ($host, $port) = split(/:/, $hostport); # strip off port number | |
94 | $port = ":$port" if ($port); | |
95 | $match = ""; | |
96 | foreach (split(/\./, $hostport)) { | |
97 | $match = "$_/$match"; # little-endian -> big-endian conversion | |
98 | } | |
99 | $match = "$CACHEDIR/hosts/$match$scheme$port.urls"; # full path | |
100 | if (-f "$match") { | |
101 | #### optimize! #### | |
102 | open(IN, "$match") && do { | |
103 | while(<IN>) { /^$URL / && ($hitmisserr = 2, last); } | |
104 | close(IN); | |
105 | } | |
106 | } | |
107 | } else { | |
108 | $hitmisserr = 2 if -f "$CACHEDIR/$scheme/$hostport/$path"; | |
109 | } | |
110 | } | |
111 | ||
112 | print "$type $hitmisserr ", join(".", @theirip), " $URL\n" if $opt_v; | |
113 | ||
114 | $response_template = 'CCnx4x8x4A' . length($URL); | |
115 | $ICP_response = | |
116 | pack($response_template, $hitmisserr, 2, 20 + length($URL), $URL); | |
117 | send(S, $ICP_response, 0, $theiraddr) || die "Couldn't send request: $!"; | |
118 | } | |
119 |