forward.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:16k
源码类别:

代理服务器

开发平台:

Unix_Linux

  1. /*
  2.  * $Id: forward.c,v 1.54 1999/01/29 23:39:18 wessels Exp $
  3.  *
  4.  * DEBUG: section 17    Request Forwarding
  5.  * AUTHOR: Duane Wessels
  6.  *
  7.  * SQUID Internet Object Cache  http://squid.nlanr.net/Squid/
  8.  * ----------------------------------------------------------
  9.  *
  10.  *  Squid is the result of efforts by numerous individuals from the
  11.  *  Internet community.  Development is led by Duane Wessels of the
  12.  *  National Laboratory for Applied Network Research and funded by the
  13.  *  National Science Foundation.  Squid is Copyrighted (C) 1998 by
  14.  *  Duane Wessels and the University of California San Diego.  Please
  15.  *  see the COPYRIGHT file for full details.  Squid incorporates
  16.  *  software developed and/or copyrighted by other sources.  Please see
  17.  *  the CREDITS file for full details.
  18.  *
  19.  *  This program is free software; you can redistribute it and/or modify
  20.  *  it under the terms of the GNU General Public License as published by
  21.  *  the Free Software Foundation; either version 2 of the License, or
  22.  *  (at your option) any later version.
  23.  *  
  24.  *  This program is distributed in the hope that it will be useful,
  25.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  26.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27.  *  GNU General Public License for more details.
  28.  *  
  29.  *  You should have received a copy of the GNU General Public License
  30.  *  along with this program; if not, write to the Free Software
  31.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
  32.  *
  33.  */
  34. #include "squid.h"
  35. static PSC fwdStartComplete;
  36. static void fwdDispatch(FwdState *);
  37. static void fwdConnectStart(void *); /* should be same as EVH */
  38. static void fwdStateFree(FwdState * fwdState);
  39. static PF fwdConnectTimeout;
  40. static PF fwdServerClosed;
  41. static CNCB fwdConnectDone;
  42. static int fwdCheckRetry(FwdState * fwdState);
  43. static int fwdReforward(FwdState *);
  44. static void fwdStartFail(FwdState *);
  45. static void fwdLogReplyStatus(int tries, http_status status);
  46. static OBJH fwdStats;
  47. static STABH fwdAbort;
  48. #define MAX_FWD_STATS_IDX 9
  49. static int FwdReplyCodes[MAX_FWD_STATS_IDX + 1][HTTP_INVALID_HEADER + 1];
  50. static void
  51. fwdServerFree(FwdServer * fs)
  52. {
  53.     if (fs->peer)
  54. cbdataUnlock(fs->peer);
  55.     memFree(fs, MEM_FWD_SERVER);
  56. }
  57. static void
  58. fwdServersFree(FwdServer ** FS)
  59. {
  60.     FwdServer *fs;
  61.     while ((fs = *FS)) {
  62. *FS = fs->next;
  63. fwdServerFree(fs);
  64.     }
  65. }
  66. static void
  67. fwdStateFree(FwdState * fwdState)
  68. {
  69.     StoreEntry *e = fwdState->entry;
  70.     int sfd;
  71.     debug(17, 3) ("fwdStateFree: %pn", fwdState);
  72.     assert(e->mem_obj);
  73.     if (e->store_status == STORE_PENDING) {
  74. if (e->mem_obj->inmem_hi == 0) {
  75.     assert(fwdState->err);
  76.     errorAppendEntry(e, fwdState->err);
  77. } else {
  78.     EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT);
  79.     storeComplete(e);
  80.     storeReleaseRequest(e);
  81. }
  82.     }
  83.     if (storePendingNClients(e) > 0)
  84. assert(!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT));
  85.     fwdServersFree(&fwdState->servers);
  86.     requestUnlink(fwdState->request);
  87.     fwdState->request = NULL;
  88.     storeUnregisterAbort(e);
  89.     storeUnlockObject(e);
  90.     fwdState->entry = NULL;
  91.     sfd = fwdState->server_fd;
  92.     if (sfd > -1) {
  93. comm_remove_close_handler(sfd, fwdServerClosed, fwdState);
  94. fwdState->server_fd = -1;
  95. debug(17, 3) ("fwdStateFree: closing FD %dn", sfd);
  96. comm_close(sfd);
  97.     }
  98.     cbdataFree(fwdState);
  99. }
  100. static int
  101. fwdCheckRetry(FwdState * fwdState)
  102. {
  103.     if (fwdState->entry->store_status != STORE_PENDING)
  104. return 0;
  105.     if (fwdState->entry->mem_obj->inmem_hi > 0)
  106. return 0;
  107.     if (fwdState->n_tries > 10)
  108. return 0;
  109.     if (squid_curtime - fwdState->start > 120)
  110. return 0;
  111.     if (fwdState->flags.dont_retry)
  112. return 0;
  113.     if (pumpMethod(fwdState->request->method))
  114. if (0 == pumpRestart(fwdState->request))
  115.     return 0;
  116.     return 1;
  117. }
  118. static void
  119. fwdServerClosed(int fd, void *data)
  120. {
  121.     FwdState *fwdState = data;
  122.     debug(17, 2) ("fwdServerClosed: FD %d %sn", fd, storeUrl(fwdState->entry));
  123.     assert(fwdState->server_fd == fd);
  124.     fwdState->server_fd = -1;
  125.     if (fwdCheckRetry(fwdState)) {
  126. debug(17, 3) ("fwdServerClosed: re-forwarding (%d tries, %d secs)n",
  127.     fwdState->n_tries,
  128.     (int) (squid_curtime - fwdState->start));
  129. /* use eventAdd to break potential call sequence loops */
  130. eventAdd("fwdConnectStart", fwdConnectStart, fwdState, 0.0, 1);
  131.     } else {
  132. fwdStateFree(fwdState);
  133.     }
  134. }
  135. static void
  136. fwdConnectDone(int server_fd, int status, void *data)
  137. {
  138.     FwdState *fwdState = data;
  139.     static FwdState *current = NULL;
  140.     FwdServer *fs = fwdState->servers;
  141.     ErrorState *err;
  142.     request_t *request = fwdState->request;
  143.     assert(current != fwdState);
  144.     current = fwdState;
  145.     assert(fwdState->server_fd == server_fd);
  146.     if (status == COMM_ERR_DNS) {
  147. fwdState->flags.dont_retry = 1;
  148. debug(17, 4) ("fwdConnectDone: Unknown host: %sn",
  149.     request->host);
  150. err = errorCon(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE);
  151. err->dnsserver_msg = xstrdup(dns_error_message);
  152. err->request = requestLink(request);
  153. fwdFail(fwdState, err);
  154. comm_close(server_fd);
  155.     } else if (status != COMM_OK) {
  156. assert(fs);
  157. err = errorCon(ERR_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE);
  158. err->xerrno = errno;
  159. if (fs->peer) {
  160.     err->host = xstrdup(fs->peer->host);
  161.     err->port = fs->peer->http_port;
  162. } else {
  163.     err->host = xstrdup(request->host);
  164.     err->port = request->port;
  165. }
  166. err->request = requestLink(request);
  167. fwdFail(fwdState, err);
  168. if (fs->peer)
  169.     peerCheckConnectStart(fs->peer);
  170. comm_close(server_fd);
  171.     } else {
  172. debug(17, 3) ("fwdConnectDone: FD %d: '%s'n", server_fd, storeUrl(fwdState->entry));
  173. fd_note(server_fd, storeUrl(fwdState->entry));
  174. fd_table[server_fd].uses++;
  175. fwdDispatch(fwdState);
  176.     }
  177.     current = NULL;
  178. }
  179. static void
  180. fwdConnectTimeout(int fd, void *data)
  181. {
  182.     FwdState *fwdState = data;
  183.     StoreEntry *entry = fwdState->entry;
  184.     ErrorState *err;
  185.     debug(17, 2) ("fwdConnectTimeout: FD %d: '%s'n", fd, storeUrl(entry));
  186.     assert(fd == fwdState->server_fd);
  187.     if (entry->mem_obj->inmem_hi == 0) {
  188. err = errorCon(ERR_CONNECT_FAIL, HTTP_GATEWAY_TIMEOUT);
  189. err->request = requestLink(fwdState->request);
  190. err->xerrno = ETIMEDOUT;
  191. fwdFail(fwdState, err);
  192.     }
  193.     comm_close(fd);
  194. }
  195. static void
  196. fwdConnectStart(void *data)
  197. {
  198.     FwdState *fwdState = data;
  199.     const char *url = storeUrl(fwdState->entry);
  200.     int fd;
  201.     ErrorState *err;
  202.     FwdServer *fs = fwdState->servers;
  203.     const char *host;
  204.     unsigned short port;
  205.     assert(fs);
  206.     assert(fwdState->server_fd == -1);
  207.     debug(17, 3) ("fwdConnectStart: %sn", url);
  208.     if (fs->peer) {
  209. host = fs->peer->host;
  210. port = fs->peer->http_port;
  211.     } else {
  212. host = fwdState->request->host;
  213. port = fwdState->request->port;
  214.     }
  215.     hierarchyNote(&fwdState->request->hier, fs->code, host);
  216.     if ((fd = pconnPop(host, port)) >= 0) {
  217. debug(17, 3) ("fwdConnectStart: reusing pconn FD %dn", fd);
  218. fwdState->server_fd = fd;
  219. fwdState->n_tries++;
  220. comm_add_close_handler(fd, fwdServerClosed, fwdState);
  221. fwdConnectDone(fd, COMM_OK, fwdState);
  222. return;
  223.     }
  224.     fd = comm_open(SOCK_STREAM,
  225. 0,
  226. Config.Addrs.tcp_outgoing,
  227. 0,
  228. COMM_NONBLOCKING,
  229. url);
  230.     if (fd < 0) {
  231. debug(50, 4) ("fwdConnectStart: %sn", xstrerror());
  232. err = errorCon(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
  233. err->xerrno = errno;
  234. err->request = requestLink(fwdState->request);
  235. fwdFail(fwdState, err);
  236. fwdStateFree(fwdState);
  237. return;
  238.     }
  239.     fwdState->server_fd = fd;
  240.     fwdState->n_tries++;
  241.     comm_add_close_handler(fd, fwdServerClosed, fwdState);
  242.     commSetTimeout(fd,
  243. Config.Timeout.connect,
  244. fwdConnectTimeout,
  245. fwdState);
  246.     commConnectStart(fd, host, port, fwdConnectDone, fwdState);
  247. }
  248. static void
  249. fwdStartComplete(FwdServer * servers, void *data)
  250. {
  251.     FwdState *fwdState = data;
  252.     debug(17, 3) ("fwdStartComplete: %sn", storeUrl(fwdState->entry));
  253.     if (servers != NULL) {
  254. fwdState->servers = servers;
  255. fwdConnectStart(fwdState);
  256.     } else {
  257. fwdStartFail(fwdState);
  258.     }
  259. }
  260. static void
  261. fwdStartFail(FwdState * fwdState)
  262. {
  263.     ErrorState *err;
  264.     debug(17, 3) ("fwdStartFail: %sn", storeUrl(fwdState->entry));
  265.     err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE);
  266.     err->request = requestLink(fwdState->request);
  267.     err->xerrno = errno;
  268.     fwdFail(fwdState, err);
  269.     fwdStateFree(fwdState);
  270. }
  271. static void
  272. fwdDispatch(FwdState * fwdState)
  273. {
  274.     peer *p;
  275.     request_t *request = fwdState->request;
  276.     StoreEntry *entry = fwdState->entry;
  277.     debug(17, 3) ("fwdDispatch: FD %d: Fetching '%s %s'n",
  278. fwdState->client_fd,
  279. RequestMethodStr[request->method],
  280. storeUrl(entry));
  281.     /*assert(!EBIT_TEST(entry->flags, ENTRY_DISPATCHED)); */
  282.     assert(entry->ping_status != PING_WAITING);
  283.     assert(entry->lock_count);
  284.     EBIT_SET(entry->flags, ENTRY_DISPATCHED);
  285.     netdbPingSite(request->host);
  286.     /*
  287.      * Assert that server_fd is set.  This is to guarantee that fwdState
  288.      * is attached to something and will be deallocated when server_fd
  289.      * is closed.
  290.      */
  291.     assert(fwdState->server_fd > -1);
  292.     if (fwdState->servers && (p = fwdState->servers->peer)) {
  293. p->stats.fetches++;
  294. httpStart(fwdState);
  295.     } else {
  296. switch (request->protocol) {
  297. case PROTO_HTTP:
  298.     httpStart(fwdState);
  299.     break;
  300. case PROTO_GOPHER:
  301.     gopherStart(fwdState);
  302.     break;
  303. case PROTO_FTP:
  304.     ftpStart(fwdState);
  305.     break;
  306. case PROTO_WAIS:
  307.     waisStart(fwdState);
  308.     break;
  309. case PROTO_CACHEOBJ:
  310. case PROTO_INTERNAL:
  311. case PROTO_URN:
  312.     fatal_dump("Should never get here");
  313.     break;
  314. case PROTO_WHOIS:
  315.     whoisStart(fwdState);
  316.     break;
  317. default:
  318.     debug(17, 1) ("fwdDispatch: Cannot retrieve '%s'n",
  319. storeUrl(entry));
  320.     fwdFail(fwdState, errorCon(ERR_UNSUP_REQ, HTTP_BAD_REQUEST));
  321.     comm_close(fwdState->server_fd);
  322.     break;
  323. }
  324.     }
  325. }
  326. static int
  327. fwdReforward(FwdState * fwdState)
  328. {
  329.     StoreEntry *e = fwdState->entry;
  330.     FwdServer *fs = fwdState->servers;
  331.     http_status s;
  332.     assert(e->store_status == STORE_PENDING);
  333.     assert(e->mem_obj);
  334.     debug(17, 3) ("fwdReforward: %s?n", storeUrl(e));
  335.     if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) {
  336. debug(17, 3) ("fwdReforward: No, ENTRY_FWD_HDR_WAIT isn't setn");
  337. return 0;
  338.     }
  339.     if (fwdState->n_tries > 9)
  340. return 0;
  341.     if (pumpMethod(fwdState->request->method))
  342. if (0 == pumpRestart(fwdState->request))
  343.     return 0;
  344.     assert(fs);
  345.     fwdState->servers = fs->next;
  346.     fwdServerFree(fs);
  347.     if (fwdState->servers == NULL) {
  348. debug(17, 3) ("fwdReforward: No forward-servers leftn");
  349. return 0;
  350.     }
  351.     s = e->mem_obj->reply->sline.status;
  352.     debug(17, 3) ("fwdReforward: status %dn", (int) s);
  353.     switch (s) {
  354.     case HTTP_FORBIDDEN:
  355.     case HTTP_INTERNAL_SERVER_ERROR:
  356.     case HTTP_NOT_IMPLEMENTED:
  357.     case HTTP_BAD_GATEWAY:
  358.     case HTTP_SERVICE_UNAVAILABLE:
  359.     case HTTP_GATEWAY_TIMEOUT:
  360. return 1;
  361.     default:
  362. return 0;
  363.     }
  364.     /* NOTREACHED */
  365. }
  366. /* PUBLIC FUNCTIONS */
  367. void
  368. fwdStart(int fd, StoreEntry * e, request_t * r, struct in_addr client_addr,
  369.     struct in_addr my_addr)
  370. {
  371.     FwdState *fwdState;
  372.     aclCheck_t ch;
  373.     int answer;
  374.     ErrorState *err;
  375.     /*
  376.      * client_addr == no_addr indicates this is an "internal" request
  377.      * from peer_digest.c, asn.c, netdb.c, etc and should always
  378.      * be allowed.  yuck, I know.
  379.      */
  380.     if (client_addr.s_addr != no_addr.s_addr) {
  381. /*      
  382.  * Check if this host is allowed to fetch MISSES from us (miss_access)
  383.  */
  384. memset(&ch, '', sizeof(aclCheck_t));
  385. ch.src_addr = client_addr;
  386. ch.my_addr = my_addr;
  387. ch.request = r;
  388. answer = aclCheckFast(Config.accessList.miss, &ch);
  389. if (answer == 0) {
  390.     err = errorCon(ERR_FORWARDING_DENIED, HTTP_FORBIDDEN);
  391.     err->request = requestLink(r);
  392.     err->src_addr = client_addr;
  393.     errorAppendEntry(e, err);
  394.     return;
  395. }
  396.     }
  397.     debug(17, 3) ("fwdStart: '%s'n", storeUrl(e));
  398.     e->mem_obj->request = requestLink(r);
  399.     e->mem_obj->fd = fd;
  400.     if (shutting_down) {
  401. /* more yuck */
  402. err = errorCon(ERR_SHUTTING_DOWN, HTTP_SERVICE_UNAVAILABLE);
  403. err->request = requestLink(r);
  404. errorAppendEntry(e, err);
  405. return;
  406.     }
  407.     switch (r->protocol) {
  408. /*
  409.  * Note, don't create fwdState for these requests
  410.  */
  411.     case PROTO_INTERNAL:
  412. internalStart(r, e);
  413. return;
  414.     case PROTO_CACHEOBJ:
  415. cachemgrStart(fd, r, e);
  416. return;
  417.     case PROTO_URN:
  418. urnStart(r, e);
  419. return;
  420.     default:
  421. break;
  422.     }
  423.     fwdState = memAllocate(MEM_FWD_STATE);
  424.     cbdataAdd(fwdState, memFree, MEM_FWD_STATE);
  425.     fwdState->entry = e;
  426.     fwdState->client_fd = fd;
  427.     fwdState->server_fd = -1;
  428.     fwdState->request = requestLink(r);
  429.     fwdState->start = squid_curtime;
  430.     storeLockObject(e);
  431.     EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT);
  432.     storeRegisterAbort(e, fwdAbort, fwdState);
  433.     peerSelect(r, e, fwdStartComplete, fwdState);
  434. }
  435. int
  436. fwdCheckDeferRead(int fd, void *data)
  437. {
  438.     StoreEntry *e = data;
  439.     MemObject *mem = e->mem_obj;
  440.     if (mem == NULL)
  441. return 0;
  442. #if DELAY_POOLS
  443.     if (!delayIsNoDelay(fd) && delayMostBytesWanted(mem, 1) == 0)
  444. return 1;
  445. #endif
  446.     if (mem->inmem_hi - storeLowestMemReaderOffset(e) < READ_AHEAD_GAP)
  447. return 0;
  448.     return 1;
  449. }
  450. void
  451. fwdFail(FwdState * fwdState, ErrorState * errorState)
  452. {
  453.     assert(EBIT_TEST(fwdState->entry->flags, ENTRY_FWD_HDR_WAIT));
  454.     debug(17, 3) ("fwdFail: %s "%s"nt%sn",
  455. err_type_str[errorState->type],
  456. httpStatusString(errorState->http_status),
  457. storeUrl(fwdState->entry));
  458.     if (fwdState->err)
  459. errorStateFree(fwdState->err);
  460.     fwdState->err = errorState;
  461. }
  462. /*
  463.  * Called when someone else calls StoreAbort() on this entry
  464.  */
  465. void
  466. fwdAbort(void *data)
  467. {
  468.     FwdState *fwdState = data;
  469.     debug(17, 2) ("fwdAbort: %sn", storeUrl(fwdState->entry));
  470.     fwdStateFree(fwdState);
  471. }
  472. /*
  473.  * Frees fwdState without closing FD or generating an abort
  474.  */
  475. void
  476. fwdUnregister(int fd, FwdState * fwdState)
  477. {
  478.     debug(17, 3) ("fwdUnregister: %sn", storeUrl(fwdState->entry));
  479.     assert(fd = fwdState->server_fd);
  480.     assert(fd > -1);
  481.     comm_remove_close_handler(fd, fwdServerClosed, fwdState);
  482.     fwdState->server_fd = -1;
  483. }
  484. /*
  485.  * server-side modules call fwdComplete() when they are done
  486.  * downloading an object.  Then, we either 1) re-forward the
  487.  * request somewhere else if needed, or 2) call storeComplete()
  488.  * to finish it off
  489.  */
  490. void
  491. fwdComplete(FwdState * fwdState)
  492. {
  493.     StoreEntry *e = fwdState->entry;
  494.     assert(e->store_status == STORE_PENDING);
  495.     debug(17, 3) ("fwdComplete: %sntstatus %dn", storeUrl(e),
  496. e->mem_obj->reply->sline.status);
  497.     fwdLogReplyStatus(fwdState->n_tries, e->mem_obj->reply->sline.status);
  498.     if (fwdReforward(fwdState)) {
  499. debug(17, 3) ("fwdComplete: re-forwarding %d %sn",
  500.     e->mem_obj->reply->sline.status,
  501.     storeUrl(e));
  502. if (fwdState->server_fd > -1)
  503.     fwdUnregister(fwdState->server_fd, fwdState);
  504. storeEntryReset(e);
  505. fwdStartComplete(fwdState->servers, fwdState);
  506.     } else {
  507. debug(17, 3) ("fwdComplete: not re-forwarding status %dn",
  508.     e->mem_obj->reply->sline.status);
  509. EBIT_CLR(e->flags, ENTRY_FWD_HDR_WAIT);
  510. storeComplete(e);
  511. /*
  512.  * If fwdState isn't associated with a server FD, it
  513.  * won't get freed unless we do it here.
  514.  */
  515. if (fwdState->server_fd < 0)
  516.     fwdStateFree(fwdState);
  517.     }
  518. }
  519. void
  520. fwdInit(void)
  521. {
  522.     cachemgrRegister("forward",
  523. "Request Forwarding Statistics",
  524. fwdStats, 0, 1);
  525. }
  526. static void
  527. fwdLogReplyStatus(int tries, http_status status)
  528. {
  529.     if (status > HTTP_INVALID_HEADER)
  530. return;
  531.     assert(tries);
  532.     tries--;
  533.     if (tries > MAX_FWD_STATS_IDX)
  534. tries = MAX_FWD_STATS_IDX;
  535.     FwdReplyCodes[tries][status]++;
  536. }
  537. static void
  538. fwdStats(StoreEntry * s)
  539. {
  540.     int i;
  541.     int j;
  542.     storeAppendPrintf(s, "Status");
  543.     for (j = 0; j <= MAX_FWD_STATS_IDX; j++) {
  544. storeAppendPrintf(s, "ttry#%d", j + 1);
  545.     }
  546.     storeAppendPrintf(s, "n");
  547.     for (i = 0; i <= (int) HTTP_INVALID_HEADER; i++) {
  548. if (FwdReplyCodes[0][i] == 0)
  549.     continue;
  550. storeAppendPrintf(s, "%3d", i);
  551. for (j = 0; j <= MAX_FWD_STATS_IDX; j++) {
  552.     storeAppendPrintf(s, "t%d", FwdReplyCodes[j][i]);
  553. }
  554. storeAppendPrintf(s, "n");
  555.     }
  556. }