=== modified file 'src/ICP.h' --- src/ICP.h 2012-04-25 05:29:20 +0000 +++ src/ICP.h 2012-05-01 00:08:22 +0000 @@ -110,6 +110,9 @@ /// \ingroup ServerProtocolICPAPI struct icpUdpData { + /// config details of the peer this packet is being sent to (if any) + const peer *peerDetail; // XXX: cbdata pointer? + /// IP address for the remote end. Because we reply to packets from unknown non-peers. Ip::Address address; @@ -126,10 +129,14 @@ struct timeval queue_time; }; -extern Comm::ConnectionPointer icpIncomingConn; -extern Comm::ConnectionPointer icpOutgoingConn; +/// whether any ICP ports are currently open +extern bool icpActive; + extern Ip::Address theIcpPublicHostID; +/// Locate an open ICP port which can use for packets to the given destination +extern Comm::ConnectionPointer icpLocateOutConn(const Ip::Address &sendingTo); + /// \ingroup ServerProtocolICPAPI extern HttpRequest* icpGetRequest(char *url, int reqnum, int fd, Ip::Address &from); @@ -143,7 +150,7 @@ extern icp_opcode icpGetCommonOpcode(); /// \ingroup ServerProtocolICPAPI -SQUIDCEXTERN int icpUdpSend(int, const Ip::Address &, icp_common_t *, log_type, int); +SQUIDCEXTERN int icpUdpSend(const peer *, const Ip::Address &, icp_common_t *, log_type, int); /// \ingroup ServerProtocolICPAPI SQUIDCEXTERN log_type icpLogFromICPCode(icp_opcode opcode); === modified file 'src/anyp/PortCfg.h' --- src/anyp/PortCfg.h 2012-04-25 05:29:20 +0000 +++ src/anyp/PortCfg.h 2012-05-06 01:32:19 +0000 @@ -12,7 +12,7 @@ { struct PortCfg { - PortCfg(const char *aProtocol); + explicit PortCfg(const char *aProtocol); ~PortCfg(); AnyP::PortCfg *clone() const; === modified file 'src/cache_cf.cc' --- src/cache_cf.cc 2012-04-26 01:04:17 +0000 +++ src/cache_cf.cc 2012-05-06 05:29:10 +0000 @@ -3763,19 +3763,28 @@ } void -add_http_port(char *portspec) +add_generic_port(char *portspec, const char *protocol) { - AnyP::PortCfg *s = new AnyP::PortCfg("http_port"); + AnyP::PortCfg *s = new AnyP::PortCfg(protocol); parsePortSpecification(s, portspec); // we may need to merge better if the above returns a list with clones assert(s->next == NULL); - s->next = Config.Sockaddr.http; - Config.Sockaddr.http = s; + if (!strcmp(protocol,"http")) { + s->next = Config.Sockaddr.http; + Config.Sockaddr.http = s; + } else if(!strcmp(protocol,"icp")) { + s->next = Config.Sockaddr.icp; + Config.Sockaddr.icp = s; + } } static void -parsePortCfg(AnyP::PortCfg ** head, const char *protocol) +parsePortCfg(AnyP::PortCfg ** head, const char *type) { + char protocol[15]; + memset(protocol, '\0', sizeof(protocol)); + memcpy(protocol, type, min(sizeof(protocol)-1,strlen(type)-5)); + char *token = strtok(NULL, w_space); if (!token) { @@ -3834,7 +3843,7 @@ if (s->defaultsite) storeAppendPrintf(e, " defaultsite=%s", s->defaultsite); - if (s->protocol && strcmp(s->protocol,"http") != 0) + if (s->protocol && strncmp(s->protocol, n, strlen(s->protocol)) != 0) storeAppendPrintf(e, " protocol=%s", s->protocol); if (s->allow_direct) === modified file 'src/cf.data.pre' --- src/cf.data.pre 2012-04-25 05:29:20 +0000 +++ src/cf.data.pre 2012-05-08 01:30:05 +0000 @@ -5592,18 +5592,19 @@ COMMENT_END NAME: snmp_port -TYPE: u_short -LOC: Config.Port.snmp -DEFAULT: 0 +TYPE: PortCfg +DEFAULT: none +LOC: Config.Sockaddr.snmp IFDEF: SQUID_SNMP DOC_START - The port number where Squid listens for SNMP requests. To enable + The port where Squid listens for SNMP requests. To enable SNMP support set this to a suitable port number. Port number - 3401 is often used for the Squid SNMP agent. By default it's - set to "0" (disabled) + 3401 is often used for the Squid SNMP agent. + By default SNMP is disabled. Example: snmp_port 3401 + snmp_port 192.1.2.3:3401 DOC_END NAME: snmp_access @@ -5626,36 +5627,11 @@ snmp_access deny all DOC_END -NAME: snmp_incoming_address -TYPE: address -LOC: Config.Addrs.snmp_incoming -DEFAULT: any_addr -IFDEF: SQUID_SNMP -DOC_NONE - -NAME: snmp_outgoing_address -TYPE: address -LOC: Config.Addrs.snmp_outgoing -DEFAULT: no_addr +NAME: snmp_incoming_address snmp_outgoing_address +TYPE: obsolete IFDEF: SQUID_SNMP DOC_START - Just like 'udp_incoming_address', but for the SNMP port. - - snmp_incoming_address is used for the SNMP socket receiving - messages from SNMP agents. - snmp_outgoing_address is used for SNMP packets returned to SNMP - agents. - - The default snmp_incoming_address is to listen on all - available network interfaces. - - If snmp_outgoing_address is not set it will use the same socket - as snmp_incoming_address. Only change this if you want to have - SNMP replies sent using another address than where this Squid - listens for SNMP queries. - - NOTE, snmp_incoming_address and snmp_outgoing_address can not have - the same value since they both use port 3401. + Use snmp_port instead. It takes address:port as a parameter. DOC_END COMMENT_START @@ -5664,27 +5640,27 @@ COMMENT_END NAME: icp_port udp_port -TYPE: u_short -DEFAULT: 0 -LOC: Config.Port.icp +TYPE: PortCfg +DEFAULT: none +LOC: Config.Sockaddr.icp DOC_START - The port number where Squid sends and receives ICP queries to + The address port where Squid sends and receives ICP queries to and from neighbor caches. The standard UDP port for ICP is 3130. - Default is disabled (0). + Default is disabled. Example: - icp_port @DEFAULT_ICP_PORT@ + icp_port 3130 DOC_END NAME: htcp_port IFDEF: USE_HTCP -TYPE: u_short -DEFAULT: 0 -LOC: Config.Port.htcp +TYPE: PortCfg +DEFAULT: none +LOC: Config.Sockaddr.htcp DOC_START - The port number where Squid sends and receives HTCP queries to + The address and port where Squid sends and receives HTCP queries to and from neighbor caches. To turn it on you want to set it to - 4827. By default it is set to "0" (disabled). + 4827. By default it is disabled. Example: htcp_port 4827 @@ -5702,41 +5678,49 @@ DOC_END NAME: udp_incoming_address +TYPE: obsolete +DOC_START + Use dns_incoming_address for DNS listening address. + Use icp_port, htcp_port, or snmp_port for other UDP protocols address:port settings. +DOC_END + +NAME: dns_incoming_address TYPE: address -LOC:Config.Addrs.udp_incoming +LOC:Config.dns.incomingAddr DEFAULT: any_addr DOC_START - udp_incoming_address is used for UDP packets received from other - caches. + dns_incoming_address is used to listen for DNS packets. The default behavior is to not bind to any specific address. - Only change this if you want to have all UDP queries received on + Only change this if you want to have all DNS queries received on a specific interface/address. - NOTE: udp_incoming_address is used by the ICP, HTCP, and DNS - modules. Altering it will affect all of them in the same manner. - - see also; udp_outgoing_address - - NOTE, udp_incoming_address and udp_outgoing_address can not + see also; dns_outgoing_address + + NOTE, dns_incoming_address and dns_outgoing_address can not have the same value since they both use the same port. DOC_END NAME: udp_outgoing_address +TYPE: obsolete +DOC_START + Use dns_outgoing_address for DNS sending address. + See icp_port, htcp_port, or snmp_port for details on outgoing address for those protocols. +DOC_END + +NAME: dns_outgoing_address TYPE: address -LOC: Config.Addrs.udp_outgoing +LOC: Config.dns.outgoingAddr DEFAULT: no_addr DOC_START - udp_outgoing_address is used for UDP packets sent out to other - caches. + dns_outgoing_address is used for DNS packets sent. The default behavior is to not bind to any specific address. - Instead it will use the same socket as udp_incoming_address. - Only change this if you want to have UDP queries sent using another - address than where this Squid listens for UDP queries from other - caches. + Instead it will use the same socket as dns_incoming_address. + Only change this if you want to have DNS queries sent using another + address than where this Squid listens for DNS responses. NOTE: udp_outgoing_address is used by the ICP, HTCP, and DNS modules. Altering it will affect all of them in the same manner. === modified file 'src/comm/ModPoll.cc' --- src/comm/ModPoll.cc 2012-04-26 01:04:17 +0000 +++ src/comm/ModPoll.cc 2012-05-06 00:28:20 +0000 @@ -172,11 +172,10 @@ static int fdIsUdpListen(int fd) { - if (icpIncomingConn != NULL && icpIncomingConn->fd == fd) - return 1; - - if (icpOutgoingConn != NULL && icpOutgoingConn->fd == fd) - return 1; + for (const AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (s->listenConn != NULL && s->listenConn->fd == fd) + return 1; + } return 0; } @@ -283,11 +282,10 @@ int nevents; udp_io_events = 0; - if (Comm::IsConnOpen(icpIncomingConn)) - fds[nfds++] = icpIncomingConn->fd; - - if (icpIncomingConn != icpOutgoingConn && Comm::IsConnOpen(icpOutgoingConn)) - fds[nfds++] = icpOutgoingConn->fd; + for (const AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (Comm::IsConnOpen(s->listenConn)) + fds[nfds++] = s->listenConn->fd; + } if (nfds == 0) return; @@ -319,11 +317,9 @@ // XXX: only poll sockets that won't be deferred. But how do we identify them? - for (j = 0; j < NHttpSockets; j++) { - if (HttpSockets[j] < 0) - continue; - - fds[nfds++] = HttpSockets[j]; + for (const AnyP::PortCfg *s = Config.Sockaddr.http; s; s = s->next) { + if (Comm::IsConnOpen(s->listenConn)) + fds[nfds++] = s->listenConn->fd; } nevents = comm_check_incoming_poll_handlers(nfds, fds); === modified file 'src/comm/ModSelect.cc' --- src/comm/ModSelect.cc 2012-04-25 05:29:20 +0000 +++ src/comm/ModSelect.cc 2012-04-25 05:49:52 +0000 @@ -170,11 +170,10 @@ static int fdIsUdpListener(int fd) { - if (icpIncomingConn != NULL && fd == icpIncomingConn->fd) - return 1; - - if (icpOutgoingConn != NULL && fd == icpOutgoingConn->fd) - return 1; + for (const AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (s->listenConn != NULL && s->listenConn->fd == fd) + return 1; + } return 0; } @@ -278,11 +277,10 @@ int nevents; udp_io_events = 0; - if (Comm::IsConnOpen(icpIncomingConn)) - fds[nfds++] = icpIncomingConn->fd; - - if (Comm::IsConnOpen(icpOutgoingConn) && icpIncomingConn != icpOutgoingConn) - fds[nfds++] = icpOutgoingConn->fd; + for (const AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (Comm::IsConnOpen(s->listenConn)) + fds[nfds++] = s->listenConn->fd; + } if (nfds == 0) return; === modified file 'src/dns_internal.cc' --- src/dns_internal.cc 2012-03-05 11:36:38 +0000 +++ src/dns_internal.cc 2012-03-21 07:07:46 +0000 @@ -842,10 +842,10 @@ Comm::ConnectionPointer conn = new Comm::Connection(); - if (!Config.Addrs.udp_outgoing.IsNoAddr()) - conn->local = Config.Addrs.udp_outgoing; + if (!Config.dns.outgoingAddr.IsNoAddr()) + conn->local = Config.dns.outgoingAddr; else - conn->local = Config.Addrs.udp_incoming; + conn->local = Config.dns.incomingAddr; conn->remote = nameservers[ns].S; @@ -1480,10 +1480,10 @@ if (DnsSocketA < 0 && DnsSocketB < 0) { Ip::Address addrV6; // since we don't want to alter Config.Addrs.udp_* and dont have one of our own. - if (!Config.Addrs.udp_outgoing.IsNoAddr()) - addrV6 = Config.Addrs.udp_outgoing; + if (!Config.dns.outgoingAddr.IsNoAddr()) + addrV6 = Config.dns.outgoingAddr; else - addrV6 = Config.Addrs.udp_incoming; + addrV6 = Config.dns.incomingAddr; Ip::Address addrV4 = addrV6; addrV4.SetIPv4(); @@ -1639,6 +1639,8 @@ idns_query *q = cbdataAlloc(idns_query); memcpy(q->name, master->name, sizeof(q->name)); memcpy(q->orig, master->orig, sizeof(q->orig)); + q->callback = NULL; + q->callback_data = NULL; q->master = master; q->query_id = idnsQueryID(); q->sz = rfc3596BuildAAAAQuery(q->name, q->buf, sizeof(q->buf), q->query_id, &q->query, Config.dns.packet_max); === modified file 'src/htcp.cc' --- src/htcp.cc 2012-04-25 05:29:20 +0000 +++ src/htcp.cc 2012-05-06 05:52:23 +0000 @@ -231,11 +231,9 @@ RR_RESPONSE }; -static void htcpIncomingConnectionOpened(const Comm::ConnectionPointer &conn, int errNo); +static void htcpPortOpened(const Comm::ConnectionPointer &conn, int errNo); static uint32_t msg_id_counter = 0; -static Comm::ConnectionPointer htcpOutgoingConn = NULL; -static Comm::ConnectionPointer htcpIncomingConn = NULL; #define N_QUERIED_KEYS 8192 static uint32_t queried_id[N_QUERIED_KEYS]; static cache_key queried_keys[N_QUERIED_KEYS][SQUID_MD5_DIGEST_LENGTH]; @@ -244,7 +242,7 @@ static MemAllocator *htcpDetailPool = NULL; static int old_squid_format = 0; - +bool htcpActive = false; static ssize_t htcpBuildPacket(char *buf, size_t buflen, htcpStuff * stuff); static htcpSpecifier *htcpUnpackSpecifier(char *buf, int sz); @@ -272,7 +270,7 @@ static void htcpRecv(int fd, void *data); -static void htcpSend(const char *buf, int len, Ip::Address &to); +static void htcpSend(const Comm::ConnectionPointer &htcpOutgoingConn, const char *buf, int len, Ip::Address &to); static void htcpTstReply(htcpDataHeader *, StoreEntry *, htcpSpecifier *, Ip::Address &); @@ -600,7 +598,7 @@ } static void -htcpSend(const char *buf, int len, Ip::Address &to) +htcpSend(const Comm::ConnectionPointer &htcpOutgoingConn, const char *buf, int len, Ip::Address &to) { debugs(31, 3, HERE << to); htcpHexdump("htcpSend", buf, len); @@ -848,6 +846,20 @@ return (checklist.fastCheck() == ACCESS_ALLOWED); } +/// Locate an open HTCP port which can use for packets to the given destination +static Comm::ConnectionPointer +htcpLocateOutConn(const Ip::Address &sendingTo) +{ + // NP: we simplify the split-stack/dual-stack port management by just going split-stack + // even on systems where one port would have been fine. + for (AnyP::PortCfg *s = Config.Sockaddr.htcp; s; s = s->next) { + if (Comm::IsConnOpen(s->listenConn) && sendingTo.IsIPv4() == s->s.IsIPv4()) { + return s->listenConn; + } + } + return Comm::ConnectionPointer(); +} + static void htcpTstReply(htcpDataHeader * dhdr, StoreEntry * e, htcpSpecifier * spec, Ip::Address &from) { @@ -865,6 +877,10 @@ debugs(31, 3, "htcpTstReply: response = " << stuff.response); stuff.msg_id = dhdr->msg_id; + const Comm::ConnectionPointer htcpOutgoingConn = htcpLocateOutConn(from); + if (htcpOutgoingConn == NULL) + return; + if (spec) { mb.init(); packerToMemInit(&p, &mb); @@ -933,7 +949,7 @@ return; } - htcpSend(pkt, (int) pktlen, from); + htcpSend(htcpOutgoingConn, pkt, (int) pktlen, from); } static void @@ -949,6 +965,10 @@ if (dhdr->F1 == 0) return; + const Comm::ConnectionPointer htcpOutgoingConn = htcpLocateOutConn(from); + if (htcpOutgoingConn == NULL) + return; + memset(&stuff, '\0', sizeof(stuff)); stuff.op = HTCP_CLR; @@ -970,7 +990,7 @@ return; } - htcpSend(pkt, (int) pktlen, from); + htcpSend(htcpOutgoingConn, pkt, (int) pktlen, from); } static void @@ -1314,7 +1334,11 @@ continue; } - htcpSend(buf, sz, p->in_addr); + const Comm::ConnectionPointer htcpOutgoingConn = htcpLocateOutConn(p->in_addr); + if (htcpOutgoingConn == NULL) + continue; + + htcpSend(htcpOutgoingConn, buf, sz, p->in_addr); } } @@ -1472,57 +1496,22 @@ void htcpOpenPorts(void) { - if (Config.Port.htcp <= 0) { + if (!Config.Sockaddr.htcp) { debugs(31, DBG_IMPORTANT, "HTCP Disabled."); return; } - htcpIncomingConn = new Comm::Connection; - htcpIncomingConn->local = Config.Addrs.udp_incoming; - htcpIncomingConn->local.SetPort(Config.Port.htcp); - - if (!Ip::EnableIpv6 && !htcpIncomingConn->local.SetIPv4()) { - debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpIncomingConn->local << " is not an IPv4 address."); - fatal("HTCP port cannot be opened."); - } - /* split-stack for now requires default IPv4-only HTCP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpIncomingConn->local.IsAnyAddr()) { - htcpIncomingConn->local.SetIPv4(); - } - - AsyncCall::Pointer call = asyncCall(31, 2, - "htcpIncomingConnectionOpened", - Comm::UdpOpenDialer(&htcpIncomingConnectionOpened)); - - Ipc::StartListening(SOCK_DGRAM, - IPPROTO_UDP, - htcpIncomingConn, - Ipc::fdnInHtcpSocket, call); - - if (!Config.Addrs.udp_outgoing.IsNoAddr()) { - htcpOutgoingConn = new Comm::Connection; - htcpOutgoingConn->local = Config.Addrs.udp_outgoing; - htcpOutgoingConn->local.SetPort(Config.Port.htcp); - - if (!Ip::EnableIpv6 && !htcpOutgoingConn->local.SetIPv4()) { - debugs(31, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << htcpOutgoingConn->local << " is not an IPv4 address."); - fatal("HTCP port cannot be opened."); - } - /* split-stack for now requires default IPv4-only HTCP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && htcpOutgoingConn->local.IsAnyAddr()) { - htcpOutgoingConn->local.SetIPv4(); - } - - enter_suid(); - comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, htcpOutgoingConn, "Outgoing HTCP Socket"); - leave_suid(); - - if (!Comm::IsConnOpen(htcpOutgoingConn)) - fatal("Cannot open Outgoing HTCP Socket"); - - Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0); - - debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local); + for (AnyP::PortCfg *s = Config.Sockaddr.htcp; s; s = s->next) { + s->listenConn = new Comm::Connection; + + AsyncCall::Pointer call = asyncCall(31, 2, + "htcpPortOpened", + Comm::UdpOpenDialer(&htcpPortOpened)); + + Ipc::StartListening(SOCK_DGRAM, + IPPROTO_UDP, + s->listenConn, + Ipc::fdnInHtcpSocket, call); } if (!htcpDetailPool) { @@ -1530,25 +1519,27 @@ } } -static void -htcpIncomingConnectionOpened(const Comm::ConnectionPointer &conn, int) +void +htcpPortOpened(const Comm::ConnectionPointer &conn, int errNo) { - if (!Comm::IsConnOpen(conn)) - fatal("Cannot open HTCP Socket"); - - Comm::SetSelect(conn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0); - - debugs(31, DBG_CRITICAL, "Accepting HTCP messages on " << conn->local); - - if (Config.Addrs.udp_outgoing.IsNoAddr()) { - htcpOutgoingConn = conn; - debugs(31, DBG_IMPORTANT, "Sending HTCP messages from " << htcpOutgoingConn->local); - } + if (Comm::IsConnOpen(conn)) { + Comm::SetSelect(conn->fd, COMM_SELECT_READ, htcpRecv, NULL, 0); + debugs(31, DBG_CRITICAL, "Accepting HTCP messages on " << conn->local); + fd_note(conn->fd, "HTCP Port"); + htcpActive = true; + } else + debugs(31, DBG_CRITICAL, "ERROR: Cannot open HTCP port " << conn->local); } int htcpQuery(StoreEntry * e, HttpRequest * req, peer * p) { + const Comm::ConnectionPointer htcpOutgoingConn = htcpLocateOutConn(p->in_addr); + if (htcpOutgoingConn == NULL) { + debugs(15, DBG_CRITICAL, "HTCP is disabled! Cannot send HTCP request to peer."); + return 0; + } + cache_key *save_key; static char pkt[8192]; ssize_t pktlen; @@ -1559,9 +1550,6 @@ MemBuf mb; http_state_flags flags; - if (!Comm::IsConnOpen(htcpIncomingConn)) - return 0; - old_squid_format = p->options.htcp_oldsquid; memset(&flags, '\0', sizeof(flags)); snprintf(vbuf, sizeof(vbuf), "%d/%d", @@ -1588,7 +1576,7 @@ return -1; } - htcpSend(pkt, (int) pktlen, p->in_addr); + htcpSend(htcpOutgoingConn, pkt, (int) pktlen, p->in_addr); queried_id[stuff.msg_id % N_QUERIED_KEYS] = stuff.msg_id; save_key = queried_keys[stuff.msg_id % N_QUERIED_KEYS]; @@ -1614,7 +1602,8 @@ MemBuf mb; http_state_flags flags; - if (!Comm::IsConnOpen(htcpIncomingConn)) + const Comm::ConnectionPointer htcpOutgoingConn = htcpLocateOutConn(p->in_addr); + if (htcpOutgoingConn == NULL) return; old_squid_format = p->options.htcp_oldsquid; @@ -1667,51 +1656,24 @@ return; } - htcpSend(pkt, (int) pktlen, p->in_addr); + htcpSend(htcpOutgoingConn, pkt, (int) pktlen, p->in_addr); } -/* - * htcpSocketShutdown only closes the 'in' socket if it is - * different than the 'out' socket. +/** + * Close all HTCP ports. + * This terminates all HTCP traffic. */ void -htcpSocketShutdown(void) -{ - if (!Comm::IsConnOpen(htcpIncomingConn)) - return; - - debugs(12, DBG_IMPORTANT, "Stop accepting HTCP on " << htcpIncomingConn->local); - /* - * Here we just unlink htcpIncomingConn because the HTCP 'in' - * and 'out' sockets might be just one FD. This prevents this - * function from executing repeatedly. When we are really ready to - * exit or restart, main will comm_close the 'out' descriptor. - */ - htcpIncomingConn = NULL; - - /* - * Normally we only write to the outgoing HTCP socket, but - * we also have a read handler there to catch messages sent - * to that specific interface. During shutdown, we must - * disable reading on the outgoing socket. - */ - /* XXX Don't we need this handler to read replies while shutting down? - * I think there should be a separate hander for reading replies.. - */ - assert(Comm::IsConnOpen(htcpOutgoingConn)); - - Comm::SetSelect(htcpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0); -} - -void htcpClosePorts(void) { - htcpSocketShutdown(); + for (AnyP::PortCfg *s = Config.Sockaddr.htcp; s; s = s->next) { + if (!Comm::IsConnOpen(s->listenConn)) + continue; - if (htcpOutgoingConn != NULL) { - debugs(12, DBG_IMPORTANT, "Stop sending HTCP from " << htcpOutgoingConn->local); - htcpOutgoingConn = NULL; + s->listenConn->close(); + debugs(12, DBG_IMPORTANT, "Stop accepting HTCP on " << s->listenConn->local); } + htcpActive = false; } static void === modified file 'src/htcp.h' --- src/htcp.h 2012-04-25 05:29:20 +0000 +++ src/htcp.h 2012-04-25 05:50:54 +0000 @@ -55,6 +55,9 @@ } cto; }; +/// whether any HTCP ports are currently open +extern bool htcpActive; + /// \bug redundant typedef typedef class HtcpReplyData htcpReplyData; === modified file 'src/icp_v2.cc' --- src/icp_v2.cc 2012-04-25 05:29:20 +0000 +++ src/icp_v2.cc 2012-04-25 05:51:18 +0000 @@ -56,7 +56,7 @@ #include "ipcache.h" #include "rfc1738.h" -static void icpIncomingConnectionOpened(const Comm::ConnectionPointer &conn, int errNo); +static void icpPortOpened(const Comm::ConnectionPointer &conn, int errNo); /// \ingroup ServerProtocolICPInternal2 static void icpLogIcp(const Ip::Address &, log_type, int, const char *, int); @@ -75,11 +75,8 @@ static icpUdpData *IcpQueueHead = NULL; /// \ingroup ServerProtocolICPInternal2 static icpUdpData *IcpQueueTail = NULL; +bool icpActive = false; -/// \ingroup ServerProtocolICPInternal2 -Comm::ConnectionPointer icpIncomingConn = NULL; -/// \ingroup ServerProtocolICPInternal2 -Comm::ConnectionPointer icpOutgoingConn = NULL; /* icp_common_t */ _icp_common_t::_icp_common_t() : opcode(ICP_INVALID), version(0), length(0), reqnum(0), flags(0), pad(0), shostid(0) @@ -223,7 +220,7 @@ while ((q = IcpQueueHead) != NULL) { int delay = tvSubUsec(q->queue_time, current_time); /* increment delay to prevent looping */ - const int x = icpUdpSend(fd, q->address, (icp_common_t *) q->msg, q->logcode, ++delay); + const int x = icpUdpSend(q->peerDetail, q->address, (icp_common_t *) q->msg, q->logcode, ++delay); IcpQueueHead = q->next; xfree(q); @@ -277,31 +274,48 @@ return (icp_common_t *)buf; } +Comm::ConnectionPointer +icpLocateOutConn(const Ip::Address &sendingTo) +{ + // NP: we simplify the split-stack/dual-stack port management by just going split-stack + // even on systems where one port would have been fine. + for (AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (Comm::IsConnOpen(s->listenConn) && sendingTo.IsIPv4() == s->s.IsIPv4()) { + return s->listenConn; + } + } + return Comm::ConnectionPointer(); +} + int -icpUdpSend(int fd, - const Ip::Address &to, - icp_common_t * msg, - log_type logcode, - int delay) +icpUdpSend(const peer *p, const Ip::Address &from, icp_common_t * msg, log_type logcode, int delay) { + const Comm::ConnectionPointer icpOutConn = icpLocateOutConn(p?p->in_addr:from); + if (icpOutConn == NULL) + return 0; + icpUdpData *queue; int x; int len; len = (int) ntohs(msg->length); - debugs(12, 5, "icpUdpSend: FD " << fd << " sending " << - icp_opcode_str[msg->opcode] << ", " << len << " bytes to " << to); - - x = comm_udp_sendto(fd, to, msg, len); + debugs(12, 5, HERE << "FD " << icpOutConn->fd << ", " << icpOutConn->local << " sending " << + icp_opcode_str[msg->opcode] << ", " << len << " bytes to " << (p?p->in_addr:from)); + + if (p && p->type == PEER_MULTICAST) + mcastSetTtl(icpOutConn->fd, p->mcast.ttl); + + x = comm_udp_sendto(icpOutConn->fd, (p?p->in_addr:from), msg, len); if (x >= 0) { /* successfully written */ - icpLogIcp(to, logcode, len, (char *) (msg + 1), delay); + icpLogIcp((p?p->in_addr:from), logcode, len, (char *) (msg + 1), delay); icpCount(msg, SENT, (size_t) len, delay); safe_free(msg); } else if (0 == delay) { /* send failed, but queue it */ queue = (icpUdpData *) xcalloc(1, sizeof(icpUdpData)); - queue->address = to; + queue->peerDetail = p; + queue->address = (p?p->in_addr:from); queue->msg = msg; queue->len = (int) ntohs(msg->length); queue->queue_time = current_time; @@ -318,7 +332,7 @@ IcpQueueTail = queue; } - Comm::SetSelect(fd, COMM_SELECT_WRITE, icpUdpSendQueue, NULL, 0); + Comm::SetSelect(icpOutConn->fd, COMM_SELECT_WRITE, icpUdpSendQueue, NULL, 0); statCounter.icp.replies_queued++; } else { /* don't queue it */ @@ -392,7 +406,8 @@ icpCreateAndSend(icp_opcode opcode, int flags, char const *url, int reqnum, int pad, int fd, const Ip::Address &from) { icp_common_t *reply = _icp_common_t::createMessage(opcode, flags, url, reqnum, pad); - icpUdpSend(fd, from, reply, icpLogFromICPCode(opcode), 0); + + icpUdpSend((peer *)NULL, from, reply, icpLogFromICPCode(opcode), 0); } void @@ -643,9 +658,14 @@ icp_version = (int) buf[1]; /* cheat! */ - if (icpOutgoingConn->local == from) + // TODO: find a faster way to ignore packets that we sent + bool ourPacket = false; + for (const AnyP::PortCfg *s = Config.Sockaddr.icp; s && !ourPacket; s=s->next) + ourPacket = (s->listenConn->local == from); + + if (ourPacket) // ignore ICP packets which loop back (multicast usually) - debugs(12, 4, "icpHandleUdp: Ignoring UDP packet sent by myself"); + debugs(12, 4, HERE << "Ignoring ICP packet sent by myself"); else if (icp_version == ICP_VERSION_2) icpHandleIcpV2(sock, from, buf, len); else if (icp_version == ICP_VERSION_3) @@ -659,120 +679,57 @@ void icpOpenPorts(void) { - uint16_t port; - - if ((port = Config.Port.icp) <= 0) + if (!Config.Sockaddr.icp) { + debugs(31, DBG_IMPORTANT, "ICP Disabled."); return; - - icpIncomingConn = new Comm::Connection; - icpIncomingConn->local = Config.Addrs.udp_incoming; - icpIncomingConn->local.SetPort(port); - - if (!Ip::EnableIpv6 && !icpIncomingConn->local.SetIPv4()) { - debugs(12, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << icpIncomingConn->local << " is not an IPv4 address."); - fatal("ICP port cannot be opened."); - } - /* split-stack for now requires default IPv4-only ICP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && icpIncomingConn->local.IsAnyAddr()) { - icpIncomingConn->local.SetIPv4(); - } - - AsyncCall::Pointer call = asyncCall(12, 2, - "icpIncomingConnectionOpened", - Comm::UdpOpenDialer(&icpIncomingConnectionOpened)); - - Ipc::StartListening(SOCK_DGRAM, - IPPROTO_UDP, - icpIncomingConn, - Ipc::fdnInIcpSocket, call); - - if ( !Config.Addrs.udp_outgoing.IsNoAddr() ) { - icpOutgoingConn = new Comm::Connection; - icpOutgoingConn->local = Config.Addrs.udp_outgoing; - icpOutgoingConn->local.SetPort(port); - - if (!Ip::EnableIpv6 && !icpOutgoingConn->local.SetIPv4()) { - debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << icpOutgoingConn->local << " is not an IPv4 address."); - fatal("ICP port cannot be opened."); - } - /* split-stack for now requires default IPv4-only ICP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && icpOutgoingConn->local.IsAnyAddr()) { - icpOutgoingConn->local.SetIPv4(); - } - - enter_suid(); - comm_open_listener(SOCK_DGRAM, IPPROTO_UDP, icpOutgoingConn, "Outgoing ICP Port"); - leave_suid(); - - if (!Comm::IsConnOpen(icpOutgoingConn)) - fatal("Cannot open Outgoing ICP Port"); - - debugs(12, DBG_CRITICAL, "Sending ICP messages from " << icpOutgoingConn->local); - - Comm::SetSelect(icpOutgoingConn->fd, COMM_SELECT_READ, icpHandleUdp, NULL, 0); - fd_note(icpOutgoingConn->fd, "Outgoing ICP socket"); + } + + for (AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + s->listenConn = new Comm::Connection; + + AsyncCall::Pointer call = asyncCall(12, 2, + "icpPortOpened", + Comm::UdpOpenDialer(&icpPortOpened)); + + Ipc::StartListening(SOCK_DGRAM, + IPPROTO_UDP, + s->listenConn, + Ipc::fdnInIcpSocket, call); } } static void -icpIncomingConnectionOpened(const Comm::ConnectionPointer &conn, int errNo) +icpPortOpened(const Comm::ConnectionPointer &conn, int errNo) { - if (!Comm::IsConnOpen(conn)) - fatal("Cannot open ICP Port"); - - Comm::SetSelect(conn->fd, COMM_SELECT_READ, icpHandleUdp, NULL, 0); - - for (const wordlist *s = Config.mcast_group_list; s; s = s->next) - ipcache_nbgethostbyname(s->key, mcastJoinGroups, NULL); // XXX: pass the conn for mcastJoinGroups usage. - - debugs(12, DBG_IMPORTANT, "Accepting ICP messages on " << conn->local); - - fd_note(conn->fd, "Incoming ICP port"); - - if (Config.Addrs.udp_outgoing.IsNoAddr()) { - icpOutgoingConn = conn; - debugs(12, DBG_IMPORTANT, "Sending ICP messages from " << icpOutgoingConn->local); - } + if (Comm::IsConnOpen(conn)) { + Comm::SetSelect(conn->fd, COMM_SELECT_READ, icpHandleUdp, NULL, 0); + for (const wordlist *s = Config.mcast_group_list; s; s = s->next) { + // XXX: yuck. we need a better way to do this. + Comm::ConnectionPointer *tmp = new Comm::ConnectionPointer(conn); + ipcache_nbgethostbyname(s->key, mcastJoinGroups, new generic_cbdata(tmp)); + } + debugs(12, DBG_IMPORTANT, "Accepting ICP messages on " << conn->local); + fd_note(conn->fd, "ICP port"); + icpActive = true; + } else + debugs(12, DBG_CRITICAL, "ERROR: Cannot open ICP port " << conn->local); } /** - * icpConnectionShutdown only closes the 'in' socket if it is - * different than the 'out' socket. + * Close all ICP ports. + * This terminates all ICP traffic. */ void -icpConnectionShutdown(void) -{ - if (!Comm::IsConnOpen(icpIncomingConn)) - return; - - debugs(12, DBG_IMPORTANT, "Stop receiving ICP on " << icpIncomingConn->local); - - /** Release the 'in' socket for lazy closure. - * in and out sockets may be sharing one same FD. - * This prevents this function from executing repeatedly. - */ - icpIncomingConn = NULL; - - /** - * Normally we only write to the outgoing ICP socket, but - * we also have a read handler there to catch messages sent - * to that specific interface. During shutdown, we must - * disable reading on the outgoing socket. - */ - assert(Comm::IsConnOpen(icpOutgoingConn)); - - Comm::SetSelect(icpOutgoingConn->fd, COMM_SELECT_READ, NULL, NULL, 0); -} - -void icpClosePorts(void) { - icpConnectionShutdown(); + for (AnyP::PortCfg *s = Config.Sockaddr.icp; s; s = s->next) { + if (!Comm::IsConnOpen(s->listenConn)) + continue; - if (icpOutgoingConn != NULL) { - debugs(12, DBG_IMPORTANT, "Stop sending ICP from " << icpOutgoingConn->local); - icpOutgoingConn = NULL; + s->listenConn->close(); + debugs(12, DBG_IMPORTANT, "Stop accepting ICP on " << s->listenConn->local); } + icpActive = false; } static void === modified file 'src/main.cc' --- src/main.cc 2012-04-25 05:29:20 +0000 +++ src/main.cc 2012-04-25 05:53:33 +0000 @@ -139,7 +139,6 @@ #endif static char *opt_syslog_facility = NULL; -static int icpPortNumOverride = 1; /* Want to detect "-u 0" */ static int configured_once = 0; #if MALLOC_DBG static int malloc_debug_level = 0; @@ -393,7 +392,7 @@ case 'a': /** \par a * Add optional HTTP port as given following the option */ - add_http_port(optarg); + add_generic_port(optarg,"http"); break; case 'd': @@ -532,13 +531,8 @@ case 'u': /** \par u - * Store the ICP port number given in global option icpPortNumOverride - * ensuring its a positive number. */ - icpPortNumOverride = atoi(optarg); - - if (icpPortNumOverride < 0) - icpPortNumOverride = 0; - + * Add optional ICP port as given following the option */ + add_generic_port(optarg,"icp"); break; case 'v': @@ -707,9 +701,9 @@ } if (IamWorkerProcess()) { clientHttpConnectionsClose(); - icpConnectionShutdown(); + icpClosePorts(); #if USE_HTCP - htcpSocketShutdown(); + htcpClosePorts(); #endif icmpEngine.Close(); @@ -961,9 +955,6 @@ setEffectiveUser(); - if (icpPortNumOverride != 1) - Config.Port.icp = (unsigned short) icpPortNumOverride; - _db_init(Debug::cache_log, Debug::debugOptions); fd_open(fileno(debug_log), FD_LOG, Debug::cache_log); === modified file 'src/multicast.cc' --- src/multicast.cc 2012-01-20 18:55:04 +0000 +++ src/multicast.cc 2012-03-21 07:07:47 +0000 @@ -54,14 +54,20 @@ } void -mcastJoinGroups(const ipcache_addrs *ia, const DnsLookupDetails &, void *datanotused) +mcastJoinGroups(const ipcache_addrs *ia, const DnsLookupDetails &, void *data) { #ifdef IP_MULTICAST_TTL + // XXX: yuck. when we have a UDP receiver Job that will be the data. + generic_cbdata *d = static_cast(data); + Comm::ConnectionPointer *conn; + d->unwrap(&conn); // deletes itself + struct ip_mreq mr; int i; if (ia == NULL) { debugs(7, 0, "comm_join_mcast_groups: Unknown host"); + delete conn; return; } @@ -77,13 +83,13 @@ mr.imr_interface.s_addr = INADDR_ANY; - if (setsockopt(icpIncomingConn->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mr, sizeof(struct ip_mreq)) < 0) - debugs(7, DBG_IMPORTANT, "ERROR: Join failed for " << icpIncomingConn << ", Multicast IP=" << ia->in_addrs[i]); + if (setsockopt((*conn)->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &mr, sizeof(struct ip_mreq)) < 0) + debugs(7, DBG_IMPORTANT, "ERROR: Join failed for " << (*conn)->local << ", Multicast IP=" << ia->in_addrs[i]); char c = 0; - if (setsockopt(icpIncomingConn->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c, 1) < 0) - debugs(7, DBG_IMPORTANT, "ERROR: " << icpIncomingConn << " can't disable multicast loopback: " << xstrerror()); + if (setsockopt((*conn)->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c, 1) < 0) + debugs(7, DBG_IMPORTANT, "ERROR: " << (*conn)->local << " can't disable multicast loopback: " << xstrerror()); } - + delete conn; #endif } === modified file 'src/neighbors.cc' --- src/neighbors.cc 2012-04-25 05:29:20 +0000 +++ src/neighbors.cc 2012-04-25 05:32:36 +0000 @@ -520,7 +520,11 @@ "Peer Cache Statistics", neighborDumpPeers, 0, 1); - if (Comm::IsConnOpen(icpIncomingConn)) { +#if USE_HTCP + if (htcpActive || icpActive) { +#else + if (icpActive) { +#endif Mgr::RegisterAction("non_peers", "List of Unknown sites sending ICP messages", neighborDumpNonPeers, 0, 1); @@ -537,7 +541,11 @@ neighborsRegisterWithCacheManager(); - if (Comm::IsConnOpen(icpIncomingConn)) { +#if USE_HTCP + if (htcpActive || icpActive) { +#else + if (icpActive) { +#endif for (thisPeer = Config.peers; thisPeer; thisPeer = next) { next = thisPeer->next; @@ -622,29 +630,22 @@ #if USE_HTCP if (p->options.htcp && !p->options.htcp_only_clr) { - if (Config.Port.htcp <= 0) { - debugs(15, DBG_CRITICAL, "HTCP is disabled! Cannot send HTCP request to peer."); - continue; - } - debugs(15, 3, "neighborsUdpPing: sending HTCP query"); if (htcpQuery(entry, request, p) <= 0) continue; // unable to send. } else #endif { - if (Config.Port.icp <= 0 || !Comm::IsConnOpen(icpOutgoingConn)) { + if (!icpActive) { debugs(15, DBG_CRITICAL, "ICP is disabled! Cannot send ICP request to peer."); continue; } else { - if (p->type == PEER_MULTICAST) - mcastSetTtl(icpOutgoingConn->fd, p->mcast.ttl); - if (p->icp.port == echo_port) { debugs(15, 4, "neighborsUdpPing: Looks like a dumb cache, send DECHO ping"); query = _icp_common_t::createMessage(ICP_DECHO, 0, url, reqnum, 0); - icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); + if (icpUdpSend(p, p->in_addr, query, LOG_ICP_QUERY, 0) <= 0) + continue; // unable to send. } else { flags = 0; @@ -654,7 +655,8 @@ query = _icp_common_t::createMessage(ICP_QUERY, flags, url, reqnum, 0); - icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); + if (icpUdpSend(p, p->in_addr, query, LOG_ICP_QUERY, 0) <= 0) + continue; // unable to send. } } } @@ -1388,11 +1390,10 @@ mem->start_ping = current_time; mem->ping_reply_callback = peerCountHandleIcpReply; mem->ircb_data = psstate; - mcastSetTtl(icpOutgoingConn->fd, p->mcast.ttl); p->mcast.id = mem->id; reqnum = icpSetCacheKey((const cache_key *)fake->key); query = _icp_common_t::createMessage(ICP_QUERY, 0, url, reqnum, 0); - icpUdpSend(icpOutgoingConn->fd, p->in_addr, query, LOG_ICP_QUERY, 0); + icpUdpSend(p, p->in_addr, query, LOG_ICP_QUERY, 0); fake->ping_status = PING_WAITING; eventAdd("peerCountMcastPeersDone", peerCountMcastPeersDone, === modified file 'src/protos.h' --- src/protos.h 2012-04-25 05:29:20 +0000 +++ src/protos.h 2012-04-25 05:32:36 +0000 @@ -66,7 +66,7 @@ class MemBuf; SQUIDCEXTERN void wordlistCat(const wordlist *, MemBuf * mb); SQUIDCEXTERN void self_destruct(void); -SQUIDCEXTERN void add_http_port(char *portspec); +SQUIDCEXTERN void add_generic_port(char *portspec, const char *protocol); extern int xatoi(const char *token); extern long xatol(const char *token); === modified file 'src/send-announce.cc' --- src/send-announce.cc 2012-01-20 18:55:04 +0000 +++ src/send-announce.cc 2012-03-21 07:07:47 +0000 @@ -34,6 +34,7 @@ */ #include "squid-old.h" +#include "anyp/PortCfg.h" #include "comm/Connection.h" #include "event.h" #include "fde.h" @@ -46,10 +47,7 @@ void start_announce(void *datanotused) { - if (0 == Config.onoff.announce) - return; - - if (!Comm::IsConnOpen(icpOutgoingConn)) + if (!Config.onoff.announce || !icpActive) return; ipcache_nbgethostbyname(Config.Announce.host, send_announce, NULL); @@ -75,15 +73,29 @@ return; } - debugs(27, 1, "Sending Announcement to " << host); + // XXX: re-work this send functionality to support + // - multiple IP results, + // - multiple listening ports, + // - multiple transport types, + // - non-ICP probe ports + // Does IRcache announce need the whole matrix for backward compatibility or can we alter/extend the lines here freely? + Ip::Address S = ia->in_addrs[0]; + S.SetPort(port); + + debugs(27, DBG_IMPORTANT, "Sending Announcement to " << host); sndbuf[0] = '\0'; snprintf(tbuf, 256, "cache_version SQUID/%s\n", version_string); strcat(sndbuf, tbuf); - assert(Config.Sockaddr.http); - snprintf(tbuf, 256, "Running on %s %d %d\n", + const Comm::ConnectionPointer conn = icpLocateOutConn(S); + if (!Comm::IsConnOpen(conn)) { + debugs(27, DBG_IMPORTANT, "send_announce: Cannot send to " << host << " primary IP '" << S << "'"); + return; + } + + snprintf(tbuf, 256, "Running on %s %d %u\n", getMyHostname(), getMyPort(), - (int) Config.Port.icp); + conn->local.GetPort()); // NP: advertise the port this peer should be able to contact strcat(sndbuf, tbuf); if (Config.adminEmail) { @@ -110,10 +122,6 @@ } } - Ip::Address S = ia->in_addrs[0]; - S.SetPort(port); - assert(Comm::IsConnOpen(icpOutgoingConn)); - - if (comm_udp_sendto(icpOutgoingConn->fd, S, sndbuf, strlen(sndbuf) + 1) < 0) - debugs(27, 1, "ERROR: Failed to announce to " << S << " from " << icpOutgoingConn->local << ": " << xstrerror()); + if (comm_udp_sendto(conn->fd, S, sndbuf, strlen(sndbuf) + 1) < 0) + debugs(27, DBG_IMPORTANT, "ERROR: Failed to announce to " << S << " from " << conn->local << ": " << xstrerror()); } === modified file 'src/snmp_core.cc' --- src/snmp_core.cc 2012-04-25 05:29:20 +0000 +++ src/snmp_core.cc 2012-04-25 05:32:36 +0000 @@ -31,6 +31,7 @@ */ #include "squid-old.h" #include "acl/FilledChecklist.h" +#include "anyp/PortCfg.h" #include "base/CbcPointer.h" #include "comm.h" #include "comm/Connection.h" @@ -45,9 +46,7 @@ mib_tree_entry *mib_tree_head; mib_tree_entry *mib_tree_last; - -Comm::ConnectionPointer snmpIncomingConn; -Comm::ConnectionPointer snmpOutgoingConn; +bool snmpActive = false; static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType = atNone); static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, AggrType aggrType, int children,...); @@ -68,14 +67,7 @@ static mib_tree_entry *snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current); extern "C" void snmpSnmplibDebug(int lvl, char *buf); -/* - * The functions used during startup: - * snmpInit - * snmpConnectionOpen - * snmpConnectionClose - */ - -/* +/** * Turns the MIB into a Tree structure. Called during the startup process. */ void @@ -269,81 +261,46 @@ void snmpOpenPorts(void) { - debugs(49, 5, "snmpConnectionOpen: Called"); - - if (Config.Port.snmp <= 0) + if (!Config.Sockaddr.snmp) return; - snmpIncomingConn = new Comm::Connection; - snmpIncomingConn->local = Config.Addrs.snmp_incoming; - snmpIncomingConn->local.SetPort(Config.Port.snmp); - - if (!Ip::EnableIpv6 && !snmpIncomingConn->local.SetIPv4()) { - debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpIncomingConn->local << " is not an IPv4 address."); - fatal("SNMP port cannot be opened."); - } - /* split-stack for now requires IPv4-only SNMP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpIncomingConn->local.IsAnyAddr()) { - snmpIncomingConn->local.SetIPv4(); - } - - AsyncCall::Pointer call = asyncCall(49, 2, "snmpIncomingConnectionOpened", - Comm::UdpOpenDialer(&snmpPortOpened)); - Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpIncomingConn, Ipc::fdnInSnmpSocket, call); - - if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { - snmpOutgoingConn = new Comm::Connection; - snmpOutgoingConn->local = Config.Addrs.snmp_outgoing; - snmpOutgoingConn->local.SetPort(Config.Port.snmp); - - if (!Ip::EnableIpv6 && !snmpOutgoingConn->local.SetIPv4()) { - debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << snmpOutgoingConn->local << " is not an IPv4 address."); - fatal("SNMP port cannot be opened."); - } - /* split-stack for now requires IPv4-only SNMP */ - if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && snmpOutgoingConn->local.IsAnyAddr()) { - snmpOutgoingConn->local.SetIPv4(); - } - AsyncCall::Pointer call = asyncCall(49, 2, "snmpOutgoingConnectionOpened", + for (AnyP::PortCfg *s = Config.Sockaddr.snmp; s; s = s->next) { + s->listenConn = new Comm::Connection; + + AsyncCall::Pointer call = asyncCall(12, 2, + "snmpPortOpened", Comm::UdpOpenDialer(&snmpPortOpened)); - Ipc::StartListening(SOCK_DGRAM, IPPROTO_UDP, snmpOutgoingConn, Ipc::fdnOutSnmpSocket, call); - } else { - snmpOutgoingConn = snmpIncomingConn; - debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local); + + Ipc::StartListening(SOCK_DGRAM, + IPPROTO_UDP, + s->listenConn, + Ipc::fdnInSnmpSocket, call); } } static void snmpPortOpened(const Comm::ConnectionPointer &conn, int errNo) { - if (!Comm::IsConnOpen(conn)) - fatalf("Cannot open SNMP %s Port",(conn->fd == snmpIncomingConn->fd?"receiving":"sending")); - - Comm::SetSelect(conn->fd, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); - - if (conn->fd == snmpIncomingConn->fd) - debugs(1, DBG_IMPORTANT, "Accepting SNMP messages on " << snmpIncomingConn->local); - else if (conn->fd == snmpOutgoingConn->fd) - debugs(1, DBG_IMPORTANT, "Sending SNMP messages from " << snmpOutgoingConn->local); - else - fatalf("Lost SNMP port (%d) on FD %d", (int)conn->local.GetPort(), conn->fd); + if (Comm::IsConnOpen(conn)) { + Comm::SetSelect(conn->fd, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); + debugs(1, DBG_IMPORTANT, "Accepting SNMP messages on " << conn->local); + fd_note(conn->fd, "SNMP port"); + snmpActive = true; + } else + debugs(49, DBG_CRITICAL, "ERROR: Cannot open SNMP port " << conn->local); } void snmpClosePorts(void) { - if (Comm::IsConnOpen(snmpIncomingConn)) { - debugs(49, DBG_IMPORTANT, "Closing SNMP receiving port " << snmpIncomingConn->local); - snmpIncomingConn->close(); - } - snmpIncomingConn = NULL; + for (AnyP::PortCfg *s = Config.Sockaddr.snmp; s; s = s->next) { + if (!Comm::IsConnOpen(s->listenConn)) + continue; - if (Comm::IsConnOpen(snmpOutgoingConn) && snmpIncomingConn != snmpOutgoingConn) { - // Perform OUT port closure so as not to step on IN port when sharing a conn. - debugs(49, DBG_IMPORTANT, "Closing SNMP sending port " << snmpOutgoingConn->local); - snmpOutgoingConn->close(); + s->listenConn->close(); + debugs(12, DBG_IMPORTANT, "Stop accepting SNMP on " << s->listenConn->local); } - snmpOutgoingConn = NULL; + snmpActive = false; } /* === modified file 'src/snmp_core.h' --- src/snmp_core.h 2011-06-04 12:48:45 +0000 +++ src/snmp_core.h 2012-03-06 12:50:45 +0000 @@ -35,6 +35,7 @@ extern struct snmp_pdu* snmpAgentResponse(struct snmp_pdu* PDU); extern AggrType snmpAggrType(oid* Current, snint CurrentLen); -extern Comm::ConnectionPointer snmpOutgoingConn; +/// whether any SNMP ports are currently open +extern bool snmpActive; #endif /* SQUID_SNMP_CORE_H */ === modified file 'src/structs.h' --- src/structs.h 2012-04-26 01:04:17 +0000 +++ src/structs.h 2012-05-08 01:31:14 +0000 @@ -235,22 +235,17 @@ acl_size_t *ReplyBodySize; struct { - unsigned short icp; -#if USE_HTCP - - unsigned short htcp; -#endif -#if SQUID_SNMP - - unsigned short snmp; -#endif - } Port; - - struct { AnyP::PortCfg *http; #if USE_SSL AnyP::PortCfg *https; #endif + AnyP::PortCfg *icp; +#if USE_HTCP + AnyP::PortCfg *htcp; +#endif +#if SQUID_SNMP + AnyP::PortCfg *snmp; +#endif } Sockaddr; #if SQUID_SNMP @@ -352,13 +347,6 @@ } Announce; struct { - - Ip::Address udp_incoming; - Ip::Address udp_outgoing; -#if SQUID_SNMP - Ip::Address snmp_incoming; - Ip::Address snmp_outgoing; -#endif /* FIXME INET6 : this should really be a CIDR value */ Ip::Address client_netmask; } Addrs; @@ -643,6 +631,8 @@ int client_ip_max_connections; struct { + Ip::Address incomingAddr; + Ip::Address outgoingAddr; int v4_first; ///< Place IPv4 first in the order of DNS results. ssize_t packet_max; ///< maximum size EDNS advertised for DNS replies. } dns; === modified file 'src/tools.cc' --- src/tools.cc 2012-04-25 05:29:20 +0000 +++ src/tools.cc 2012-04-25 05:55:34 +0000 @@ -96,8 +96,14 @@ // clear icp_port's icpClosePorts(); +#if USE_HTCP + htcpClosePorts(); +#endif +#if SQUID_SNMP + snmpClosePorts(); +#endif - // XXX: Why not the HTCP, SNMP, DNS ports as well? + // XXX: Why not the DNS ports as well? // XXX: why does this differ from main closeServerConnections() anyway ? }