net-ip.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:25k
- /*-
- * 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: /cvsroot/nsnam/ns-2/emulate/net-ip.cc,v 1.20 2003/10/12 21:13:09 xuanc Exp $ (LBL)";
- #endif
- #include <stdio.h>
- #ifndef WIN32
- #include <unistd.h>
- #endif
- #include <time.h>
- #include <errno.h>
- #include <string.h>
- #ifdef WIN32
- #include <io.h>
- #define close closesocket
- #else
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <netinet/in.h>
- #include <netinet/in_systm.h>
- #include <netinet/ip.h>
- typedef int Socket;
- #endif
- #if defined(sun) && defined(__svr4__)
- #include <sys/systeminfo.h>
- #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: ctorn");
- }
- UDPIPNetwork::UDPIPNetwork() :
- lport_(htons(0)),
- port_(htons(0))
- {
- NIDEBUG("UDPIPNetwork: ctorn");
- }
- /*
- * 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 %dn",
- 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: %sn",
- 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 %dn",
- name(), rsock_, len, cc);
- if (cc < 0) {
- if (errno != EWOULDBLOCK) {
- fprintf(stderr,
- "UDPIPNetwork(%s): recvfrom failed: %sn",
- 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 pktn", 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 sockn",
- 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: %sn",
- 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: %sn",
- 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: %sn",
- 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 sockn",
- 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 defaultn",
- name(), secondtry);
- }
- }
- }
- mode_ = mode;
- NIDEBUG5("UDPIPNetwork(%s): opened network w/mode %d, ssock:%d, rsock:%dn",
- 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_ANYn",
- 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 openn",
- name());
- return (-1);
- }
- if (mode_ == O_WRONLY) {
- fprintf(stderr,
- "UDPIPNetwork(%s): attempted bind/listen but net is write-onlyn",
- 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]: %sn",
- 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 openn",
- name());
- return (-1);
- }
- if (mode_ == O_RDONLY) {
- fprintf(stderr,
- "UDPIPNetwork(%s): attempted connect but net is read-onlyn",
- 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 %dn",
- 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 privsn",
- 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: %sn",
- 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 : %sn",
- name(), strerror(errno));
- }
- #endif
- rsock_ = ssock_ = fd;
- mode_ = mode;
- NIDEBUG5("IPNetwork(%s): opened with mode %d, rsock_:%d, ssock_:%dn",
- 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: %sn",
- 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: %sn",
- name(), inet_ntoa(addr), strerror(errno));
- return (-1);
- }
- NIDEBUG3("IPNetwork(%s): add_membership for grp %s donen",
- name(), inet_ntoa(addr));
- return (0);
- }
- #else
- fprintf(stderr, "IPNetwork(%s): add_membership: host does not support IP multicastn",
- name());
- #endif
- NIDEBUG3("IPNetwork(%s): add_membership for grp %s failedn",
- 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: %sn",
- name(), inet_ntoa(addr), strerror(errno));
- return (-1);
- }
- NIDEBUG3("IPNetwork(%s): drop_membership for grp %s donen",
- name(), inet_ntoa(addr));
- return (0);
- }
- #else
- fprintf(stderr, "IPNetwork(%s): drop_membership: host does not support IP multicastn",
- name());
- #endif
- NIDEBUG3("IPNetwork(%s): drop_membership for grp %s failedn",
- 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 multicastn",
- 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): resetn", 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 resetn",
- 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()
- {
- }