Index: src/client_side.c =================================================================== RCS file: /cvsroot/squid/squid/src/client_side.c,v retrieving revision 1.108 diff -u -r1.108 client_side.c --- src/client_side.c 30 May 2006 22:50:36 -0000 1.108 +++ src/client_side.c 1 Jun 2006 11:27:39 -0000 @@ -1306,7 +1306,6 @@ /* If any connection has been pinned to this client, force keep alive */ if (http->conn->pinned) { request->flags.must_keepalive = 1; - request->flags.auth = 1; request->flags.pinned = 1; } if (httpHeaderHas(req_hdr, HDR_AUTHORIZATION)) Index: src/comm.c =================================================================== RCS file: /cvsroot/squid/squid/src/comm.c,v retrieving revision 1.38 diff -u -r1.38 comm.c --- src/comm.c 29 May 2006 16:51:13 -0000 1.38 +++ src/comm.c 1 Jun 2006 11:27:40 -0000 @@ -710,6 +710,9 @@ comm_close(int fd) { fde *F = &fd_table[fd]; + fde *server_fde; + int i,server_fd; + PF *callback; debug(5, 5) ("comm_close: FD %d\n", fd); assert(fd >= 0); @@ -726,6 +729,31 @@ assert(F->flags.open); assert(F->type != FD_FILE); F->flags.closing = 1; + + /* Check for server-side fds that need closing */ + if(F->pinned_server.nused) { + debug(5, 3) ("comm_close: Checking %d pinned connections on fd %d\n", F->pinned_server.nused, fd); + for(i=F->pinned_server.nused - 1;i>=0;i--) { + server_fd=F->pinned_server.fds[i]; + server_fde=&fd_table[server_fd]; + + debug(5, 3) ("comm_close: Checking pinned server fd %d\n", server_fd); + /* Make sure we don't mess with a server fd incorrectly. + * + * If the server fd has been re-used, pinned_client_fd will change, + * if it has been closed, there will be no timeout handler + */ + if((server_fde->pinned_client_fd == fd) && (server_fde->timeout_handler)) { + callback=server_fde->timeout_handler; + server_fde->timeout_handler = NULL; + + debug(5, 3) ("comm_close: Closing pinned server fd %d\n", server_fd); + callback(server_fd,server_fde->timeout_data); + } + } + xfree(F->pinned_server.fds); + } + CommWriteStateCallbackAndFree(fd, COMM_ERR_CLOSING); commCallCloseHandlers(fd); if (F->uses) /* assume persistent connect count */ Index: src/fd.c =================================================================== RCS file: /cvsroot/squid/squid/src/fd.c,v retrieving revision 1.14 diff -u -r1.14 fd.c --- src/fd.c 30 May 2006 13:50:25 -0000 1.14 +++ src/fd.c 1 Jun 2006 11:27:40 -0000 @@ -50,6 +50,48 @@ static void fdUpdateBiggest(int fd, int); +void +fdAddPinnedServer(int clientfd, int serverfd) +{ + fde *F = &fd_table[clientfd]; + int i; + int *old; + + assert(clientfd < Squid_MaxFD); + assert(clientfd >= 0); + assert(serverfd < Squid_MaxFD); + assert(serverfd >= 0); + + debug(51, 5) ("fdAddPinnedServer: checking %d -> %d\n", clientfd, serverfd); + if(!(F->pinned_server.nalloc)) { + F->pinned_server.nalloc = 8; + F->pinned_server.fds=xmalloc(F->pinned_server.nalloc * sizeof(int)); + + debug(51, 5) ("fdAddPinnedServer: Adding first entry (%d)\n",F->pinned_server.nused); + F->pinned_server.fds[F->pinned_server.nused++] = serverfd; + } + else + { + for(i = F->pinned_server.nused - 1;i >= 0; i--) { + if(F->pinned_server.fds[i] == serverfd) + break; + } + + if(i < 0 ) { + if(F->pinned_server.nalloc == F->pinned_server.nused) { + F->pinned_server.nalloc <<= 1; + old = F->pinned_server.fds; + F->pinned_server.fds = xmalloc(F->pinned_server.nalloc * sizeof(int)); + xmemcpy(F->pinned_server.fds, old, F->pinned_server.nused * sizeof(int)); + xfree(old); + } + + debug(51, 5) ("fdAddPinnedServer: Adding next entry (%d)\n",F->pinned_server.nused); + F->pinned_server.fds[F->pinned_server.nused++] = serverfd; + } + } +} + static void fdUpdateBiggest(int fd, int opening) { @@ -120,6 +162,7 @@ F->flags.open = 1; F->read_method = &default_read_method; F->write_method = &default_write_method; + F->pinned_client_fd = -1; fdUpdateBiggest(fd, 1); if (desc) xstrncpy(F->desc, desc, FD_DESC_SZ); Index: src/forward.c =================================================================== RCS file: /cvsroot/squid/squid/src/forward.c,v retrieving revision 1.30 diff -u -r1.30 forward.c --- src/forward.c 30 May 2006 13:50:25 -0000 1.30 +++ src/forward.c 1 Jun 2006 11:27:41 -0000 @@ -495,11 +495,16 @@ if (ftimeout < ctimeout) ctimeout = ftimeout; if (fwdState->request->flags.pinned) - fd = pconnPop(name, port, domain, &fwdState->request->client_addr, fwdState->request->client_port); + /* We've already done a pconnLookup, so this should never fail */ + if((fd = pconnPop(name, port, NULL, &fwdState->request->client_addr, fwdState->request->client_port)) < 0) { + debug(17, 1) ("fwdConnectStart: pconnPop failed. If this cache uses parents, unusual results may follow\n"); + fwdState->request->flags.pinned = 0; + fwdState->request->flags.auth = 0; + } #if LINUX_TPROXY if (fd == -1 && (Config.onoff.linux_tproxy) && ((fwdState->request->my_port == Config.tproxy_port) || (Config.tproxy_port == 0))) - fd = pconnPop(name, port, domain, &fwdState->request->client_addr, 0); + fd = pconnPop(name, port, NULL, &fwdState->request->client_addr, 0); #endif if (fd == -1) fd = pconnPop(name, port, domain, NULL, 0); @@ -775,6 +780,7 @@ fwdStart(int fd, StoreEntry * e, request_t * r) { FwdState *fwdState; + FwdServer *peer = NULL; aclCheck_t ch; int answer; ErrorState *err; @@ -851,7 +857,18 @@ storeLockObject(e); EBIT_SET(e->flags, ENTRY_FWD_HDR_WAIT); storeRegisterAbort(e, fwdAbort, fwdState); - peerSelect(r, e, fwdStartComplete, fwdState); + if((r->flags.pinned) && (pconnLookup(r->host,r->port,NULL,&r->client_addr,r->client_port))) { + debug(17, 3) ("fwdStart: reusing persistent pinned connection\n"); + r->flags.auth=1; + peerAddFwdServer(&peer,NULL,HIER_DIRECT); + fwdStartComplete(peer,fwdState); + } + else + { + /* Make sure we remove the pinned flag */ + r->flags.pinned=0; + peerSelect(r, e, fwdStartComplete, fwdState); + } } int Index: src/http.c =================================================================== RCS file: /cvsroot/squid/squid/src/http.c,v retrieving revision 1.36 diff -u -r1.36 http.c --- src/http.c 27 May 2006 12:50:34 -0000 1.36 +++ src/http.c 1 Jun 2006 11:27:43 -0000 @@ -559,8 +559,6 @@ int bin; int clen; size_t read_sz = SQUID_TCP_SO_RCVBUF; - struct in_addr *client_addr = NULL; - u_short client_port = 0; #if DELAY_POOLS delay_id delay_id; #endif @@ -727,16 +725,6 @@ } } if (keep_alive) { - if (httpState->request->flags.pinned) { - client_addr = &httpState->request->client_addr; - client_port = httpState->request->client_port; - } -#if LINUX_TPROXY - else if ((Config.onoff.linux_tproxy) && - ((httpState->request->my_port == Config.tproxy_port) || (Config.tproxy_port == 0))) { - client_addr = &httpState->request->client_addr; - } -#endif /* yes we have to clear all these! */ commSetDefer(fd, NULL, NULL); commSetTimeout(fd, -1, NULL, NULL); @@ -746,14 +734,27 @@ #endif comm_remove_close_handler(fd, httpStateFree, httpState); fwdUnregister(fd, httpState->fwd); - if (httpState->peer) { + if (httpState->request->flags.pinned) { + fde *F = &fd_table[fd]; + + F->pinned_client_fd = httpState->fwd->client_fd; + fdAddPinnedServer(httpState->fwd->client_fd,fd); + + pconnPush(fd, request->host, request->port, NULL, &httpState->request->client_addr, httpState->request->client_port); + } else if (httpState->peer) { if (httpState->peer->options.originserver) - pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host, client_addr, client_port); + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, httpState->orig_request->host, NULL, 0); else - pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL, client_addr, client_port); - } else { - pconnPush(fd, request->host, request->port, NULL, client_addr, client_port); + pconnPush(fd, httpState->peer->name, httpState->peer->http_port, NULL, NULL, 0); } +#if LINUX_TPROXY + else if ((Config.onoff.linux_tproxy) && + ((httpState->request->my_port == Config.tproxy_port) || (Config.tproxy_port == 0))) { + pconnPush(fd, request->host, request->port, NULL, &httpState->request->client_addr, 0); +#endif + else + pconnPush(fd, request->host, request->port, NULL, NULL, 0); + fwdComplete(httpState->fwd); httpState->fd = -1; httpStateFree(fd, httpState); Index: src/protos.h =================================================================== RCS file: /cvsroot/squid/squid/src/protos.h,v retrieving revision 1.96 diff -u -r1.96 protos.h --- src/protos.h 30 May 2006 22:50:36 -0000 1.96 +++ src/protos.h 1 Jun 2006 11:27:45 -0000 @@ -258,6 +258,7 @@ extern void fd_open(int fd, unsigned int type, const char *); extern void fd_note(int fd, const char *); extern void fd_bytes(int fd, int len, unsigned int type); +extern void fdAddPinnedServer(int clientfd, int serverfd); extern void fdFreeMemory(void); extern void fdDumpOpen(void); extern int fdNFree(void); Index: src/structs.h =================================================================== RCS file: /cvsroot/squid/squid/src/structs.h,v retrieving revision 1.101 diff -u -r1.101 structs.h --- src/structs.h 30 May 2006 23:50:50 -0000 1.101 +++ src/structs.h 1 Jun 2006 11:27:47 -0000 @@ -869,6 +869,12 @@ squid_off_t bytes_read; squid_off_t bytes_written; int uses; /* ie # req's over persistent conn */ + int pinned_client_fd; /* The client fd this connection is pinned to */ + struct _pinnedconn { + int *fds; /* The server fd's this client has pinned */ + int nalloc; /* The number of allocated fds */ + int nused; /* The number of used fds */ + } pinned_server; #if USE_EPOLL unsigned epoll_state; /* keep track of the epoll state */ unsigned epoll_backoff; /* keep track of whether the fd is backed off */