/*- * Copyright (c) 1993-1994, 1998 * The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/net-ip.cc,v 1.20 2003/10/12 21:13:09 xuanc Exp $ (LBL)"; #endif #include #ifndef WIN32 #include #endif #include #include #include #ifdef WIN32 #include #define close closesocket #else #include #include #include #include #include #include typedef int Socket; #endif #if defined(sun) && defined(__svr4__) #include #endif #include "config.h" #include "net.h" #include "inet.h" #include "tclcl.h" #include "scheduler.h" //#define NIPDEBUG 1 #ifdef NIPDEBUG #define NIDEBUG(x) { if (NIPDEBUG) fprintf(stderr, (x)); } #define NIDEBUG2(x,y) { if (NIPDEBUG) fprintf(stderr, (x), (y)); } #define NIDEBUG3(x,y,z) { if (NIPDEBUG) fprintf(stderr, (x), (y), (z)); } #define NIDEBUG4(w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (w), (x), (y), (z)); } #define NIDEBUG5(v,w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (v), (w), (x), (y), (z)); } #else #define NIDEBUG(x) { } #define NIDEBUG2(x,y) { } #define NIDEBUG3(x,y,z) { } #define NIDEBUG4(w,x,y,z) { } #define NIDEBUG5(v,w,x,y,z) { } #endif /* * Net-ip.cc: this file defines the IP and IP/UDP network * objects. IP provides a raw IP interface and support functions * [such as setting multicast parameters]. IP/UDP provides a standard * UDP datagram interface. */ // // IPNetwork: a low-level (raw) IP network object // class IPNetwork : public Network { public: IPNetwork(); inline int ttl() const { return (mttl_); } // current mcast ttl inline int noloopback_broken() { // no loopback filter? return (noloopback_broken_); } int setmttl(Socket, int); // set mcast ttl int setmloop(Socket, int); // set mcast loopback int command(int argc, const char*const* argv); // virtual in Network inline Socket rchannel() { return(rsock_); } // virtual in Network inline Socket schannel() { return(ssock_); } // virtual in Network int send(u_char* buf, int len); // virtual in Network int recv(u_char* buf, int len, sockaddr& from, double& ); // virtual in Network inline in_addr& laddr() { return (localaddr_); } inline in_addr& dstaddr() { return (destaddr_); } int add_membership(Socket, in_addr& grp); // join mcast int drop_membership(Socket, in_addr& grp); // leave mcast /* generally useful routines */ static int bindsock(Socket, in_addr&, u_int16_t, sockaddr_in&); static int connectsock(Socket, in_addr&, u_int16_t, sockaddr_in&); static int rbufsize(Socket, int); static int sbufsize(Socket, int); protected: in_addr destaddr_; // remote side, if set (network order) in_addr localaddr_; // local side (network order) int mttl_; // multicast ttl to use Socket rsock_; // socket to receive on Socket ssock_; // socket to send on int noloopback_broken_; // couldn't turn (off) mcast loopback int loop_; // do we want loopbacks? // (system usually assumes yes) void reset(int reconfigure); // reset + reconfig? virtual int open(int mode); // open sockets/endpoints virtual void reconfigure(); // restore state after reset int close(); time_t last_reset_; }; class UDPIPNetwork : public IPNetwork { public: UDPIPNetwork(); int send(u_char*, int); int recv(u_char*, int, sockaddr&, double&); int open(int mode); // mode only int command(int argc, const char*const* argv); void reconfigure(); void add_membership(Socket, in_addr&, u_int16_t); // udp version protected: int bind(in_addr&, u_int16_t port); // bind to addr/port, mcast ok int connect(in_addr& remoteaddr, u_int16_t port); // connect() u_int16_t lport_; // local port (network order) u_int16_t port_; // remote (dst) port (network order) }; static class IPNetworkClass : public TclClass { public: IPNetworkClass() : TclClass("Network/IP") {} TclObject* create(int, const char*const*) { return (new IPNetwork); } } nm_ip; static class UDPIPNetworkClass : public TclClass { public: UDPIPNetworkClass() : TclClass("Network/IP/UDP") {} TclObject* create(int, const char*const*) { return (new UDPIPNetwork); } } nm_ip_udp; IPNetwork::IPNetwork() : mttl_(0), rsock_(-1), ssock_(-1), noloopback_broken_(0), loop_(1) { localaddr_.s_addr = 0L; destaddr_.s_addr = 0L; NIDEBUG("IPNetwork: ctor\n"); } UDPIPNetwork::UDPIPNetwork() : lport_(htons(0)), port_(htons(0)) { NIDEBUG("UDPIPNetwork: ctor\n"); } /* * UDPIP::send -- send "len" bytes in buffer "buf" out the sending * channel. * * returns the number of bytes written */ int UDPIPNetwork::send(u_char* buf, int len) { int cc = ::send(schannel(), (char*)buf, len, 0); NIDEBUG5("UDPIPNetwork(%s): ::send(%d, buf, %d) returned %d\n", name(), schannel(), len, cc); if (cc < 0) { switch (errno) { case ECONNREFUSED: /* no one listening at some site - ignore */ #if defined(__osf__) || defined(_AIX) || defined(__FreeBSD__) /* * Here's an old comment... * * Due to a bug in kern/uipc_socket.c, on several * systems, datagram sockets incorrectly persist * in an error state on receipt of an ICMP * port-unreachable. This causes unicast connection * rendezvous problems, and worse, multicast * transmission problems because several systems * incorrectly send port unreachables for * multicast destinations. Our work around * is to simply close and reopen the socket * (by calling reset() below). * * This bug originated at CSRG in Berkeley * and was present in the BSD Reno networking * code release. It has since been fixed * in 4.4BSD and OSF-3.x. It is known to remain * in AIX-4.1.3. * * A fix is to change the following lines from * kern/uipc_socket.c: * * if (so_serror) * snderr(so->so_error); * * to: * * if (so->so_error) { * error = so->so_error; * so->so_error = 0; * splx(s); * goto release; * } * */ reset(1); #endif break; case ENETUNREACH: case EHOSTUNREACH: /* * These "errors" are totally meaningless. * There is some broken host sending * icmp unreachables for multicast destinations. * UDP probably aborted the send because of them -- * try exactly once more. E.g., the send we * just did cleared the errno for the previous * icmp unreachable, so we should be able to * send now. */ cc = ::send(schannel(), (char*)buf, len, 0); break; default: fprintf(stderr, "UDPIPNetwork(%s): send failed: %s\n", name(), strerror(errno)); return (-1); } } return cc; // bytes sent } int UDPIPNetwork::recv(u_char* buf, int len, sockaddr& from, double& ts) { sockaddr_in sfrom; int fromlen = sizeof(sfrom); int cc = ::recvfrom(rsock_, (char*)buf, len, 0, (sockaddr*)&sfrom, (socklen_t*)&fromlen); NIDEBUG5("UDPIPNetwork(%s): ::recvfrom(%d, buf, %d) returned %d\n", name(), rsock_, len, cc); if (cc < 0) { if (errno != EWOULDBLOCK) { fprintf(stderr, "UDPIPNetwork(%s): recvfrom failed: %s\n", name(), strerror(errno)); } return (-1); } from = *((sockaddr*)&sfrom); /* * if we received multicast data and we don't want the look, * there is a chance it is * what we sent if "noloopback_broken_" is set. * If so, filter out the stuff we don't want right here. */ if (!loop_ && noloopback_broken_ && sfrom.sin_addr.s_addr == localaddr_.s_addr && sfrom.sin_port == lport_) { NIDEBUG2("UDPIPNetwork(%s): filtered out our own pkt\n", name()); return (0); // empty } ts = Scheduler::instance().clock(); return (cc); // number of bytes received } int UDPIPNetwork::open(int mode) { if (mode == O_RDONLY || mode == O_RDWR) { rsock_ = socket(AF_INET, SOCK_DGRAM, 0); if (rsock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: couldn't open rcv sock\n", name()); } nonblock(rsock_); int on = 1; if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: warning: unable set REUSEADDR: %s\n", name(), strerror(errno)); } #ifdef SO_REUSEPORT on = 1; if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: warning: unable set REUSEPORT: %s\n", name(), strerror(errno)); } #endif /* * XXX don't need this for the session socket. */ if (rbufsize(rsock_, 80*1024) < 0) { if (rbufsize(rsock_, 32*1024) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: unable to set r bufsize to %d: %s\n", name(), 32*1024, strerror(errno)); } } } if (mode == O_WRONLY || mode == O_RDWR) { ssock_ = socket(AF_INET, SOCK_DGRAM, 0); if (ssock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: couldn't open snd sock\n", name()); } nonblock(ssock_); int firsttry = 80 * 1024; int secondtry = 48 * 1024; if (sbufsize(ssock_, firsttry) < 0) { if (sbufsize(ssock_, secondtry) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: cannot set send sockbuf size to %d bytes, using default\n", name(), secondtry); } } } mode_ = mode; NIDEBUG5("UDPIPNetwork(%s): opened network w/mode %d, ssock:%d, rsock:%d\n", name(), mode_, rsock_, ssock_); return (0); } // // IP/UDP version of add_membership: try binding // void UDPIPNetwork::add_membership(Socket sock, in_addr& addr, u_int16_t port) { int failure = 0; sockaddr_in sin; if (bindsock(sock, addr, port, sin) < 0) failure = 1; if (failure) { in_addr addr2 = addr; addr2.s_addr = INADDR_ANY; if (bindsock(sock, addr2, port, sin) < 0) failure = 1; else failure = 0; } if (IPNetwork::add_membership(sock, addr) < 0) failure = 1; if (failure) { fprintf(stderr, "UDPIPNetwork(%s): add_membership: failed bind on mcast addr %s and INADDR_ANY\n", name(), inet_ntoa(addr)); } } // // server-side bind (or mcast subscription) // int UDPIPNetwork::bind(in_addr& addr, u_int16_t port) { NIDEBUG4("UDPIPNetwork(%s): attempt to bind to addr %s, port %d [net order]\n", name(), inet_ntoa(addr), ntohs(port)); if (rsock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): bind/listen called before net is open\n", name()); return (-1); } if (mode_ == O_WRONLY) { fprintf(stderr, "UDPIPNetwork(%s): attempted bind/listen but net is write-only\n", name()); return (-1); } #ifdef IP_ADD_MEMBERSHIP if (IN_CLASSD(ntohl(addr.s_addr))) { // MULTICAST case, call UDPIP vers of add_membership add_membership(rsock_, addr, port); } else #endif { // UNICAST case sockaddr_in sin; if (bindsock(rsock_, addr, port, sin) < 0) { port = ntohs(port); fprintf(stderr, "UDPIPNetwork(%s): bind: unable to bind %s [port:%hu]: %s\n", name(), inet_ntoa(addr), port, strerror(errno)); return (-1); } /* * MS Windows currently doesn't compy with the Internet Host * Requirements standard (RFC-1122) and won't let us include * the source address in the receive socket demux state. */ #ifndef WIN32 /* * (try to) connect the foreign host's address to this socket. */ (void)connectsock(rsock_, addr, 0, sin); #endif } localaddr_ = addr; lport_ = port; return (0); } // // client-side connect // int UDPIPNetwork::connect(in_addr& addr, u_int16_t port) { sockaddr_in sin; if (ssock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): connect called before net is open\n", name()); return (-1); } if (mode_ == O_RDONLY) { fprintf(stderr, "UDPIPNetwork(%s): attempted connect but net is read-only\n", name()); return (-1); } int rval = connectsock(ssock_, addr, port, sin); if (rval < 0) return (rval); destaddr_ = addr; port_ = port; last_reset_ = 0; return(rval); } int UDPIPNetwork::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { // $udpip port if (strcmp(argv[1], "port") == 0) { tcl.resultf("%d", ntohs(port_)); return (TCL_OK); } // $udpip lport if (strcmp(argv[1], "lport") == 0) { tcl.resultf("%d", ntohs(lport_)); return (TCL_OK); } } else if (argc == 4) { // $udpip listen addr port // $udpip bind addr port if (strcmp(argv[1], "listen") == 0 || strcmp(argv[1], "bind") == 0) { in_addr addr; if (strcmp(argv[2], "any") == 0) addr.s_addr = INADDR_ANY; else addr.s_addr = LookupHostAddr(argv[2]); u_int16_t port = htons(atoi(argv[3])); if (bind(addr, port) < 0) { tcl.resultf("%s %hu", inet_ntoa(addr), port); } else { tcl.result("0"); } return (TCL_OK); } // $udpip connect addr port if (strcmp(argv[1], "connect") == 0) { in_addr addr; addr.s_addr = LookupHostAddr(argv[2]); u_int16_t port = htons(atoi(argv[3])); if (connect(addr, port) < 0) { tcl.resultf("%s %hu", inet_ntoa(addr), port); } else { tcl.result("0"); } return (TCL_OK); } } return (IPNetwork::command(argc, argv)); } // // raw IP network recv() // int IPNetwork::recv(u_char* buf, int len, sockaddr& sa, double& ts) { if (mode_ == O_WRONLY) { fprintf(stderr, "IPNetwork(%s) recv while in writeonly mode!\n", name()); abort(); } int fromlen = sizeof(sa); int cc = ::recvfrom(rsock_, (char*)buf, len, 0, &sa, (socklen_t*)&fromlen); if (cc < 0) { if (errno != EWOULDBLOCK) perror("recvfrom"); return (-1); } ts = Scheduler::instance().clock(); return (cc); } // // we are given a "raw" IP datagram. // the raw interface appears to want the len and off fields // in *host* order, so make it this way here // note also, that it will compute the cksum "for" us... :( // int IPNetwork::send(u_char* buf, int len) { struct ip *ip = (struct ip*) buf; #ifdef __linux__ // For raw sockets on linux the send does not work, // all packets show up only on the loopback device and are not routed // to the correct host. Using sendto on a closed socket solves this problem ip->ip_len = (ip->ip_len); ip->ip_off = (ip->ip_off); sockaddr_in sin; memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = ip->ip_dst; return (::sendto(ssock_, (char*)buf, len, 0,(sockaddr *) &sin,sizeof(sin))); #else ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); return (::send(ssock_, (char*)buf, len, 0)); #endif } int IPNetwork::command(int argc, const char*const* argv) { Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "close") == 0) { close(); return (TCL_OK); } // Old approach uses tcl.result() to get result buffer first // char* cp = tcl.result(); // new approach uses tcl.result(const char*) directly. // xuanc, 10/07/2003 if (strcmp(argv[1], "destaddr") == 0) { tcl.result(inet_ntoa(destaddr_)); return (TCL_OK); } if (strcmp(argv[1], "localaddr") == 0) { tcl.result(inet_ntoa(localaddr_)); return (TCL_OK); } if (strcmp(argv[1], "mttl") == 0) { tcl.resultf("%d", mttl_); return (TCL_OK); } /* for backward compatability */ if (strcmp(argv[1], "ismulticast") == 0) { tcl.result(IN_CLASSD(ntohl(destaddr_.s_addr)) ? "1" : "0"); return (TCL_OK); } if (strcmp(argv[1], "addr") == 0) { tcl.result(inet_ntoa(destaddr_)); return (TCL_OK); } if (strcmp(argv[1], "ttl") == 0) { tcl.resultf("%d", mttl_); return (TCL_OK); } if (strcmp(argv[1], "interface") == 0) { tcl.result(inet_ntoa(localaddr_)); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "open") == 0) { int mode = parsemode(argv[2]); if (open(mode) < 0) return (TCL_ERROR); return (TCL_OK); } if (strcmp(argv[1], "add-membership") == 0) { in_addr addr; addr.s_addr = LookupHostAddr(argv[2]); if (add_membership(rchannel(), addr) < 0) tcl.result("0"); else tcl.result("1"); return (TCL_OK); } if (strcmp(argv[1], "drop-membership") == 0) { in_addr addr; addr.s_addr = LookupHostAddr(argv[2]); if (drop_membership(rchannel(), addr) < 0) tcl.result("0"); else tcl.result("1"); return (TCL_OK); } if (strcmp(argv[1], "loopback") == 0) { int val = atoi(argv[2]); if (strcmp(argv[2], "true") == 0) val = 1; else if (strcmp(argv[2], "false") == 0) val = 0; if (setmloop(schannel(), val) < 0) tcl.result("0"); else tcl.result("1"); return (TCL_OK); } } return (Network::command(argc, argv)); } int IPNetwork::setmttl(Socket s, int ttl) { /* set the multicast TTL */ #ifdef WIN32 u_int t = ttl; #else u_char t = ttl; #endif t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, (char*)&t, sizeof(t)) < 0) { fprintf(stderr, "IPNetwork(%s): couldn't set multicast ttl to %d\n", name(), t); return (-1); } return (0); } /* * open a RAW IP socket (will require privilege). * turn on HDRINCL, specifying that we will be writing the raw IP header */ int IPNetwork::open(int mode) { // obtain a raw socket we can use to send ip datagrams Socket fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (fd < 0) { perror("socket(RAW)"); if (::getuid() != 0 && ::geteuid() != 0) { fprintf(stderr, "IPNetwork(%s): open: use of the Network/IP object requires super-user privs\n", name()); } return (-1); } // turn on HDRINCL option (we will be writing IP header) // in FreeBSD 2.2.5 (and possibly others), the IP id field // is set by the kernel routine rip_output() // only if it is non-zero, so we should be ok. int one = 1; if (::setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) { fprintf(stderr, "IPNetwork(%s): open: unable to turn on IP_HDRINCL: %s\n", name(), strerror(errno)); return (-1); } #ifndef __linux__ // sort of curious, but do a connect() even though we have // HDRINCL on. Otherwise, we get ENOTCONN when doing a send() sockaddr_in sin; in_addr ia = { INADDR_ANY }; if (connectsock(fd, ia, 0, sin) < 0) { fprintf(stderr, "IPNetwork(%s): open: unable to connect : %s\n", name(), strerror(errno)); } #endif rsock_ = ssock_ = fd; mode_ = mode; NIDEBUG5("IPNetwork(%s): opened with mode %d, rsock_:%d, ssock_:%d\n", name(), mode_, rsock_, ssock_); return 0; } /* * close both sending and receiving sockets */ int IPNetwork::close() { if (ssock_ >= 0) { (void)::close(ssock_); ssock_ = -1; } if (rsock_ >= 0) { (void)::close(rsock_); rsock_ = -1; } return (0); } /* * add multicast group membership on the socket */ int IPNetwork::add_membership(Socket fd, in_addr& addr) { #if defined(IP_ADD_MEMBERSHIP) if (IN_CLASSD(ntohl(addr.s_addr))) { #ifdef notdef /* * Try to bind the multicast address as the socket * dest address. On many systems this won't work * so fall back to a destination of INADDR_ANY if * the first bind fails. */ sockaddr_in sin; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr = addr; if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { sin.sin_addr.s_addr = INADDR_ANY; if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) { fprintf(stderr, "IPNetwork(%s): add_membership: unable to bind to addr %s: %s\n", name(), inet_ntoa(sin.sin_addr), strerror(errno)); return (-1); } } #endif /* * XXX This is bogus multicast setup that really * shouldn't have to be done (group membership should be * implicit in the IP class D address, route should contain * ttl & no loopback flag, etc.). Steve Deering has promised * to fix this for the 4.4bsd release. We're all waiting * with bated breath. */ struct ip_mreq mr; mr.imr_multiaddr = addr; mr.imr_interface.s_addr = INADDR_ANY; if (::setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) { fprintf(stderr, "IPNetwork(%s): add_membership: unable to add membership for addr %s: %s\n", name(), inet_ntoa(addr), strerror(errno)); return (-1); } NIDEBUG3("IPNetwork(%s): add_membership for grp %s done\n", name(), inet_ntoa(addr)); return (0); } #else fprintf(stderr, "IPNetwork(%s): add_membership: host does not support IP multicast\n", name()); #endif NIDEBUG3("IPNetwork(%s): add_membership for grp %s failed\n", name(), inet_ntoa(addr)); return (-1); } /* * drop membership from the specified group on the specified socket */ int IPNetwork::drop_membership(Socket fd, in_addr& addr) { #if defined(IP_DROP_MEMBERSHIP) if (IN_CLASSD(ntohl(addr.s_addr))) { struct ip_mreq mr; mr.imr_multiaddr = addr; mr.imr_interface.s_addr = INADDR_ANY; if (::setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) { fprintf(stderr, "IPNetwork(%s): drop_membership: unable to drop membership for addr %s: %s\n", name(), inet_ntoa(addr), strerror(errno)); return (-1); } NIDEBUG3("IPNetwork(%s): drop_membership for grp %s done\n", name(), inet_ntoa(addr)); return (0); } #else fprintf(stderr, "IPNetwork(%s): drop_membership: host does not support IP multicast\n", name()); #endif NIDEBUG3("IPNetwork(%s): drop_membership for grp %s failed\n", name(), inet_ntoa(addr)); return (-1); } int IPNetwork::bindsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin) { memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr = addr; return(::bind(s, (struct sockaddr *)&sin, sizeof(sin))); } int IPNetwork::connectsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin) { memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr = addr; return(::connect(s, (struct sockaddr *)&sin, sizeof(sin))); } int IPNetwork::sbufsize(Socket s, int cnt) { return(::setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&cnt, sizeof(cnt))); } int IPNetwork::rbufsize(Socket s, int cnt) { return(::setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&cnt, sizeof(cnt))); } int IPNetwork::setmloop(Socket s, int loop) { #ifdef IP_MULTICAST_LOOP u_char c = loop; if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &c, sizeof(c)) < 0) { /* * If we cannot turn off loopback (Like on the * Microsoft TCP/IP stack), then declare this * option broken so that our packets can be * filtered on the recv path. */ if (c != loop) { noloopback_broken_ = 1; loop_ = c; } return (-1); } noloopback_broken_ = 0; #else fprintf(stderr, "IPNetwork(%s): msetloop: host does not support IP multicast\n", name()); #endif loop_ = c; return (0); } void IPNetwork::reset(int restart) { time_t t = time(0); int d = int(t - last_reset_); NIDEBUG2("IPNetwork(%s): reset\n", name()); if (d > 3) { // Steve: why? last_reset_ = t; if (ssock_ >= 0) (void)::close(ssock_); if (rsock_ >= 0) (void)::close(rsock_); if (open(mode_) < 0) { fprintf(stderr, "IPNetwork(%s): couldn't reset\n", name()); mode_ = -1; return; } if (restart) (void) reconfigure(); } } /* * after a reset, we may want to re-establish our state * [set up addressing, etc]. Do this here */ void IPNetwork::reconfigure() { } void UDPIPNetwork::reconfigure() { }