net-ip.cc

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1993-1994, 1998
00003  * The Regents of the University of California.
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. All advertising materials mentioning features or use of this software
00015  *    must display the following acknowledgement:
00016  *      This product includes software developed by the University of
00017  *      California, Berkeley and the Network Research Group at
00018  *      Lawrence Berkeley Laboratory.
00019  * 4. Neither the name of the University nor of the Laboratory may be used
00020  *    to endorse or promote products derived from this software without
00021  *    specific prior written permission.
00022  *
00023  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00024  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00026  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00027  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00028  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00029  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00030  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00031  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00032  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00033  * SUCH DAMAGE.
00034  */
00035 #ifndef lint
00036 static const char rcsid[] =
00037     "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/net-ip.cc,v 1.20 2003/10/12 21:13:09 xuanc Exp $ (LBL)";
00038 #endif
00039 
00040 #include <stdio.h>
00041 #ifndef WIN32
00042 #include <unistd.h>
00043 #endif
00044 #include <time.h>
00045 #include <errno.h>
00046 #include <string.h>
00047 #ifdef WIN32
00048 #include <io.h>
00049 #define close closesocket
00050 #else
00051 #include <sys/param.h>
00052 #include <sys/socket.h>
00053 #include <sys/ioctl.h>
00054 #include <netinet/in.h>
00055 #include <netinet/in_systm.h>
00056 #include <netinet/ip.h>
00057 typedef int Socket;
00058 #endif
00059 #if defined(sun) && defined(__svr4__)
00060 #include <sys/systeminfo.h>
00061 #endif
00062 
00063 #include "config.h"
00064 #include "net.h"
00065 #include "inet.h"
00066 #include "tclcl.h"
00067 #include "scheduler.h"
00068 
00069 //#define   NIPDEBUG    1
00070 #ifdef NIPDEBUG
00071 #define NIDEBUG(x) { if (NIPDEBUG) fprintf(stderr, (x)); }
00072 #define NIDEBUG2(x,y) { if (NIPDEBUG) fprintf(stderr, (x), (y)); }
00073 #define NIDEBUG3(x,y,z) { if (NIPDEBUG) fprintf(stderr, (x), (y), (z)); }
00074 #define NIDEBUG4(w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (w), (x), (y), (z)); }
00075 #define NIDEBUG5(v,w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (v), (w), (x), (y), (z)); }
00076 #else
00077 #define NIDEBUG(x) { }
00078 #define NIDEBUG2(x,y) { }
00079 #define NIDEBUG3(x,y,z) { }
00080 #define NIDEBUG4(w,x,y,z) { }
00081 #define NIDEBUG5(v,w,x,y,z) { }
00082 #endif
00083 
00084 
00085 /*
00086  * Net-ip.cc: this file defines the IP and IP/UDP network
00087  * objects.  IP provides a raw IP interface and support functions
00088  * [such as setting multicast parameters].  IP/UDP provides a standard
00089  * UDP datagram interface.
00090  */
00091 
00092 //
00093 // IPNetwork: a low-level (raw) IP network object
00094 //
00095 
00096 class IPNetwork : public Network {
00097 public:
00098     IPNetwork();
00099 
00100         inline int ttl() const { return (mttl_); }  // current mcast ttl
00101     inline int noloopback_broken() {        // no loopback filter?
00102         return (noloopback_broken_);
00103     }
00104     int setmttl(Socket, int);           // set mcast ttl
00105     int setmloop(Socket, int);          // set mcast loopback
00106     int command(int argc, const char*const* argv);  // virtual in Network
00107     inline Socket rchannel() { return(rsock_); }    // virtual in Network
00108     inline Socket schannel() { return(ssock_); }    // virtual in Network
00109 
00110         int send(u_char* buf, int len);         // virtual in Network
00111         int recv(u_char* buf, int len, sockaddr& from, double& ); // virtual in Network
00112 
00113         inline in_addr& laddr() { return (localaddr_); }
00114         inline in_addr& dstaddr() { return (destaddr_); }
00115 
00116     int add_membership(Socket, in_addr& grp);   // join mcast
00117     int drop_membership(Socket, in_addr& grp);  // leave mcast
00118 
00119     /* generally useful routines */
00120 
00121     static int bindsock(Socket, in_addr&, u_int16_t, sockaddr_in&);
00122     static int connectsock(Socket, in_addr&, u_int16_t, sockaddr_in&);
00123     static int rbufsize(Socket, int);
00124     static int sbufsize(Socket, int);
00125 
00126 protected:
00127     in_addr destaddr_;      // remote side, if set (network order)
00128     in_addr localaddr_;     // local side (network order)
00129         int mttl_;          // multicast ttl to use
00130     Socket rsock_;          // socket to receive on
00131     Socket ssock_;          // socket to send on
00132         int noloopback_broken_;     // couldn't turn (off) mcast loopback
00133     int loop_;          // do we want loopbacks?
00134                     // (system usually assumes yes)
00135 
00136     void reset(int reconfigure);            // reset + reconfig?
00137     virtual int open(int mode); // open sockets/endpoints
00138     virtual void reconfigure(); // restore state after reset
00139     int close();
00140 
00141     time_t last_reset_;
00142 };
00143 
00144 class UDPIPNetwork : public IPNetwork {
00145 public:
00146     UDPIPNetwork();
00147 
00148     int send(u_char*, int);
00149     int recv(u_char*, int, sockaddr&, double&);
00150     int open(int mode);         // mode only
00151 
00152     int command(int argc, const char*const* argv);
00153     void reconfigure();
00154     void add_membership(Socket, in_addr&, u_int16_t); // udp version
00155 protected:
00156     int bind(in_addr&, u_int16_t port); // bind to addr/port, mcast ok
00157     int connect(in_addr& remoteaddr, u_int16_t port);   // connect()
00158         u_int16_t lport_;   // local port (network order)
00159         u_int16_t port_;    // remote (dst) port (network order)
00160 };
00161 
00162 static class IPNetworkClass : public TclClass {
00163     public:
00164     IPNetworkClass() : TclClass("Network/IP") {}
00165     TclObject* create(int, const char*const*) {
00166         return (new IPNetwork);
00167     }
00168 } nm_ip;
00169 
00170 static class UDPIPNetworkClass : public TclClass {
00171     public:
00172     UDPIPNetworkClass() : TclClass("Network/IP/UDP") {}
00173     TclObject* create(int, const char*const*) {
00174         return (new UDPIPNetwork);
00175     }
00176 } nm_ip_udp;
00177 
00178 IPNetwork::IPNetwork() :
00179     mttl_(0),
00180         rsock_(-1), 
00181         ssock_(-1),
00182         noloopback_broken_(0),
00183     loop_(1)
00184 {
00185     localaddr_.s_addr = 0L;
00186     destaddr_.s_addr = 0L;
00187     NIDEBUG("IPNetwork: ctor\n");
00188 }
00189 
00190 UDPIPNetwork::UDPIPNetwork() :
00191         lport_(htons(0)), 
00192         port_(htons(0))
00193 {
00194     NIDEBUG("UDPIPNetwork: ctor\n");
00195 }
00196 
00197 /*
00198  * UDPIP::send -- send "len" bytes in buffer "buf" out the sending
00199  * channel.
00200  *
00201  * returns the number of bytes written
00202  */
00203 int
00204 UDPIPNetwork::send(u_char* buf, int len)
00205 {
00206     int cc = ::send(schannel(), (char*)buf, len, 0);
00207     NIDEBUG5("UDPIPNetwork(%s): ::send(%d, buf, %d) returned %d\n",
00208         name(), schannel(), len, cc);
00209 
00210     if (cc < 0) {
00211         switch (errno) {
00212         case ECONNREFUSED:
00213             /* no one listening at some site - ignore */
00214 #if defined(__osf__) || defined(_AIX) || defined(__FreeBSD__)
00215             /*
00216              * Here's an old comment...
00217              *
00218              * Due to a bug in kern/uipc_socket.c, on several
00219              * systems, datagram sockets incorrectly persist
00220              * in an error state on receipt of an ICMP
00221              * port-unreachable.  This causes unicast connection
00222              * rendezvous problems, and worse, multicast
00223              * transmission problems because several systems
00224              * incorrectly send port unreachables for 
00225              * multicast destinations.  Our work around
00226              * is to simply close and reopen the socket
00227              * (by calling reset() below).
00228              *
00229              * This bug originated at CSRG in Berkeley
00230              * and was present in the BSD Reno networking
00231              * code release.  It has since been fixed
00232              * in 4.4BSD and OSF-3.x.  It is known to remain
00233              * in AIX-4.1.3.
00234              *
00235              * A fix is to change the following lines from
00236              * kern/uipc_socket.c:
00237              *
00238              *  if (so_serror)
00239              *      snderr(so->so_error);
00240              *
00241              * to:
00242              *
00243              *  if (so->so_error) {
00244              *      error = so->so_error;
00245              *      so->so_error = 0;
00246              *      splx(s);
00247              *      goto release;
00248              *  }
00249              *
00250              */
00251             reset(1);
00252 #endif
00253             break;
00254 
00255         case ENETUNREACH:
00256         case EHOSTUNREACH:
00257             /*
00258              * These "errors" are totally meaningless.
00259              * There is some broken host sending
00260              * icmp unreachables for multicast destinations.
00261              * UDP probably aborted the send because of them --
00262              * try exactly once more.  E.g., the send we
00263              * just did cleared the errno for the previous
00264              * icmp unreachable, so we should be able to
00265              * send now.
00266              */
00267             cc = ::send(schannel(), (char*)buf, len, 0);
00268             break;
00269 
00270         default:
00271             fprintf(stderr, "UDPIPNetwork(%s): send failed: %s\n",
00272                 name(), strerror(errno));
00273             return (-1);
00274         }
00275     }
00276     return cc;  // bytes sent
00277 }
00278 int
00279 UDPIPNetwork::recv(u_char* buf, int len, sockaddr& from, double& ts)
00280 {
00281     sockaddr_in sfrom;
00282     int fromlen = sizeof(sfrom);
00283     int cc = ::recvfrom(rsock_, (char*)buf, len, 0,
00284                 (sockaddr*)&sfrom, (socklen_t*)&fromlen);
00285     NIDEBUG5("UDPIPNetwork(%s): ::recvfrom(%d, buf, %d) returned %d\n",
00286         name(), rsock_, len, cc);
00287     if (cc < 0) {
00288         if (errno != EWOULDBLOCK) {
00289             fprintf(stderr,
00290                 "UDPIPNetwork(%s): recvfrom failed: %s\n",
00291                 name(), strerror(errno));
00292         }
00293         return (-1);
00294     }
00295     from = *((sockaddr*)&sfrom);
00296 
00297     /*
00298      * if we received multicast data and we don't want the look,
00299      * there is a chance it is
00300      * what we sent if "noloopback_broken_" is set.
00301      * If so, filter out the stuff we don't want right here.
00302      */
00303  
00304     if (!loop_ && noloopback_broken_ &&
00305         sfrom.sin_addr.s_addr == localaddr_.s_addr &&
00306         sfrom.sin_port == lport_) {
00307     NIDEBUG2("UDPIPNetwork(%s): filtered out our own pkt\n", name());
00308         return (0); // empty
00309     }
00310 
00311     ts = Scheduler::instance().clock();
00312     return (cc);    // number of bytes received
00313 }
00314 
00315 int
00316 UDPIPNetwork::open(int mode)
00317 {
00318     if (mode == O_RDONLY || mode == O_RDWR) {
00319         rsock_ = socket(AF_INET, SOCK_DGRAM, 0);
00320         if (rsock_ < 0) {
00321             fprintf(stderr,
00322     "UDPIPNetwork(%s): open: couldn't open rcv sock\n",
00323                 name());
00324         }
00325         nonblock(rsock_);
00326         int on = 1;
00327         if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
00328                 sizeof(on)) < 0) {
00329             fprintf(stderr,
00330     "UDPIPNetwork(%s): open: warning: unable set REUSEADDR: %s\n",
00331                 name(), strerror(errno));
00332         }
00333 #ifdef SO_REUSEPORT
00334         on = 1;
00335         if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEPORT, (char *)&on,
00336                    sizeof(on)) < 0) {
00337             fprintf(stderr,
00338     "UDPIPNetwork(%s): open: warning: unable set REUSEPORT: %s\n",
00339                 name(), strerror(errno));
00340         }
00341 #endif
00342         /*
00343          * XXX don't need this for the session socket.
00344          */ 
00345         if (rbufsize(rsock_, 80*1024) < 0) {
00346             if (rbufsize(rsock_, 32*1024) < 0) {
00347                 fprintf(stderr,
00348         "UDPIPNetwork(%s): open: unable to set r bufsize to %d: %s\n",
00349                     name(), 32*1024, strerror(errno));
00350             }
00351         }
00352     }
00353     if (mode == O_WRONLY || mode == O_RDWR) {
00354         ssock_ = socket(AF_INET, SOCK_DGRAM, 0);
00355         if (ssock_ < 0) {
00356             fprintf(stderr,
00357     "UDPIPNetwork(%s): open: couldn't open snd sock\n",
00358                 name());
00359         }
00360         nonblock(ssock_);
00361         int firsttry = 80 * 1024;
00362         int secondtry = 48 * 1024;
00363         
00364         if (sbufsize(ssock_, firsttry) < 0) {
00365             if (sbufsize(ssock_, secondtry) < 0) {
00366                 fprintf(stderr,
00367   "UDPIPNetwork(%s): open: cannot set send sockbuf size to %d bytes, using default\n",  
00368                 name(), secondtry);
00369             }
00370         }
00371 
00372     }
00373     mode_ = mode;
00374     NIDEBUG5("UDPIPNetwork(%s): opened network w/mode %d, ssock:%d, rsock:%d\n",
00375         name(), mode_, rsock_, ssock_);
00376     return (0);
00377 }
00378 
00379 //
00380 // IP/UDP version of add_membership: try binding
00381 //
00382 
00383 void
00384 UDPIPNetwork::add_membership(Socket sock, in_addr& addr, u_int16_t port)
00385 {
00386     int failure = 0;
00387     sockaddr_in sin;
00388     if (bindsock(sock, addr, port, sin) < 0)
00389         failure = 1;
00390     if (failure) {
00391         in_addr addr2 = addr;
00392         addr2.s_addr = INADDR_ANY;
00393         if (bindsock(sock, addr2, port, sin) < 0)
00394             failure = 1;
00395         else
00396             failure = 0;
00397     }
00398 
00399     if (IPNetwork::add_membership(sock, addr) < 0)
00400         failure = 1;
00401 
00402     if (failure) {
00403         fprintf(stderr,
00404         "UDPIPNetwork(%s): add_membership: failed bind on mcast addr %s and INADDR_ANY\n",
00405             name(), inet_ntoa(addr));
00406     }
00407 }
00408 
00409 //
00410 // server-side bind (or mcast subscription)
00411 //
00412 int
00413 UDPIPNetwork::bind(in_addr& addr, u_int16_t port)
00414 {
00415     NIDEBUG4("UDPIPNetwork(%s): attempt to bind to addr %s, port %d [net order]\n",
00416         name(), inet_ntoa(addr), ntohs(port));
00417     if (rsock_ < 0) {
00418         fprintf(stderr,
00419         "UDPIPNetwork(%s): bind/listen called before net is open\n",
00420             name());
00421         return (-1);
00422     }
00423     if (mode_ == O_WRONLY) {
00424         fprintf(stderr,
00425         "UDPIPNetwork(%s): attempted bind/listen but net is write-only\n",
00426             name());
00427         return (-1);
00428     }
00429 #ifdef IP_ADD_MEMBERSHIP
00430         if (IN_CLASSD(ntohl(addr.s_addr))) {
00431         // MULTICAST case, call UDPIP vers of add_membership
00432                 add_membership(rsock_, addr, port);
00433         } else
00434 #endif
00435         {
00436         // UNICAST case
00437                 sockaddr_in sin;
00438                 if (bindsock(rsock_, addr, port, sin) < 0) {
00439                         port = ntohs(port);
00440                         fprintf(stderr,
00441         "UDPIPNetwork(%s): bind: unable to bind %s [port:%hu]: %s\n",
00442                                 name(), inet_ntoa(addr),
00443                                 port, strerror(errno));
00444             return (-1);
00445                 }
00446                 /*
00447                  * MS Windows currently doesn't compy with the Internet Host
00448                  * Requirements standard (RFC-1122) and won't let us include
00449                  * the source address in the receive socket demux state.
00450                  */
00451 #ifndef WIN32
00452                 /*
00453                  * (try to) connect the foreign host's address to this socket.
00454                  */
00455                 (void)connectsock(rsock_, addr, 0, sin);
00456 #endif
00457         }
00458     localaddr_ = addr;
00459     lport_ = port;
00460     return (0);
00461 }
00462 
00463 //
00464 // client-side connect
00465 //
00466 int
00467 UDPIPNetwork::connect(in_addr& addr, u_int16_t port)
00468 {
00469     sockaddr_in sin;
00470     if (ssock_ < 0) {
00471         fprintf(stderr,
00472         "UDPIPNetwork(%s): connect called before net is open\n",
00473             name());
00474         return (-1);
00475     }
00476     if (mode_ == O_RDONLY) {
00477         fprintf(stderr,
00478         "UDPIPNetwork(%s): attempted connect but net is read-only\n",
00479             name());
00480         return (-1);
00481     }
00482 
00483     int rval = connectsock(ssock_, addr, port, sin);
00484     if (rval < 0)
00485         return (rval);
00486     destaddr_ = addr;
00487     port_ = port;
00488     last_reset_ = 0;
00489     return(rval);
00490 }
00491 
00492 int
00493 UDPIPNetwork::command(int argc, const char*const* argv)
00494 {
00495     Tcl& tcl = Tcl::instance();
00496     if (argc == 2) {
00497         // $udpip port
00498         if (strcmp(argv[1], "port") == 0) {
00499             tcl.resultf("%d", ntohs(port_));
00500             return (TCL_OK);
00501         }
00502         // $udpip lport
00503         if (strcmp(argv[1], "lport") == 0) {
00504             tcl.resultf("%d", ntohs(lport_));
00505             return (TCL_OK);
00506         }
00507     } else if (argc == 4) {
00508         // $udpip listen addr port
00509         // $udpip bind addr port
00510         if (strcmp(argv[1], "listen") == 0 ||
00511             strcmp(argv[1], "bind") == 0) {
00512             in_addr addr;
00513             if (strcmp(argv[2], "any") == 0)
00514                 addr.s_addr = INADDR_ANY;
00515             else
00516                 addr.s_addr = LookupHostAddr(argv[2]);
00517             u_int16_t port = htons(atoi(argv[3]));
00518             if (bind(addr, port) < 0) {
00519                 tcl.resultf("%s %hu",
00520                     inet_ntoa(addr), port);
00521             } else {
00522                 tcl.result("0");
00523             }
00524             return (TCL_OK);
00525         }
00526         // $udpip connect addr port
00527         if (strcmp(argv[1], "connect") == 0) {
00528             in_addr addr;
00529             addr.s_addr = LookupHostAddr(argv[2]);
00530             u_int16_t port = htons(atoi(argv[3]));
00531             if (connect(addr, port) < 0) {
00532                 tcl.resultf("%s %hu",
00533                     inet_ntoa(addr), port);
00534             } else {
00535                 tcl.result("0");
00536             }
00537             return (TCL_OK);
00538         }
00539     }
00540     return (IPNetwork::command(argc, argv));
00541 }
00542 
00543 //
00544 // raw IP network recv()
00545 //
00546 int
00547 IPNetwork::recv(u_char* buf, int len, sockaddr& sa, double& ts)
00548 {
00549     if (mode_ == O_WRONLY) {
00550         fprintf(stderr,
00551             "IPNetwork(%s) recv while in writeonly mode!\n",
00552             name());
00553         abort();
00554     }
00555     int fromlen = sizeof(sa);
00556     int cc = ::recvfrom(rsock_, (char*)buf, len, 0, &sa, (socklen_t*)&fromlen);
00557     if (cc < 0) {
00558         if (errno != EWOULDBLOCK)
00559             perror("recvfrom");
00560         return (-1);
00561     }
00562     ts = Scheduler::instance().clock();
00563     return (cc);
00564 }
00565 
00566 //
00567 // we are given a "raw" IP datagram.
00568 // the raw interface appears to want the len and off fields
00569 // in *host* order, so make it this way here
00570 // note also, that it will compute the cksum "for" us... :(
00571 //
00572 int
00573 IPNetwork::send(u_char* buf, int len)
00574 {
00575     struct ip *ip = (struct ip*) buf;
00576 #ifdef __linux__ 
00577 // For raw sockets on linux the send does not work,
00578 // all packets show up only on the loopback device and are not routed
00579 // to the correct host. Using sendto on a closed socket solves this problem
00580        ip->ip_len = (ip->ip_len);
00581        ip->ip_off = (ip->ip_off);
00582         sockaddr_in sin;
00583        memset((char *)&sin, 0, sizeof(sin));
00584        sin.sin_family = AF_INET;
00585         sin.sin_addr = ip->ip_dst;
00586        return (::sendto(ssock_, (char*)buf, len, 0,(sockaddr *) &sin,sizeof(sin)));
00587 #else
00588         ip->ip_len = ntohs(ip->ip_len);
00589         ip->ip_off = ntohs(ip->ip_off);
00590         return (::send(ssock_, (char*)buf, len, 0));
00591 #endif
00592 }
00593 
00594 int IPNetwork::command(int argc, const char*const* argv)
00595 {
00596     Tcl& tcl = Tcl::instance();
00597     if (argc == 2) {
00598         if (strcmp(argv[1], "close") == 0) {
00599             close();
00600             return (TCL_OK);
00601         }
00602         // Old approach uses tcl.result() to get result buffer first
00603         // char* cp = tcl.result();
00604         // new approach uses tcl.result(const char*) directly.
00605         // xuanc, 10/07/2003
00606         if (strcmp(argv[1], "destaddr") == 0) {
00607             tcl.result(inet_ntoa(destaddr_));
00608             return (TCL_OK);
00609         }
00610         if (strcmp(argv[1], "localaddr") == 0) {
00611             tcl.result(inet_ntoa(localaddr_));
00612             return (TCL_OK);
00613         }
00614         if (strcmp(argv[1], "mttl") == 0) {
00615             tcl.resultf("%d", mttl_);
00616             return (TCL_OK);
00617         }
00618         /* for backward compatability */
00619         if (strcmp(argv[1], "ismulticast") == 0) {
00620             tcl.result(IN_CLASSD(ntohl(destaddr_.s_addr)) ?
00621                 "1" : "0");
00622             return (TCL_OK);
00623         }
00624         if (strcmp(argv[1], "addr") == 0) {
00625             tcl.result(inet_ntoa(destaddr_));
00626             return (TCL_OK);
00627         }
00628         if (strcmp(argv[1], "ttl") == 0) {
00629             tcl.resultf("%d", mttl_);
00630             return (TCL_OK);
00631         }
00632         if (strcmp(argv[1], "interface") == 0) {
00633             tcl.result(inet_ntoa(localaddr_));
00634             return (TCL_OK);
00635         }
00636     } else if (argc == 3) {
00637         
00638         if (strcmp(argv[1], "open") == 0) {
00639             int mode = parsemode(argv[2]);
00640             if (open(mode) < 0)
00641                 return (TCL_ERROR);
00642             return (TCL_OK);
00643         }
00644         if (strcmp(argv[1], "add-membership") == 0) {
00645             in_addr addr;
00646             addr.s_addr = LookupHostAddr(argv[2]);
00647             if (add_membership(rchannel(), addr) < 0)
00648                 tcl.result("0");
00649             else
00650                 tcl.result("1");
00651             return (TCL_OK);
00652         }
00653         if (strcmp(argv[1], "drop-membership") == 0) {
00654             in_addr addr;
00655             addr.s_addr = LookupHostAddr(argv[2]);
00656             if (drop_membership(rchannel(), addr) < 0)
00657                 tcl.result("0");
00658             else
00659                 tcl.result("1");
00660             return (TCL_OK);
00661         }
00662         if (strcmp(argv[1], "loopback") == 0) {
00663             int val = atoi(argv[2]);
00664             if (strcmp(argv[2], "true") == 0)
00665                 val = 1;
00666             else if (strcmp(argv[2], "false") == 0)
00667                 val = 0;
00668             if (setmloop(schannel(), val) < 0)
00669                 tcl.result("0");
00670             else
00671                 tcl.result("1");
00672             return (TCL_OK);
00673         }
00674     }
00675     return (Network::command(argc, argv));
00676 }
00677 int
00678 IPNetwork::setmttl(Socket s, int ttl)
00679 {
00680         /* set the multicast TTL */  
00681 
00682 #ifdef WIN32
00683         u_int t = ttl; 
00684 #else 
00685         u_char t = ttl;
00686 #endif
00687 
00688         t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; 
00689         if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
00690                        (char*)&t, sizeof(t)) < 0) {
00691         fprintf(stderr,
00692             "IPNetwork(%s): couldn't set multicast ttl to %d\n",
00693             name(), t);
00694                 return (-1);
00695         }
00696     return (0);
00697 }
00698 
00699 /*
00700  * open a RAW IP socket (will require privilege).
00701  * turn on HDRINCL, specifying that we will be writing the raw IP header
00702  */
00703 
00704 int
00705 IPNetwork::open(int mode)
00706 {
00707     // obtain a raw socket we can use to send ip datagrams
00708     Socket fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
00709     if (fd < 0) {
00710         perror("socket(RAW)");
00711         if (::getuid() != 0 && ::geteuid() != 0) {
00712             fprintf(stderr,
00713       "IPNetwork(%s): open: use of the Network/IP object requires super-user privs\n",
00714             name());
00715         }
00716 
00717         return (-1);
00718     }
00719 
00720     // turn on HDRINCL option (we will be writing IP header)
00721     // in FreeBSD 2.2.5 (and possibly others), the IP id field
00722     // is set by the kernel routine rip_output()
00723     // only if it is non-zero, so we should be ok.
00724     int one = 1;
00725     if (::setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) {
00726         fprintf(stderr,
00727     "IPNetwork(%s): open: unable to turn on IP_HDRINCL: %s\n",
00728             name(), strerror(errno));
00729         return (-1);
00730     }
00731 #ifndef __linux__
00732     // sort of curious, but do a connect() even though we have
00733     // HDRINCL on.  Otherwise, we get ENOTCONN when doing a send()
00734     sockaddr_in sin;
00735     in_addr ia = { INADDR_ANY };
00736     if (connectsock(fd, ia, 0, sin) < 0) {
00737         fprintf(stderr,
00738     "IPNetwork(%s): open: unable to connect : %s\n",
00739             name(), strerror(errno));
00740     }
00741 #endif
00742     rsock_ = ssock_ = fd;
00743     mode_ = mode;
00744     NIDEBUG5("IPNetwork(%s): opened with mode %d, rsock_:%d, ssock_:%d\n",
00745         name(), mode_, rsock_, ssock_);
00746     return 0;
00747 }
00748 
00749 /*
00750  * close both sending and receiving sockets
00751  */
00752 
00753 int
00754 IPNetwork::close()
00755 {
00756     if (ssock_ >= 0) {
00757         (void)::close(ssock_);
00758         ssock_ = -1;
00759     }
00760     if (rsock_ >= 0) {
00761         (void)::close(rsock_);
00762         rsock_ = -1;
00763     }
00764     return (0);
00765 }
00766 
00767 /*
00768  * add multicast group membership on the socket
00769  */
00770 
00771 int
00772 IPNetwork::add_membership(Socket fd, in_addr& addr)
00773 {
00774 
00775 #if defined(IP_ADD_MEMBERSHIP)
00776     if (IN_CLASSD(ntohl(addr.s_addr))) {
00777 #ifdef notdef
00778         /*
00779          * Try to bind the multicast address as the socket
00780          * dest address.  On many systems this won't work
00781          * so fall back to a destination of INADDR_ANY if
00782          * the first bind fails.
00783          */
00784         sockaddr_in sin;
00785         memset(&sin, 0, sizeof(sin));
00786         sin.sin_family = AF_INET;
00787         sin.sin_addr = addr;
00788         if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00789             sin.sin_addr.s_addr = INADDR_ANY;
00790             if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00791                 fprintf(stderr,
00792     "IPNetwork(%s): add_membership: unable to bind to addr %s: %s\n",
00793                     name(), inet_ntoa(sin.sin_addr),
00794                     strerror(errno));
00795                 return (-1);
00796             }
00797         }
00798 #endif
00799         /* 
00800          * XXX This is bogus multicast setup that really
00801          * shouldn't have to be done (group membership should be
00802          * implicit in the IP class D address, route should contain
00803          * ttl & no loopback flag, etc.).  Steve Deering has promised
00804          * to fix this for the 4.4bsd release.  We're all waiting
00805          * with bated breath.
00806          */
00807         struct ip_mreq mr;
00808 
00809         mr.imr_multiaddr = addr;
00810         mr.imr_interface.s_addr = INADDR_ANY;
00811         if (::setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
00812                    (char *)&mr, sizeof(mr)) < 0) {
00813             fprintf(stderr, "IPNetwork(%s): add_membership: unable to add membership for addr %s: %s\n",
00814                 name(), inet_ntoa(addr), strerror(errno));
00815             return (-1);
00816         }
00817         NIDEBUG3("IPNetwork(%s): add_membership for grp %s done\n",
00818             name(), inet_ntoa(addr));
00819         return (0);
00820     }
00821 #else
00822     fprintf(stderr, "IPNetwork(%s): add_membership: host does not support IP multicast\n",
00823         name());
00824 #endif
00825     NIDEBUG3("IPNetwork(%s): add_membership for grp %s failed\n",
00826         name(), inet_ntoa(addr));
00827     return (-1);
00828 }
00829 
00830 /*
00831  * drop membership from the specified group on the specified socket
00832  */
00833 
00834 int
00835 IPNetwork::drop_membership(Socket fd, in_addr& addr)
00836 {
00837 
00838 #if defined(IP_DROP_MEMBERSHIP)
00839     if (IN_CLASSD(ntohl(addr.s_addr))) {
00840         struct ip_mreq mr;
00841 
00842         mr.imr_multiaddr = addr;
00843         mr.imr_interface.s_addr = INADDR_ANY;
00844         if (::setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
00845                    (char *)&mr, sizeof(mr)) < 0) {
00846             fprintf(stderr, "IPNetwork(%s): drop_membership: unable to drop membership for addr %s: %s\n",
00847                 name(), inet_ntoa(addr), strerror(errno));
00848             return (-1);
00849         }
00850         NIDEBUG3("IPNetwork(%s): drop_membership for grp %s done\n",
00851             name(), inet_ntoa(addr));
00852         return (0);
00853     }
00854 #else
00855     fprintf(stderr, "IPNetwork(%s): drop_membership: host does not support IP multicast\n",
00856         name());
00857 #endif
00858     NIDEBUG3("IPNetwork(%s): drop_membership for grp %s failed\n",
00859         name(), inet_ntoa(addr));
00860     return (-1);
00861 }
00862 
00863 int
00864 IPNetwork::bindsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
00865 {
00866     memset((char *)&sin, 0, sizeof(sin));
00867     sin.sin_family = AF_INET;
00868     sin.sin_port = port;
00869     sin.sin_addr = addr;
00870     return(::bind(s, (struct sockaddr *)&sin, sizeof(sin)));
00871 }
00872 
00873 int
00874 IPNetwork::connectsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
00875 {
00876     memset((char *)&sin, 0, sizeof(sin));
00877     sin.sin_family = AF_INET;
00878     sin.sin_port = port;
00879     sin.sin_addr = addr;
00880     return(::connect(s, (struct sockaddr *)&sin, sizeof(sin)));
00881 }
00882 int 
00883 IPNetwork::sbufsize(Socket s, int cnt)
00884 {   
00885         return(::setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&cnt, sizeof(cnt)));
00886 }   
00887 
00888 int
00889 IPNetwork::rbufsize(Socket s, int cnt)
00890 {   
00891         return(::setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&cnt, sizeof(cnt)));
00892 }   
00893 
00894 int
00895 IPNetwork::setmloop(Socket s, int loop)
00896 {
00897 
00898 #ifdef IP_MULTICAST_LOOP
00899     u_char c = loop;
00900 
00901     if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &c, sizeof(c)) < 0) {
00902         /*
00903          * If we cannot turn off loopback (Like on the
00904          * Microsoft TCP/IP stack), then declare this
00905          * option broken so that our packets can be
00906          * filtered on the recv path.
00907          */
00908         if (c != loop) {
00909             noloopback_broken_ = 1;
00910             loop_ = c;
00911         }
00912         return (-1);
00913     }
00914     noloopback_broken_ = 0;
00915 #else
00916     fprintf(stderr, "IPNetwork(%s): msetloop: host does not support IP multicast\n",
00917         name());
00918 #endif
00919     loop_ = c;
00920     return (0);
00921 }
00922 
00923 void
00924 IPNetwork::reset(int restart)
00925 {
00926     time_t t = time(0);
00927     int d = int(t - last_reset_);
00928     NIDEBUG2("IPNetwork(%s): reset\n", name());
00929     if (d > 3) {    // Steve: why?
00930         last_reset_ = t;
00931         if (ssock_ >= 0)
00932             (void)::close(ssock_);
00933         if (rsock_ >= 0)
00934             (void)::close(rsock_);
00935         if (open(mode_) < 0) {
00936             fprintf(stderr,
00937               "IPNetwork(%s): couldn't reset\n",
00938               name());
00939             mode_ = -1;
00940             return;
00941         }
00942         if (restart)
00943             (void) reconfigure();
00944     }
00945 }
00946 
00947 /*
00948  * after a reset, we may want to re-establish our state
00949  * [set up addressing, etc].  Do this here
00950  */
00951 
00952 void
00953 IPNetwork::reconfigure()
00954 {
00955 }
00956 
00957 void
00958 UDPIPNetwork::reconfigure()
00959 {
00960 }

Generated on Tue Mar 6 16:47:47 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6