Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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.19 2001/09/20 19:05:50 alefiyah 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                 char* cp = tcl.result();
00603                 if (strcmp(argv[1], "destaddr") == 0) {
00604                         strcpy(cp, inet_ntoa(destaddr_));
00605                         return (TCL_OK);
00606                 }
00607                 if (strcmp(argv[1], "localaddr") == 0) {
00608                         strcpy(cp, inet_ntoa(localaddr_));
00609                         return (TCL_OK);
00610                 }
00611                 if (strcmp(argv[1], "mttl") == 0) {
00612                         tcl.resultf("%d", mttl_);
00613                         return (TCL_OK);
00614                 }
00615                 /* for backward compatability */
00616                 if (strcmp(argv[1], "ismulticast") == 0) {
00617                         tcl.result(IN_CLASSD(ntohl(destaddr_.s_addr)) ?
00618                                 "1" : "0");
00619                         return (TCL_OK);
00620                 }
00621                 if (strcmp(argv[1], "addr") == 0) {
00622                         strcpy(cp, inet_ntoa(destaddr_));
00623                         return (TCL_OK);
00624                 }
00625                 if (strcmp(argv[1], "ttl") == 0) {
00626                         tcl.resultf("%d", mttl_);
00627                         return (TCL_OK);
00628                 }
00629                 if (strcmp(argv[1], "interface") == 0) {
00630                         strcpy(cp, inet_ntoa(localaddr_));
00631                         return (TCL_OK);
00632                 }
00633         } else if (argc == 3) {
00634                 
00635                 if (strcmp(argv[1], "open") == 0) {
00636                         int mode = parsemode(argv[2]);
00637                         if (open(mode) < 0)
00638                                 return (TCL_ERROR);
00639                         return (TCL_OK);
00640                 }
00641                 if (strcmp(argv[1], "add-membership") == 0) {
00642                         in_addr addr;
00643                         addr.s_addr = LookupHostAddr(argv[2]);
00644                         if (add_membership(rchannel(), addr) < 0)
00645                                 tcl.result("0");
00646                         else
00647                                 tcl.result("1");
00648                         return (TCL_OK);
00649                 }
00650                 if (strcmp(argv[1], "drop-membership") == 0) {
00651                         in_addr addr;
00652                         addr.s_addr = LookupHostAddr(argv[2]);
00653                         if (drop_membership(rchannel(), addr) < 0)
00654                                 tcl.result("0");
00655                         else
00656                                 tcl.result("1");
00657                         return (TCL_OK);
00658                 }
00659                 if (strcmp(argv[1], "loopback") == 0) {
00660                         int val = atoi(argv[2]);
00661                         if (strcmp(argv[2], "true") == 0)
00662                                 val = 1;
00663                         else if (strcmp(argv[2], "false") == 0)
00664                                 val = 0;
00665                         if (setmloop(schannel(), val) < 0)
00666                                 tcl.result("0");
00667                         else
00668                                 tcl.result("1");
00669                         return (TCL_OK);
00670                 }
00671         }
00672         return (Network::command(argc, argv));
00673 }
00674 int
00675 IPNetwork::setmttl(Socket s, int ttl)
00676 {
00677         /* set the multicast TTL */  
00678 
00679 #ifdef WIN32
00680         u_int t = ttl; 
00681 #else 
00682         u_char t = ttl;
00683 #endif
00684 
00685         t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; 
00686         if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
00687                        (char*)&t, sizeof(t)) < 0) {
00688                 fprintf(stderr,
00689                     "IPNetwork(%s): couldn't set multicast ttl to %d\n",
00690                         name(), t);
00691                 return (-1);
00692         }
00693         return (0);
00694 }
00695 
00696 /*
00697  * open a RAW IP socket (will require privilege).
00698  * turn on HDRINCL, specifying that we will be writing the raw IP header
00699  */
00700 
00701 int
00702 IPNetwork::open(int mode)
00703 {
00704         // obtain a raw socket we can use to send ip datagrams
00705         Socket fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
00706         if (fd < 0) {
00707                 perror("socket(RAW)");
00708                 if (::getuid() != 0 && ::geteuid() != 0) {
00709                         fprintf(stderr,
00710           "IPNetwork(%s): open: use of the Network/IP object requires super-user privs\n",
00711                         name());
00712                 }
00713 
00714                 return (-1);
00715         }
00716 
00717         // turn on HDRINCL option (we will be writing IP header)
00718         // in FreeBSD 2.2.5 (and possibly others), the IP id field
00719         // is set by the kernel routine rip_output()
00720         // only if it is non-zero, so we should be ok.
00721         int one = 1;
00722         if (::setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) {
00723                 fprintf(stderr,
00724         "IPNetwork(%s): open: unable to turn on IP_HDRINCL: %s\n",
00725                         name(), strerror(errno));
00726                 return (-1);
00727         }
00728 #ifndef __linux__
00729         // sort of curious, but do a connect() even though we have
00730         // HDRINCL on.  Otherwise, we get ENOTCONN when doing a send()
00731         sockaddr_in sin;
00732         in_addr ia = { INADDR_ANY };
00733         if (connectsock(fd, ia, 0, sin) < 0) {
00734                 fprintf(stderr,
00735         "IPNetwork(%s): open: unable to connect : %s\n",
00736                         name(), strerror(errno));
00737         }
00738 #endif
00739         rsock_ = ssock_ = fd;
00740         mode_ = mode;
00741         NIDEBUG5("IPNetwork(%s): opened with mode %d, rsock_:%d, ssock_:%d\n",
00742                 name(), mode_, rsock_, ssock_);
00743         return 0;
00744 }
00745 
00746 /*
00747  * close both sending and receiving sockets
00748  */
00749 
00750 int
00751 IPNetwork::close()
00752 {
00753         if (ssock_ >= 0) {
00754                 (void)::close(ssock_);
00755                 ssock_ = -1;
00756         }
00757         if (rsock_ >= 0) {
00758                 (void)::close(rsock_);
00759                 rsock_ = -1;
00760         }
00761         return (0);
00762 }
00763 
00764 /*
00765  * add multicast group membership on the socket
00766  */
00767 
00768 int
00769 IPNetwork::add_membership(Socket fd, in_addr& addr)
00770 {
00771 
00772 #if defined(IP_ADD_MEMBERSHIP)
00773         if (IN_CLASSD(ntohl(addr.s_addr))) {
00774 #ifdef notdef
00775                 /*
00776                  * Try to bind the multicast address as the socket
00777                  * dest address.  On many systems this won't work
00778                  * so fall back to a destination of INADDR_ANY if
00779                  * the first bind fails.
00780                  */
00781                 sockaddr_in sin;
00782                 memset(&sin, 0, sizeof(sin));
00783                 sin.sin_family = AF_INET;
00784                 sin.sin_addr = addr;
00785                 if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00786                         sin.sin_addr.s_addr = INADDR_ANY;
00787                         if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
00788                                 fprintf(stderr,
00789         "IPNetwork(%s): add_membership: unable to bind to addr %s: %s\n",
00790                                         name(), inet_ntoa(sin.sin_addr),
00791                                         strerror(errno));
00792                                 return (-1);
00793                         }
00794                 }
00795 #endif
00796                 /* 
00797                  * XXX This is bogus multicast setup that really
00798                  * shouldn't have to be done (group membership should be
00799                  * implicit in the IP class D address, route should contain
00800                  * ttl & no loopback flag, etc.).  Steve Deering has promised
00801                  * to fix this for the 4.4bsd release.  We're all waiting
00802                  * with bated breath.
00803                  */
00804                 struct ip_mreq mr;
00805 
00806                 mr.imr_multiaddr = addr;
00807                 mr.imr_interface.s_addr = INADDR_ANY;
00808                 if (::setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
00809                                (char *)&mr, sizeof(mr)) < 0) {
00810                         fprintf(stderr, "IPNetwork(%s): add_membership: unable to add membership for addr %s: %s\n",
00811                                 name(), inet_ntoa(addr), strerror(errno));
00812                         return (-1);
00813                 }
00814                 NIDEBUG3("IPNetwork(%s): add_membership for grp %s done\n",
00815                         name(), inet_ntoa(addr));
00816                 return (0);
00817         }
00818 #else
00819         fprintf(stderr, "IPNetwork(%s): add_membership: host does not support IP multicast\n",
00820                 name());
00821 #endif
00822         NIDEBUG3("IPNetwork(%s): add_membership for grp %s failed\n",
00823                 name(), inet_ntoa(addr));
00824         return (-1);
00825 }
00826 
00827 /*
00828  * drop membership from the specified group on the specified socket
00829  */
00830 
00831 int
00832 IPNetwork::drop_membership(Socket fd, in_addr& addr)
00833 {
00834 
00835 #if defined(IP_DROP_MEMBERSHIP)
00836         if (IN_CLASSD(ntohl(addr.s_addr))) {
00837                 struct ip_mreq mr;
00838 
00839                 mr.imr_multiaddr = addr;
00840                 mr.imr_interface.s_addr = INADDR_ANY;
00841                 if (::setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
00842                                (char *)&mr, sizeof(mr)) < 0) {
00843                         fprintf(stderr, "IPNetwork(%s): drop_membership: unable to drop membership for addr %s: %s\n",
00844                                 name(), inet_ntoa(addr), strerror(errno));
00845                         return (-1);
00846                 }
00847                 NIDEBUG3("IPNetwork(%s): drop_membership for grp %s done\n",
00848                         name(), inet_ntoa(addr));
00849                 return (0);
00850         }
00851 #else
00852         fprintf(stderr, "IPNetwork(%s): drop_membership: host does not support IP multicast\n",
00853                 name());
00854 #endif
00855         NIDEBUG3("IPNetwork(%s): drop_membership for grp %s failed\n",
00856                 name(), inet_ntoa(addr));
00857         return (-1);
00858 }
00859 
00860 int
00861 IPNetwork::bindsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
00862 {
00863         memset((char *)&sin, 0, sizeof(sin));
00864         sin.sin_family = AF_INET;
00865         sin.sin_port = port;
00866         sin.sin_addr = addr;
00867         return(::bind(s, (struct sockaddr *)&sin, sizeof(sin)));
00868 }
00869 
00870 int
00871 IPNetwork::connectsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
00872 {
00873         memset((char *)&sin, 0, sizeof(sin));
00874         sin.sin_family = AF_INET;
00875         sin.sin_port = port;
00876         sin.sin_addr = addr;
00877         return(::connect(s, (struct sockaddr *)&sin, sizeof(sin)));
00878 }
00879 int 
00880 IPNetwork::sbufsize(Socket s, int cnt)
00881 {   
00882         return(::setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&cnt, sizeof(cnt)));
00883 }   
00884 
00885 int
00886 IPNetwork::rbufsize(Socket s, int cnt)
00887 {   
00888         return(::setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&cnt, sizeof(cnt)));
00889 }   
00890 
00891 int
00892 IPNetwork::setmloop(Socket s, int loop)
00893 {
00894 
00895 #ifdef IP_MULTICAST_LOOP
00896         u_char c = loop;
00897 
00898         if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &c, sizeof(c)) < 0) {
00899                 /*
00900                  * If we cannot turn off loopback (Like on the
00901                  * Microsoft TCP/IP stack), then declare this
00902                  * option broken so that our packets can be
00903                  * filtered on the recv path.
00904                  */
00905                 if (c != loop) {
00906                         noloopback_broken_ = 1;
00907                         loop_ = c;
00908                 }
00909                 return (-1);
00910         }
00911         noloopback_broken_ = 0;
00912 #else
00913         fprintf(stderr, "IPNetwork(%s): msetloop: host does not support IP multicast\n",
00914                 name());
00915 #endif
00916         loop_ = c;
00917         return (0);
00918 }
00919 
00920 void
00921 IPNetwork::reset(int restart)
00922 {
00923         time_t t = time(0);
00924         int d = int(t - last_reset_);
00925         NIDEBUG2("IPNetwork(%s): reset\n", name());
00926         if (d > 3) {    // Steve: why?
00927                 last_reset_ = t;
00928                 if (ssock_ >= 0)
00929                         (void)::close(ssock_);
00930                 if (rsock_ >= 0)
00931                         (void)::close(rsock_);
00932                 if (open(mode_) < 0) {
00933                         fprintf(stderr,
00934                           "IPNetwork(%s): couldn't reset\n",
00935                           name());
00936                         mode_ = -1;
00937                         return;
00938                 }
00939                 if (restart)
00940                         (void) reconfigure();
00941         }
00942 }
00943 
00944 /*
00945  * after a reset, we may want to re-establish our state
00946  * [set up addressing, etc].  Do this here
00947  */
00948 
00949 void
00950 IPNetwork::reconfigure()
00951 {
00952 }
00953 
00954 void
00955 UDPIPNetwork::reconfigure()
00956 {
00957 }

Generated on Tue Apr 20 12:14:25 2004 for NS2.26SourcesOriginal by doxygen 1.3.3