From: Alex Rousskov Date: Mon, 14 Jun 2010 21:22:01 +0000 (-0600) Subject: Support ICP and HTCP _servers_ sharing listening sockets. X-Git-Tag: SQUID_3_2_0_1~93^2~10 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=013e320c6831a2b175ce7a5b4fc15e58dafdc27d;p=thirdparty%2Fsquid.git Support ICP and HTCP _servers_ sharing listening sockets. Without a shared cache, the servers will report many false misses. ICP and HTCP _clients_ cannot be supported in SMP environment unless each process has its own address (i.e., unique IP address and/or unique [ICP] port) because we cannot match outgoing queries and incoming responses across processes. If ICP/HTCP support in SMP is needed, the easiest change would be to use random source ports for sending ICP/HTCP queries. This may also improve security by avoiding well-known source ports for UDP queries. --- diff --git a/src/htcp.cc b/src/htcp.cc index b3c269d915..ab76d6678d 100644 --- a/src/htcp.cc +++ b/src/htcp.cc @@ -46,6 +46,24 @@ #include "http.h" #include "icmp/net_db.h" #include "AccessLogEntry.h" +#include "ipc/StartListening.h" + +/// dials htcpIncomingConnectionOpened call +class HtcpListeningStartedDialer: public CallDialer, + public Ipc::StartListeningCb +{ +public: + typedef void (*Handler)(int fd, int errNo); + HtcpListeningStartedDialer(Handler aHandler): handler(aHandler) {} + + virtual void print(std::ostream &os) const { startPrint(os) << ')'; } + + virtual bool canDial(AsyncCall &) const { return true; } + virtual void dial(AsyncCall &) { (handler)(fd, errNo); } + +public: + Handler handler; +}; typedef struct _Countstr Countstr; @@ -225,6 +243,8 @@ enum { RR_RESPONSE }; +static void htcpIncomingConnectionOpened(int fd, int errNo); + static u_int32_t msg_id_counter = 0; static int htcpInSocket = -1; static int htcpOutSocket = -1; @@ -1483,20 +1503,15 @@ htcpInit(void) IpAddress incomingAddr = Config.Addrs.udp_incoming; incomingAddr.SetPort(Config.Port.htcp); - enter_suid(); - htcpInSocket = comm_open_listener(SOCK_DGRAM, + AsyncCall::Pointer call = asyncCall(31, 2, + "htcpIncomingConnectionOpened", + HtcpListeningStartedDialer(&htcpIncomingConnectionOpened)); + + Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, incomingAddr, COMM_NONBLOCKING, - "HTCP Socket"); - leave_suid(); - - if (htcpInSocket < 0) - fatal("Cannot open HTCP Socket"); - - commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); - - debugs(31, 1, "Accepting HTCP messages on port " << Config.Port.htcp << ", FD " << htcpInSocket << "."); + Ipc::fdnInHtcpSocket, call); if (!Config.Addrs.udp_outgoing.IsNoAddr()) { IpAddress outgoingAddr = Config.Addrs.udp_outgoing; @@ -1518,8 +1533,6 @@ htcpInit(void) debugs(31, 1, "Outgoing HTCP messages on port " << Config.Port.htcp << ", FD " << htcpOutSocket << "."); fd_note(htcpInSocket, "Incoming HTCP socket"); - } else { - htcpOutSocket = htcpInSocket; } if (!htcpDetailPool) { @@ -1527,6 +1540,22 @@ htcpInit(void) } } +static void +htcpIncomingConnectionOpened(int fd, int errNo) +{ + htcpInSocket = fd; + + if (htcpInSocket < 0) + fatal("Cannot open HTCP Socket"); + + commSetSelect(htcpInSocket, COMM_SELECT_READ, htcpRecv, NULL, 0); + + debugs(31, 1, "Accepting HTCP messages on port " << Config.Port.htcp << ", FD " << htcpInSocket << "."); + + if (Config.Addrs.udp_outgoing.IsNoAddr()) + htcpOutSocket = htcpInSocket; +} + int htcpQuery(StoreEntry * e, HttpRequest * req, peer * p) { diff --git a/src/icp_v2.cc b/src/icp_v2.cc index cbfed7a359..fbd600b20e 100644 --- a/src/icp_v2.cc +++ b/src/icp_v2.cc @@ -48,8 +48,31 @@ #include "SwapDir.h" #include "icmp/net_db.h" #include "ip/IpAddress.h" +#include "ipc/StartListening.h" #include "rfc1738.h" +/// dials icpIncomingConnectionOpened call +class IcpListeningStartedDialer: public CallDialer, + public Ipc::StartListeningCb +{ +public: + typedef void (*Handler)(int fd, int errNo, IpAddress& addr); + IcpListeningStartedDialer(Handler aHandler, IpAddress& anAddr): + handler(aHandler), addr(anAddr) {} + + virtual void print(std::ostream &os) const { startPrint(os) << + ", address=" << addr << ')'; } + + virtual bool canDial(AsyncCall &) const { return true; } + virtual void dial(AsyncCall &) { (handler)(fd, errNo, addr); } + +public: + Handler handler; + IpAddress addr; +}; + +static void icpIncomingConnectionOpened(int fd, int errNo, IpAddress& addr); + /// \ingroup ServerProtocolICPInternal2 static void icpLogIcp(const IpAddress &, log_type, int, const char *, int); @@ -656,35 +679,22 @@ icpConnectionsOpen(void) struct addrinfo *xai = NULL; int x; - wordlist *s; if ((port = Config.Port.icp) <= 0) return; - enter_suid(); - addr = Config.Addrs.udp_incoming; addr.SetPort(port); - theInIcpConnection = comm_open_listener(SOCK_DGRAM, + + AsyncCall::Pointer call = asyncCall(12, 2, + "icpIncomingConnectionOpened", + IcpListeningStartedDialer(&icpIncomingConnectionOpened, addr)); + + Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, addr, COMM_NONBLOCKING, - "ICP Socket"); - leave_suid(); - - if (theInIcpConnection < 0) - fatal("Cannot open ICP Port"); - - commSetSelect(theInIcpConnection, - COMM_SELECT_READ, - icpHandleUdp, - NULL, - 0); - - for (s = Config.mcast_group_list; s; s = s->next) - ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL); - - debugs(12, 1, "Accepting ICP messages at " << addr << ", FD " << theInIcpConnection << "."); + Ipc::fdnInIcpSocket, call); addr.SetEmpty(); // clear for next use. addr = Config.Addrs.udp_outgoing; @@ -710,10 +720,6 @@ icpConnectionsOpen(void) debugs(12, 1, "Outgoing ICP messages on port " << addr.GetPort() << ", FD " << theOutIcpConnection << "."); fd_note(theOutIcpConnection, "Outgoing ICP socket"); - - fd_note(theInIcpConnection, "Incoming ICP socket"); - } else { - theOutIcpConnection = theInIcpConnection; } theOutICPAddr.SetEmpty(); @@ -730,6 +736,31 @@ icpConnectionsOpen(void) theOutICPAddr.FreeAddrInfo(xai); } +static void +icpIncomingConnectionOpened(int fd, int errNo, IpAddress& addr) +{ + theInIcpConnection = fd; + + if (theInIcpConnection < 0) + fatal("Cannot open ICP Port"); + + commSetSelect(theInIcpConnection, + COMM_SELECT_READ, + icpHandleUdp, + NULL, + 0); + + for (const wordlist *s = Config.mcast_group_list; s; s = s->next) + ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL); + + debugs(12, 1, "Accepting ICP messages at " << addr << ", FD " << theInIcpConnection << "."); + + fd_note(theInIcpConnection, "Incoming ICP socket"); + + if (Config.Addrs.udp_outgoing.IsNoAddr()) + theOutIcpConnection = theInIcpConnection; +} + /** * icpConnectionShutdown only closes the 'in' socket if it is * different than the 'out' socket. diff --git a/src/ipc/FdNotes.cc b/src/ipc/FdNotes.cc index 6c2a992011..9eb3328f33 100644 --- a/src/ipc/FdNotes.cc +++ b/src/ipc/FdNotes.cc @@ -18,7 +18,9 @@ Ipc::FdNote(int fdNoteId) "HTTP Socket", // fdnHttpSocket "HTTPS Socket", // fdnHttpsSocket "Incoming SNMP Socket", // fdnInSnmpSocket - "Outgoing SNMP Socket" // fdnOutSnmpSocket + "Outgoing SNMP Socket", // fdnOutSnmpSocket + "Incoming ICP Socket", // fdnInIcpSocket + "Incoming HTCP Socket" // fdnInHtcpSocket }; if (fdnNone < fdNoteId && fdNoteId < fdnEnd) diff --git a/src/ipc/FdNotes.h b/src/ipc/FdNotes.h index 74deca3456..87219d09bc 100644 --- a/src/ipc/FdNotes.h +++ b/src/ipc/FdNotes.h @@ -15,7 +15,8 @@ namespace Ipc /// fd_note() label ID typedef enum { fdnNone, fdnHttpSocket, fdnHttpsSocket, - fdnInSnmpSocket, fdnOutSnmpSocket, fdnEnd } FdNoteId; + fdnInSnmpSocket, fdnOutSnmpSocket, + fdnInIcpSocket, fdnInHtcpSocket, fdnEnd } FdNoteId; extern const char *FdNote(int fdNodeId); ///< converts FdNoteId into a string