📄 net-ip.cc
字号:
/*- * Copyright (c) 1993-1994, 1998 * The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and the Network Research Group at * Lawrence Berkeley Laboratory. * 4. Neither the name of the University nor of the Laboratory may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic const char rcsid[] = "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/emulate/net-ip.cc,v 1.17 2000/02/08 23:35:13 salehi Exp $ (LBL)";#endif#include <stdio.h>#ifndef WIN32#include <unistd.h>#endif#include <time.h>#include <errno.h>#include <string.h>#ifdef WIN32#include <io.h>#define close closesocket#else#include <sys/param.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <netinet/in.h>#include <netinet/in_systm.h>#include <netinet/ip.h>typedef int Socket;#endif#if defined(sun) && defined(__svr4__)#include <sys/systeminfo.h>#endif#include "config.h"#include "net.h"#include "inet.h"#include "tclcl.h"#include "scheduler.h"//#define NIPDEBUG 1#ifdef NIPDEBUG#define NIDEBUG(x) { if (NIPDEBUG) fprintf(stderr, (x)); }#define NIDEBUG2(x,y) { if (NIPDEBUG) fprintf(stderr, (x), (y)); }#define NIDEBUG3(x,y,z) { if (NIPDEBUG) fprintf(stderr, (x), (y), (z)); }#define NIDEBUG4(w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (w), (x), (y), (z)); }#define NIDEBUG5(v,w,x,y,z) { if (NIPDEBUG) fprintf(stderr, (v), (w), (x), (y), (z)); }#else#define NIDEBUG(x) { }#define NIDEBUG2(x,y) { }#define NIDEBUG3(x,y,z) { }#define NIDEBUG4(w,x,y,z) { }#define NIDEBUG5(v,w,x,y,z) { }#endif/* * Net-ip.cc: this file defines the IP and IP/UDP network * objects. IP provides a raw IP interface and support functions * [such as setting multicast parameters]. IP/UDP provides a standard * UDP datagram interface. *///// IPNetwork: a low-level (raw) IP network object//class IPNetwork : public Network {public: IPNetwork(); inline int ttl() const { return (mttl_); } // current mcast ttl inline int noloopback_broken() { // no loopback filter? return (noloopback_broken_); } int setmttl(Socket, int); // set mcast ttl int setmloop(Socket, int); // set mcast loopback int command(int argc, const char*const* argv); // virtual in Network inline Socket rchannel() { return(rsock_); } // virtual in Network inline Socket schannel() { return(ssock_); } // virtual in Network int send(u_char* buf, int len); // virtual in Network int recv(u_char* buf, int len, sockaddr& from, double& ); // virtual in Network inline in_addr& laddr() { return (localaddr_); } inline in_addr& dstaddr() { return (destaddr_); } int add_membership(Socket, in_addr& grp); // join mcast int drop_membership(Socket, in_addr& grp); // leave mcast /* generally useful routines */ static int bindsock(Socket, in_addr&, u_int16_t, sockaddr_in&); static int connectsock(Socket, in_addr&, u_int16_t, sockaddr_in&); static int rbufsize(Socket, int); static int sbufsize(Socket, int);protected: in_addr destaddr_; // remote side, if set (network order) in_addr localaddr_; // local side (network order) int mttl_; // multicast ttl to use Socket rsock_; // socket to receive on Socket ssock_; // socket to send on int noloopback_broken_; // couldn't turn (off) mcast loopback int loop_; // do we want loopbacks? // (system usually assumes yes) void reset(int reconfigure); // reset + reconfig? virtual int open(int mode); // open sockets/endpoints virtual void reconfigure(); // restore state after reset int close(); time_t last_reset_;};class UDPIPNetwork : public IPNetwork {public: UDPIPNetwork(); int send(u_char*, int); int recv(u_char*, int, sockaddr&, double&); int open(int mode); // mode only int command(int argc, const char*const* argv); void reconfigure(); void add_membership(Socket, in_addr&, u_int16_t); // udp versionprotected: int bind(in_addr&, u_int16_t port); // bind to addr/port, mcast ok int connect(in_addr& remoteaddr, u_int16_t port); // connect() u_int16_t lport_; // local port (network order) u_int16_t port_; // remote (dst) port (network order)};static class IPNetworkClass : public TclClass { public: IPNetworkClass() : TclClass("Network/IP") {} TclObject* create(int, const char*const*) { return (new IPNetwork); }} nm_ip;static class UDPIPNetworkClass : public TclClass { public: UDPIPNetworkClass() : TclClass("Network/IP/UDP") {} TclObject* create(int, const char*const*) { return (new UDPIPNetwork); }} nm_ip_udp;IPNetwork::IPNetwork() : mttl_(0), rsock_(-1), ssock_(-1), noloopback_broken_(0), loop_(1){ localaddr_.s_addr = 0L; destaddr_.s_addr = 0L; NIDEBUG("IPNetwork: ctor\n");}UDPIPNetwork::UDPIPNetwork() : lport_(htons(0)), port_(htons(0)){ NIDEBUG("UDPIPNetwork: ctor\n");}/* * UDPIP::send -- send "len" bytes in buffer "buf" out the sending * channel. * * returns the number of bytes written */intUDPIPNetwork::send(u_char* buf, int len){ int cc = ::send(schannel(), (char*)buf, len, 0); NIDEBUG5("UDPIPNetwork(%s): ::send(%d, buf, %d) returned %d\n", name(), schannel(), len, cc); if (cc < 0) { switch (errno) { case ECONNREFUSED: /* no one listening at some site - ignore */#if defined(__osf__) || defined(_AIX) || defined(__FreeBSD__) /* * Here's an old comment... * * Due to a bug in kern/uipc_socket.c, on several * systems, datagram sockets incorrectly persist * in an error state on receipt of an ICMP * port-unreachable. This causes unicast connection * rendezvous problems, and worse, multicast * transmission problems because several systems * incorrectly send port unreachables for * multicast destinations. Our work around * is to simply close and reopen the socket * (by calling reset() below). * * This bug originated at CSRG in Berkeley * and was present in the BSD Reno networking * code release. It has since been fixed * in 4.4BSD and OSF-3.x. It is known to remain * in AIX-4.1.3. * * A fix is to change the following lines from * kern/uipc_socket.c: * * if (so_serror) * snderr(so->so_error); * * to: * * if (so->so_error) { * error = so->so_error; * so->so_error = 0; * splx(s); * goto release; * } * */ reset(1);#endif break; case ENETUNREACH: case EHOSTUNREACH: /* * These "errors" are totally meaningless. * There is some broken host sending * icmp unreachables for multicast destinations. * UDP probably aborted the send because of them -- * try exactly once more. E.g., the send we * just did cleared the errno for the previous * icmp unreachable, so we should be able to * send now. */ cc = ::send(schannel(), (char*)buf, len, 0); break; default: fprintf(stderr, "UDPIPNetwork(%s): send failed: %s\n", name(), strerror(errno)); return (-1); } } return cc; // bytes sent}intUDPIPNetwork::recv(u_char* buf, int len, sockaddr& from, double& ts){ sockaddr_in sfrom; int fromlen = sizeof(sfrom); int cc = ::recvfrom(rsock_, (char*)buf, len, 0, (sockaddr*)&sfrom, &fromlen); NIDEBUG5("UDPIPNetwork(%s): ::recvfrom(%d, buf, %d) returned %d\n", name(), rsock_, len, cc); if (cc < 0) { if (errno != EWOULDBLOCK) { fprintf(stderr, "UDPIPNetwork(%s): recvfrom failed: %s\n", name(), strerror(errno)); } return (-1); } from = *((sockaddr*)&sfrom); /* * if we received multicast data and we don't want the look, * there is a chance it is * what we sent if "noloopback_broken_" is set. * If so, filter out the stuff we don't want right here. */ if (!loop_ && noloopback_broken_ && sfrom.sin_addr.s_addr == localaddr_.s_addr && sfrom.sin_port == lport_) { NIDEBUG2("UDPIPNetwork(%s): filtered out our own pkt\n", name()); return (0); // empty } ts = Scheduler::instance().clock(); return (cc); // number of bytes received}intUDPIPNetwork::open(int mode){ if (mode == O_RDONLY || mode == O_RDWR) { rsock_ = socket(AF_INET, SOCK_DGRAM, 0); if (rsock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: couldn't open rcv sock\n", name()); } nonblock(rsock_); int on = 1; if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: warning: unable set REUSEADDR: %s\n", name(), strerror(errno)); }#ifdef SO_REUSEPORT on = 1; if (::setsockopt(rsock_, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: warning: unable set REUSEPORT: %s\n", name(), strerror(errno)); }#endif /* * XXX don't need this for the session socket. */ if (rbufsize(rsock_, 80*1024) < 0) { if (rbufsize(rsock_, 32*1024) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: unable to set r bufsize to %d: %s\n", name(), 32*1024, strerror(errno)); } } } if (mode == O_WRONLY || mode == O_RDWR) { ssock_ = socket(AF_INET, SOCK_DGRAM, 0); if (ssock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: couldn't open snd sock\n", name()); } nonblock(ssock_); int firsttry = 80 * 1024; int secondtry = 48 * 1024; if (sbufsize(ssock_, firsttry) < 0) { if (sbufsize(ssock_, secondtry) < 0) { fprintf(stderr, "UDPIPNetwork(%s): open: cannot set send sockbuf size to %d bytes, using default\n", name(), secondtry); } } } mode_ = mode; NIDEBUG5("UDPIPNetwork(%s): opened network w/mode %d, ssock:%d, rsock:%d\n", name(), mode_, rsock_, ssock_); return (0);}//// IP/UDP version of add_membership: try binding//voidUDPIPNetwork::add_membership(Socket sock, in_addr& addr, u_int16_t port){ int failure = 0; sockaddr_in sin; if (bindsock(sock, addr, port, sin) < 0) failure = 1; if (failure) { in_addr addr2 = addr; addr2.s_addr = INADDR_ANY; if (bindsock(sock, addr2, port, sin) < 0) failure = 1; else failure = 0; } if (IPNetwork::add_membership(sock, addr) < 0) failure = 1; if (failure) { fprintf(stderr, "UDPIPNetwork(%s): add_membership: failed bind on mcast addr %s and INADDR_ANY\n", name(), inet_ntoa(addr)); }}//// server-side bind (or mcast subscription)//intUDPIPNetwork::bind(in_addr& addr, u_int16_t port){ NIDEBUG4("UDPIPNetwork(%s): attempt to bind to addr %s, port %d [net order]\n", name(), inet_ntoa(addr), ntohs(port)); if (rsock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): bind/listen called before net is open\n", name()); return (-1); } if (mode_ == O_WRONLY) { fprintf(stderr, "UDPIPNetwork(%s): attempted bind/listen but net is write-only\n", name()); return (-1); }#ifdef IP_ADD_MEMBERSHIP if (IN_CLASSD(ntohl(addr.s_addr))) { // MULTICAST case, call UDPIP vers of add_membership add_membership(rsock_, addr, port); } else#endif { // UNICAST case sockaddr_in sin; if (bindsock(rsock_, addr, port, sin) < 0) { port = ntohs(port); fprintf(stderr, "UDPIPNetwork(%s): bind: unable to bind %s [port:%hu]: %s\n", name(), inet_ntoa(addr), port, strerror(errno)); return (-1); } /* * MS Windows currently doesn't compy with the Internet Host * Requirements standard (RFC-1122) and won't let us include * the source address in the receive socket demux state. */#ifndef WIN32 /* * (try to) connect the foreign host's address to this socket. */ (void)connectsock(rsock_, addr, 0, sin);#endif } localaddr_ = addr; lport_ = port; return (0);}//// client-side connect//intUDPIPNetwork::connect(in_addr& addr, u_int16_t port){ sockaddr_in sin; if (ssock_ < 0) { fprintf(stderr, "UDPIPNetwork(%s): connect called before net is open\n", name());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -