net-ip.cc
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:25k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*-
  2.  * Copyright (c) 1993-1994, 1998
  3.  * The Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. All advertising materials mentioning features or use of this software
  15.  *    must display the following acknowledgement:
  16.  *      This product includes software developed by the University of
  17.  *      California, Berkeley and the Network Research Group at
  18.  *      Lawrence Berkeley Laboratory.
  19.  * 4. Neither the name of the University nor of the Laboratory may be used
  20.  *    to endorse or promote products derived from this software without
  21.  *    specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35. #ifndef lint
  36. static const char rcsid[] =
  37.     "@(#) $Header: /cvsroot/nsnam/ns-2/emulate/net-ip.cc,v 1.20 2003/10/12 21:13:09 xuanc Exp $ (LBL)";
  38. #endif
  39. #include <stdio.h>
  40. #ifndef WIN32
  41. #include <unistd.h>
  42. #endif
  43. #include <time.h>
  44. #include <errno.h>
  45. #include <string.h>
  46. #ifdef WIN32
  47. #include <io.h>
  48. #define close closesocket
  49. #else
  50. #include <sys/param.h>
  51. #include <sys/socket.h>
  52. #include <sys/ioctl.h>
  53. #include <netinet/in.h>
  54. #include <netinet/in_systm.h>
  55. #include <netinet/ip.h>
  56. typedef int Socket;
  57. #endif
  58. #if defined(sun) && defined(__svr4__)
  59. #include <sys/systeminfo.h>
  60. #endif
  61. #include "config.h"
  62. #include "net.h"
  63. #include "inet.h"
  64. #include "tclcl.h"
  65. #include "scheduler.h"
  66. //#define NIPDEBUG 1
  67. #ifdef NIPDEBUG
  68. #define NIDEBUG(x) { if (NIPDEBUG) fprintf(stderr, (x)); }
  69. #define NIDEBUG2(x,y) { if (NIPDEBUG) fprintf(stderr, (x), (y)); }
  70. #define NIDEBUG3(x,y,z) { if (NIPDEBUG) fprintf(stderr, (x), (y), (z)); }
  71. #define NIDEBUG4(w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (w), (x), (y), (z)); }
  72. #define NIDEBUG5(v,w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (v), (w), (x), (y), (z)); }
  73. #else
  74. #define NIDEBUG(x) { }
  75. #define NIDEBUG2(x,y) { }
  76. #define NIDEBUG3(x,y,z) { }
  77. #define NIDEBUG4(w,x,y,z) { }
  78. #define NIDEBUG5(v,w,x,y,z) { }
  79. #endif
  80. /*
  81.  * Net-ip.cc: this file defines the IP and IP/UDP network
  82.  * objects.  IP provides a raw IP interface and support functions
  83.  * [such as setting multicast parameters].  IP/UDP provides a standard
  84.  * UDP datagram interface.
  85.  */
  86. //
  87. // IPNetwork: a low-level (raw) IP network object
  88. //
  89. class IPNetwork : public Network {
  90. public:
  91. IPNetwork();
  92.         inline int ttl() const { return (mttl_); } // current mcast ttl
  93. inline int noloopback_broken() { // no loopback filter?
  94. return (noloopback_broken_);
  95. }
  96. int setmttl(Socket, int); // set mcast ttl
  97. int setmloop(Socket, int); // set mcast loopback
  98. int command(int argc, const char*const* argv); // virtual in Network
  99. inline Socket rchannel() { return(rsock_); } // virtual in Network
  100. inline Socket schannel() { return(ssock_); } // virtual in Network
  101.         int send(u_char* buf, int len); // virtual in Network
  102.         int recv(u_char* buf, int len, sockaddr& from, double& ); // virtual in Network
  103.         inline in_addr& laddr() { return (localaddr_); }
  104.         inline in_addr& dstaddr() { return (destaddr_); }
  105. int add_membership(Socket, in_addr& grp); // join mcast
  106. int drop_membership(Socket, in_addr& grp); // leave mcast
  107. /* generally useful routines */
  108. static int bindsock(Socket, in_addr&, u_int16_t, sockaddr_in&);
  109. static int connectsock(Socket, in_addr&, u_int16_t, sockaddr_in&);
  110. static int rbufsize(Socket, int);
  111. static int sbufsize(Socket, int);
  112. protected:
  113. in_addr destaddr_; // remote side, if set (network order)
  114. in_addr localaddr_; // local side (network order)
  115.         int mttl_; // multicast ttl to use
  116. Socket rsock_; // socket to receive on
  117. Socket ssock_; // socket to send on
  118.         int noloopback_broken_; // couldn't turn (off) mcast loopback
  119. int loop_; // do we want loopbacks?
  120. // (system usually assumes yes)
  121. void reset(int reconfigure); // reset + reconfig?
  122. virtual int open(int mode); // open sockets/endpoints
  123. virtual void reconfigure(); // restore state after reset
  124. int close();
  125. time_t last_reset_;
  126. };
  127. class UDPIPNetwork : public IPNetwork {
  128. public:
  129. UDPIPNetwork();
  130. int send(u_char*, int);
  131. int recv(u_char*, int, sockaddr&, double&);
  132. int open(int mode); // mode only
  133. int command(int argc, const char*const* argv);
  134. void reconfigure();
  135. void add_membership(Socket, in_addr&, u_int16_t); // udp version
  136. protected:
  137. int bind(in_addr&, u_int16_t port); // bind to addr/port, mcast ok
  138. int connect(in_addr& remoteaddr, u_int16_t port); // connect()
  139.         u_int16_t lport_; // local port (network order)
  140.         u_int16_t port_; // remote (dst) port (network order)
  141. };
  142. static class IPNetworkClass : public TclClass {
  143.     public:
  144. IPNetworkClass() : TclClass("Network/IP") {}
  145. TclObject* create(int, const char*const*) {
  146. return (new IPNetwork);
  147. }
  148. } nm_ip;
  149. static class UDPIPNetworkClass : public TclClass {
  150.     public:
  151. UDPIPNetworkClass() : TclClass("Network/IP/UDP") {}
  152. TclObject* create(int, const char*const*) {
  153. return (new UDPIPNetwork);
  154. }
  155. } nm_ip_udp;
  156. IPNetwork::IPNetwork() :
  157. mttl_(0),
  158.         rsock_(-1), 
  159.         ssock_(-1),
  160.         noloopback_broken_(0),
  161. loop_(1)
  162. {
  163. localaddr_.s_addr = 0L;
  164. destaddr_.s_addr = 0L;
  165. NIDEBUG("IPNetwork: ctorn");
  166. }
  167. UDPIPNetwork::UDPIPNetwork() :
  168.         lport_(htons(0)), 
  169.         port_(htons(0))
  170. {
  171. NIDEBUG("UDPIPNetwork: ctorn");
  172. }
  173. /*
  174.  * UDPIP::send -- send "len" bytes in buffer "buf" out the sending
  175.  * channel.
  176.  *
  177.  * returns the number of bytes written
  178.  */
  179. int
  180. UDPIPNetwork::send(u_char* buf, int len)
  181. {
  182. int cc = ::send(schannel(), (char*)buf, len, 0);
  183. NIDEBUG5("UDPIPNetwork(%s): ::send(%d, buf, %d) returned %dn",
  184. name(), schannel(), len, cc);
  185. if (cc < 0) {
  186. switch (errno) {
  187. case ECONNREFUSED:
  188. /* no one listening at some site - ignore */
  189. #if defined(__osf__) || defined(_AIX) || defined(__FreeBSD__)
  190. /*
  191.  * Here's an old comment...
  192.  *
  193.  * Due to a bug in kern/uipc_socket.c, on several
  194.  * systems, datagram sockets incorrectly persist
  195.  * in an error state on receipt of an ICMP
  196.  * port-unreachable.  This causes unicast connection
  197.  * rendezvous problems, and worse, multicast
  198.  * transmission problems because several systems
  199.  * incorrectly send port unreachables for 
  200.  * multicast destinations.  Our work around
  201.  * is to simply close and reopen the socket
  202.  * (by calling reset() below).
  203.  *
  204.  * This bug originated at CSRG in Berkeley
  205.  * and was present in the BSD Reno networking
  206.  * code release.  It has since been fixed
  207.  * in 4.4BSD and OSF-3.x.  It is known to remain
  208.  * in AIX-4.1.3.
  209.  *
  210.  * A fix is to change the following lines from
  211.  * kern/uipc_socket.c:
  212.  *
  213.  * if (so_serror)
  214.  * snderr(so->so_error);
  215.  *
  216.  * to:
  217.  *
  218.  * if (so->so_error) {
  219.  *  error = so->so_error;
  220.  * so->so_error = 0;
  221.  * splx(s);
  222.  * goto release;
  223.  * }
  224.  *
  225.  */
  226. reset(1);
  227. #endif
  228. break;
  229. case ENETUNREACH:
  230. case EHOSTUNREACH:
  231. /*
  232.  * These "errors" are totally meaningless.
  233.  * There is some broken host sending
  234.  * icmp unreachables for multicast destinations.
  235.  * UDP probably aborted the send because of them --
  236.  * try exactly once more.  E.g., the send we
  237.  * just did cleared the errno for the previous
  238.  * icmp unreachable, so we should be able to
  239.  * send now.
  240.  */
  241. cc = ::send(schannel(), (char*)buf, len, 0);
  242. break;
  243. default:
  244. fprintf(stderr, "UDPIPNetwork(%s): send failed: %sn",
  245. name(), strerror(errno));
  246. return (-1);
  247. }
  248. }
  249. return cc; // bytes sent
  250. }
  251. int
  252. UDPIPNetwork::recv(u_char* buf, int len, sockaddr& from, double& ts)
  253. {
  254. sockaddr_in sfrom;
  255. int fromlen = sizeof(sfrom);
  256. int cc = ::recvfrom(rsock_, (char*)buf, len, 0,
  257.     (sockaddr*)&sfrom, (socklen_t*)&fromlen);
  258. NIDEBUG5("UDPIPNetwork(%s): ::recvfrom(%d, buf, %d) returned %dn",
  259. name(), rsock_, len, cc);
  260. if (cc < 0) {
  261. if (errno != EWOULDBLOCK) {
  262. fprintf(stderr,
  263. "UDPIPNetwork(%s): recvfrom failed: %sn",
  264. name(), strerror(errno));
  265. }
  266. return (-1);
  267. }
  268. from = *((sockaddr*)&sfrom);
  269. /*
  270.  * if we received multicast data and we don't want the look,
  271.  * there is a chance it is
  272.  * what we sent if "noloopback_broken_" is set.
  273.  * If so, filter out the stuff we don't want right here.
  274.  */
  275.  
  276. if (!loop_ && noloopback_broken_ &&
  277.     sfrom.sin_addr.s_addr == localaddr_.s_addr &&
  278.     sfrom.sin_port == lport_) {
  279. NIDEBUG2("UDPIPNetwork(%s): filtered out our own pktn", name());
  280. return (0); // empty
  281. }
  282. ts = Scheduler::instance().clock();
  283. return (cc); // number of bytes received
  284. }
  285. int
  286. UDPIPNetwork::open(int mode)
  287. {
  288. if (mode == O_RDONLY || mode == O_RDWR) {
  289. rsock_ = socket(AF_INET, SOCK_DGRAM, 0);
  290. if (rsock_ < 0) {
  291. fprintf(stderr,
  292. "UDPIPNetwork(%s): open: couldn't open rcv sockn",
  293. name());
  294. }
  295. nonblock(rsock_);
  296. int on = 1;
  297. if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEADDR, (char *)&on,
  298. sizeof(on)) < 0) {
  299. fprintf(stderr,
  300. "UDPIPNetwork(%s): open: warning: unable set REUSEADDR: %sn",
  301. name(), strerror(errno));
  302. }
  303. #ifdef SO_REUSEPORT
  304. on = 1;
  305. if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEPORT, (char *)&on,
  306.        sizeof(on)) < 0) {
  307. fprintf(stderr,
  308. "UDPIPNetwork(%s): open: warning: unable set REUSEPORT: %sn",
  309. name(), strerror(errno));
  310. }
  311. #endif
  312. /*
  313.  * XXX don't need this for the session socket.
  314.  */
  315. if (rbufsize(rsock_, 80*1024) < 0) {
  316. if (rbufsize(rsock_, 32*1024) < 0) {
  317. fprintf(stderr,
  318. "UDPIPNetwork(%s): open: unable to set r bufsize to %d: %sn",
  319. name(), 32*1024, strerror(errno));
  320. }
  321. }
  322. }
  323. if (mode == O_WRONLY || mode == O_RDWR) {
  324. ssock_ = socket(AF_INET, SOCK_DGRAM, 0);
  325. if (ssock_ < 0) {
  326. fprintf(stderr,
  327. "UDPIPNetwork(%s): open: couldn't open snd sockn",
  328. name());
  329. }
  330. nonblock(ssock_);
  331. int firsttry = 80 * 1024;
  332. int secondtry = 48 * 1024;
  333. if (sbufsize(ssock_, firsttry) < 0) {
  334. if (sbufsize(ssock_, secondtry) < 0) {
  335. fprintf(stderr,
  336.   "UDPIPNetwork(%s): open: cannot set send sockbuf size to %d bytes, using defaultn",  
  337. name(), secondtry);
  338. }
  339. }
  340. }
  341. mode_ = mode;
  342. NIDEBUG5("UDPIPNetwork(%s): opened network w/mode %d, ssock:%d, rsock:%dn",
  343. name(), mode_, rsock_, ssock_);
  344. return (0);
  345. }
  346. //
  347. // IP/UDP version of add_membership: try binding
  348. //
  349. void
  350. UDPIPNetwork::add_membership(Socket sock, in_addr& addr, u_int16_t port)
  351. {
  352. int failure = 0;
  353. sockaddr_in sin;
  354. if (bindsock(sock, addr, port, sin) < 0)
  355. failure = 1;
  356. if (failure) {
  357. in_addr addr2 = addr;
  358. addr2.s_addr = INADDR_ANY;
  359. if (bindsock(sock, addr2, port, sin) < 0)
  360. failure = 1;
  361. else
  362. failure = 0;
  363. }
  364. if (IPNetwork::add_membership(sock, addr) < 0)
  365. failure = 1;
  366. if (failure) {
  367. fprintf(stderr,
  368. "UDPIPNetwork(%s): add_membership: failed bind on mcast addr %s and INADDR_ANYn",
  369. name(), inet_ntoa(addr));
  370. }
  371. }
  372. //
  373. // server-side bind (or mcast subscription)
  374. //
  375. int
  376. UDPIPNetwork::bind(in_addr& addr, u_int16_t port)
  377. {
  378. NIDEBUG4("UDPIPNetwork(%s): attempt to bind to addr %s, port %d [net order]n",
  379. name(), inet_ntoa(addr), ntohs(port));
  380. if (rsock_ < 0) {
  381. fprintf(stderr,
  382. "UDPIPNetwork(%s): bind/listen called before net is openn",
  383. name());
  384. return (-1);
  385. }
  386. if (mode_ == O_WRONLY) {
  387. fprintf(stderr,
  388. "UDPIPNetwork(%s): attempted bind/listen but net is write-onlyn",
  389. name());
  390. return (-1);
  391. }
  392. #ifdef IP_ADD_MEMBERSHIP
  393.         if (IN_CLASSD(ntohl(addr.s_addr))) {
  394. // MULTICAST case, call UDPIP vers of add_membership
  395.                 add_membership(rsock_, addr, port);
  396.         } else
  397. #endif
  398.         {
  399. // UNICAST case
  400.                 sockaddr_in sin;
  401.                 if (bindsock(rsock_, addr, port, sin) < 0) {
  402.                         port = ntohs(port);
  403.                         fprintf(stderr,
  404.         "UDPIPNetwork(%s): bind: unable to bind %s [port:%hu]: %sn",
  405.                                 name(), inet_ntoa(addr),
  406.                                 port, strerror(errno));
  407. return (-1);
  408.                 }
  409.                 /*
  410.                  * MS Windows currently doesn't compy with the Internet Host
  411.                  * Requirements standard (RFC-1122) and won't let us include
  412.                  * the source address in the receive socket demux state.
  413.                  */
  414. #ifndef WIN32
  415.                 /*
  416.                  * (try to) connect the foreign host's address to this socket.
  417.                  */
  418.                 (void)connectsock(rsock_, addr, 0, sin);
  419. #endif
  420.         }
  421. localaddr_ = addr;
  422. lport_ = port;
  423. return (0);
  424. }
  425. //
  426. // client-side connect
  427. //
  428. int
  429. UDPIPNetwork::connect(in_addr& addr, u_int16_t port)
  430. {
  431. sockaddr_in sin;
  432. if (ssock_ < 0) {
  433. fprintf(stderr,
  434. "UDPIPNetwork(%s): connect called before net is openn",
  435. name());
  436. return (-1);
  437. }
  438. if (mode_ == O_RDONLY) {
  439. fprintf(stderr,
  440. "UDPIPNetwork(%s): attempted connect but net is read-onlyn",
  441. name());
  442. return (-1);
  443. }
  444. int rval = connectsock(ssock_, addr, port, sin);
  445. if (rval < 0)
  446. return (rval);
  447. destaddr_ = addr;
  448. port_ = port;
  449. last_reset_ = 0;
  450. return(rval);
  451. }
  452. int
  453. UDPIPNetwork::command(int argc, const char*const* argv)
  454. {
  455. Tcl& tcl = Tcl::instance();
  456. if (argc == 2) {
  457. // $udpip port
  458. if (strcmp(argv[1], "port") == 0) {
  459. tcl.resultf("%d", ntohs(port_));
  460. return (TCL_OK);
  461. }
  462. // $udpip lport
  463. if (strcmp(argv[1], "lport") == 0) {
  464. tcl.resultf("%d", ntohs(lport_));
  465. return (TCL_OK);
  466. }
  467. } else if (argc == 4) {
  468. // $udpip listen addr port
  469. // $udpip bind addr port
  470. if (strcmp(argv[1], "listen") == 0 ||
  471.     strcmp(argv[1], "bind") == 0) {
  472. in_addr addr;
  473. if (strcmp(argv[2], "any") == 0)
  474. addr.s_addr = INADDR_ANY;
  475. else
  476. addr.s_addr = LookupHostAddr(argv[2]);
  477. u_int16_t port = htons(atoi(argv[3]));
  478. if (bind(addr, port) < 0) {
  479. tcl.resultf("%s %hu",
  480. inet_ntoa(addr), port);
  481. } else {
  482. tcl.result("0");
  483. }
  484. return (TCL_OK);
  485. }
  486. // $udpip connect addr port
  487. if (strcmp(argv[1], "connect") == 0) {
  488. in_addr addr;
  489. addr.s_addr = LookupHostAddr(argv[2]);
  490. u_int16_t port = htons(atoi(argv[3]));
  491. if (connect(addr, port) < 0) {
  492. tcl.resultf("%s %hu",
  493. inet_ntoa(addr), port);
  494. } else {
  495. tcl.result("0");
  496. }
  497. return (TCL_OK);
  498. }
  499. }
  500. return (IPNetwork::command(argc, argv));
  501. }
  502. //
  503. // raw IP network recv()
  504. //
  505. int
  506. IPNetwork::recv(u_char* buf, int len, sockaddr& sa, double& ts)
  507. {
  508. if (mode_ == O_WRONLY) {
  509. fprintf(stderr,
  510.     "IPNetwork(%s) recv while in writeonly mode!n",
  511. name());
  512. abort();
  513. }
  514. int fromlen = sizeof(sa);
  515. int cc = ::recvfrom(rsock_, (char*)buf, len, 0, &sa, (socklen_t*)&fromlen);
  516. if (cc < 0) {
  517. if (errno != EWOULDBLOCK)
  518. perror("recvfrom");
  519. return (-1);
  520. }
  521. ts = Scheduler::instance().clock();
  522. return (cc);
  523. }
  524. //
  525. // we are given a "raw" IP datagram.
  526. // the raw interface appears to want the len and off fields
  527. // in *host* order, so make it this way here
  528. // note also, that it will compute the cksum "for" us... :(
  529. //
  530. int
  531. IPNetwork::send(u_char* buf, int len)
  532. {
  533. struct ip *ip = (struct ip*) buf;
  534. #ifdef __linux__ 
  535. // For raw sockets on linux the send does not work,
  536. // all packets show up only on the loopback device and are not routed
  537. // to the correct host. Using sendto on a closed socket solves this problem
  538.        ip->ip_len = (ip->ip_len);
  539.        ip->ip_off = (ip->ip_off);
  540.         sockaddr_in sin;
  541.        memset((char *)&sin, 0, sizeof(sin));
  542.        sin.sin_family = AF_INET;
  543.         sin.sin_addr = ip->ip_dst;
  544.        return (::sendto(ssock_, (char*)buf, len, 0,(sockaddr *) &sin,sizeof(sin)));
  545. #else
  546.         ip->ip_len = ntohs(ip->ip_len);
  547.         ip->ip_off = ntohs(ip->ip_off);
  548.         return (::send(ssock_, (char*)buf, len, 0));
  549. #endif
  550. }
  551. int IPNetwork::command(int argc, const char*const* argv)
  552. {
  553. Tcl& tcl = Tcl::instance();
  554. if (argc == 2) {
  555. if (strcmp(argv[1], "close") == 0) {
  556. close();
  557. return (TCL_OK);
  558. }
  559. // Old approach uses tcl.result() to get result buffer first
  560. // char* cp = tcl.result();
  561. // new approach uses tcl.result(const char*) directly.
  562. // xuanc, 10/07/2003
  563. if (strcmp(argv[1], "destaddr") == 0) {
  564. tcl.result(inet_ntoa(destaddr_));
  565. return (TCL_OK);
  566. }
  567. if (strcmp(argv[1], "localaddr") == 0) {
  568. tcl.result(inet_ntoa(localaddr_));
  569. return (TCL_OK);
  570. }
  571. if (strcmp(argv[1], "mttl") == 0) {
  572. tcl.resultf("%d", mttl_);
  573. return (TCL_OK);
  574. }
  575. /* for backward compatability */
  576. if (strcmp(argv[1], "ismulticast") == 0) {
  577. tcl.result(IN_CLASSD(ntohl(destaddr_.s_addr)) ?
  578. "1" : "0");
  579. return (TCL_OK);
  580. }
  581. if (strcmp(argv[1], "addr") == 0) {
  582. tcl.result(inet_ntoa(destaddr_));
  583. return (TCL_OK);
  584. }
  585. if (strcmp(argv[1], "ttl") == 0) {
  586. tcl.resultf("%d", mttl_);
  587. return (TCL_OK);
  588. }
  589. if (strcmp(argv[1], "interface") == 0) {
  590. tcl.result(inet_ntoa(localaddr_));
  591. return (TCL_OK);
  592. }
  593. } else if (argc == 3) {
  594. if (strcmp(argv[1], "open") == 0) {
  595. int mode = parsemode(argv[2]);
  596. if (open(mode) < 0)
  597. return (TCL_ERROR);
  598. return (TCL_OK);
  599. }
  600. if (strcmp(argv[1], "add-membership") == 0) {
  601. in_addr addr;
  602. addr.s_addr = LookupHostAddr(argv[2]);
  603. if (add_membership(rchannel(), addr) < 0)
  604. tcl.result("0");
  605. else
  606. tcl.result("1");
  607. return (TCL_OK);
  608. }
  609. if (strcmp(argv[1], "drop-membership") == 0) {
  610. in_addr addr;
  611. addr.s_addr = LookupHostAddr(argv[2]);
  612. if (drop_membership(rchannel(), addr) < 0)
  613. tcl.result("0");
  614. else
  615. tcl.result("1");
  616. return (TCL_OK);
  617. }
  618. if (strcmp(argv[1], "loopback") == 0) {
  619. int val = atoi(argv[2]);
  620. if (strcmp(argv[2], "true") == 0)
  621. val = 1;
  622. else if (strcmp(argv[2], "false") == 0)
  623. val = 0;
  624. if (setmloop(schannel(), val) < 0)
  625. tcl.result("0");
  626. else
  627. tcl.result("1");
  628. return (TCL_OK);
  629. }
  630. }
  631. return (Network::command(argc, argv));
  632. }
  633. int
  634. IPNetwork::setmttl(Socket s, int ttl)
  635. {
  636.         /* set the multicast TTL */  
  637. #ifdef WIN32
  638.         u_int t = ttl; 
  639. #else 
  640.         u_char t = ttl;
  641. #endif
  642.         t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; 
  643.         if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL,
  644.                        (char*)&t, sizeof(t)) < 0) {
  645. fprintf(stderr,
  646.     "IPNetwork(%s): couldn't set multicast ttl to %dn",
  647. name(), t);
  648.                 return (-1);
  649.         }
  650. return (0);
  651. }
  652. /*
  653.  * open a RAW IP socket (will require privilege).
  654.  * turn on HDRINCL, specifying that we will be writing the raw IP header
  655.  */
  656. int
  657. IPNetwork::open(int mode)
  658. {
  659. // obtain a raw socket we can use to send ip datagrams
  660. Socket fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  661. if (fd < 0) {
  662. perror("socket(RAW)");
  663. if (::getuid() != 0 && ::geteuid() != 0) {
  664. fprintf(stderr,
  665.   "IPNetwork(%s): open: use of the Network/IP object requires super-user privsn",
  666. name());
  667. }
  668. return (-1);
  669. }
  670. // turn on HDRINCL option (we will be writing IP header)
  671. // in FreeBSD 2.2.5 (and possibly others), the IP id field
  672. // is set by the kernel routine rip_output()
  673. // only if it is non-zero, so we should be ok.
  674. int one = 1;
  675. if (::setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &one, sizeof(one)) < 0) {
  676. fprintf(stderr,
  677. "IPNetwork(%s): open: unable to turn on IP_HDRINCL: %sn",
  678. name(), strerror(errno));
  679. return (-1);
  680. }
  681. #ifndef __linux__
  682. // sort of curious, but do a connect() even though we have
  683. // HDRINCL on.  Otherwise, we get ENOTCONN when doing a send()
  684. sockaddr_in sin;
  685. in_addr ia = { INADDR_ANY };
  686. if (connectsock(fd, ia, 0, sin) < 0) {
  687. fprintf(stderr,
  688. "IPNetwork(%s): open: unable to connect : %sn",
  689. name(), strerror(errno));
  690. }
  691. #endif
  692. rsock_ = ssock_ = fd;
  693. mode_ = mode;
  694. NIDEBUG5("IPNetwork(%s): opened with mode %d, rsock_:%d, ssock_:%dn",
  695. name(), mode_, rsock_, ssock_);
  696. return 0;
  697. }
  698. /*
  699.  * close both sending and receiving sockets
  700.  */
  701. int
  702. IPNetwork::close()
  703. {
  704. if (ssock_ >= 0) {
  705. (void)::close(ssock_);
  706. ssock_ = -1;
  707. }
  708. if (rsock_ >= 0) {
  709. (void)::close(rsock_);
  710. rsock_ = -1;
  711. }
  712. return (0);
  713. }
  714. /*
  715.  * add multicast group membership on the socket
  716.  */
  717. int
  718. IPNetwork::add_membership(Socket fd, in_addr& addr)
  719. {
  720. #if defined(IP_ADD_MEMBERSHIP)
  721. if (IN_CLASSD(ntohl(addr.s_addr))) {
  722. #ifdef notdef
  723. /*
  724.  * Try to bind the multicast address as the socket
  725.  * dest address.  On many systems this won't work
  726.  * so fall back to a destination of INADDR_ANY if
  727.  * the first bind fails.
  728.  */
  729. sockaddr_in sin;
  730. memset(&sin, 0, sizeof(sin));
  731. sin.sin_family = AF_INET;
  732. sin.sin_addr = addr;
  733. if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  734. sin.sin_addr.s_addr = INADDR_ANY;
  735. if (::bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  736. fprintf(stderr,
  737. "IPNetwork(%s): add_membership: unable to bind to addr %s: %sn",
  738. name(), inet_ntoa(sin.sin_addr),
  739. strerror(errno));
  740. return (-1);
  741. }
  742. }
  743. #endif
  744. /* 
  745.  * XXX This is bogus multicast setup that really
  746.  * shouldn't have to be done (group membership should be
  747.  * implicit in the IP class D address, route should contain
  748.  * ttl & no loopback flag, etc.).  Steve Deering has promised
  749.  * to fix this for the 4.4bsd release.  We're all waiting
  750.  * with bated breath.
  751.  */
  752. struct ip_mreq mr;
  753. mr.imr_multiaddr = addr;
  754. mr.imr_interface.s_addr = INADDR_ANY;
  755. if (::setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
  756.        (char *)&mr, sizeof(mr)) < 0) {
  757. fprintf(stderr, "IPNetwork(%s): add_membership: unable to add membership for addr %s: %sn",
  758. name(), inet_ntoa(addr), strerror(errno));
  759. return (-1);
  760. }
  761. NIDEBUG3("IPNetwork(%s): add_membership for grp %s donen",
  762. name(), inet_ntoa(addr));
  763. return (0);
  764. }
  765. #else
  766. fprintf(stderr, "IPNetwork(%s): add_membership: host does not support IP multicastn",
  767. name());
  768. #endif
  769. NIDEBUG3("IPNetwork(%s): add_membership for grp %s failedn",
  770. name(), inet_ntoa(addr));
  771. return (-1);
  772. }
  773. /*
  774.  * drop membership from the specified group on the specified socket
  775.  */
  776. int
  777. IPNetwork::drop_membership(Socket fd, in_addr& addr)
  778. {
  779. #if defined(IP_DROP_MEMBERSHIP)
  780. if (IN_CLASSD(ntohl(addr.s_addr))) {
  781. struct ip_mreq mr;
  782. mr.imr_multiaddr = addr;
  783. mr.imr_interface.s_addr = INADDR_ANY;
  784. if (::setsockopt(fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
  785.        (char *)&mr, sizeof(mr)) < 0) {
  786. fprintf(stderr, "IPNetwork(%s): drop_membership: unable to drop membership for addr %s: %sn",
  787. name(), inet_ntoa(addr), strerror(errno));
  788. return (-1);
  789. }
  790. NIDEBUG3("IPNetwork(%s): drop_membership for grp %s donen",
  791. name(), inet_ntoa(addr));
  792. return (0);
  793. }
  794. #else
  795. fprintf(stderr, "IPNetwork(%s): drop_membership: host does not support IP multicastn",
  796. name());
  797. #endif
  798. NIDEBUG3("IPNetwork(%s): drop_membership for grp %s failedn",
  799. name(), inet_ntoa(addr));
  800. return (-1);
  801. }
  802. int
  803. IPNetwork::bindsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
  804. {
  805. memset((char *)&sin, 0, sizeof(sin));
  806. sin.sin_family = AF_INET;
  807. sin.sin_port = port;
  808. sin.sin_addr = addr;
  809. return(::bind(s, (struct sockaddr *)&sin, sizeof(sin)));
  810. }
  811. int
  812. IPNetwork::connectsock(Socket s, in_addr& addr, u_int16_t port, sockaddr_in& sin)
  813. {
  814. memset((char *)&sin, 0, sizeof(sin));
  815. sin.sin_family = AF_INET;
  816. sin.sin_port = port;
  817. sin.sin_addr = addr;
  818. return(::connect(s, (struct sockaddr *)&sin, sizeof(sin)));
  819. }
  820. int 
  821. IPNetwork::sbufsize(Socket s, int cnt)
  822. {   
  823.         return(::setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&cnt, sizeof(cnt)));
  824. }   
  825. int
  826. IPNetwork::rbufsize(Socket s, int cnt)
  827. {   
  828.         return(::setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&cnt, sizeof(cnt)));
  829. }   
  830. int
  831. IPNetwork::setmloop(Socket s, int loop)
  832. {
  833. #ifdef IP_MULTICAST_LOOP
  834. u_char c = loop;
  835. if (::setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &c, sizeof(c)) < 0) {
  836. /*
  837.  * If we cannot turn off loopback (Like on the
  838.  * Microsoft TCP/IP stack), then declare this
  839.  * option broken so that our packets can be
  840.  * filtered on the recv path.
  841.  */
  842. if (c != loop) {
  843. noloopback_broken_ = 1;
  844. loop_ = c;
  845. }
  846. return (-1);
  847. }
  848. noloopback_broken_ = 0;
  849. #else
  850. fprintf(stderr, "IPNetwork(%s): msetloop: host does not support IP multicastn",
  851. name());
  852. #endif
  853. loop_ = c;
  854. return (0);
  855. }
  856. void
  857. IPNetwork::reset(int restart)
  858. {
  859. time_t t = time(0);
  860. int d = int(t - last_reset_);
  861. NIDEBUG2("IPNetwork(%s): resetn", name());
  862. if (d > 3) { // Steve: why?
  863. last_reset_ = t;
  864. if (ssock_ >= 0)
  865. (void)::close(ssock_);
  866. if (rsock_ >= 0)
  867. (void)::close(rsock_);
  868. if (open(mode_) < 0) {
  869. fprintf(stderr,
  870.   "IPNetwork(%s): couldn't resetn",
  871.   name());
  872. mode_ = -1;
  873. return;
  874. }
  875. if (restart)
  876. (void) reconfigure();
  877. }
  878. }
  879. /*
  880.  * after a reset, we may want to re-establish our state
  881.  * [set up addressing, etc].  Do this here
  882.  */
  883. void
  884. IPNetwork::reconfigure()
  885. {
  886. }
  887. void
  888. UDPIPNetwork::reconfigure()
  889. {
  890. }