📄 net-ip.cc
字号:
/*- * Copyright (c) 1993-1994, 1996 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. * * $Id: net-ip.cc,v 1.2 1996/06/05 01:24:27 aswan Exp $ */#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <unistd.h>#include <sys/param.h>#include <sys/socket.h>#include <sys/ioctl.h>#include "config.h"#include "net.h"#include "Tcl.h"class IPNetwork : public Network {public: virtual int command(int argc, const char*const* argv); virtual void reset();protected: int open(u_int32_t addr, int port, int ttl); int close(); void localname(sockaddr_in*); int openssock(u_int32_t addr, u_short port, int ttl) const; int openrsock(u_int32_t addr, u_short port, const struct sockaddr_in& local); time_t last_reset_;};static class IPNetworkMatcher : public Matcher {public: IPNetworkMatcher() : Matcher("network") {} TclObject* match(const char* id) { if (strcasecmp(id, "ip") == 0) return (new IPNetwork); else return (0); }} nm_ip;int IPNetwork::command(int argc, const char*const* argv){ Tcl& tcl = Tcl::instance(); if (argc == 2) { if (strcmp(argv[1], "close") == 0) { close(); return (TCL_OK); } } else if (argc == 3) { if (strcmp(argv[1], "loopback") == 0) { char c = atoi(argv[2]); if (setsockopt(ssock_, IPPROTO_IP, IP_MULTICAST_LOOP, (const char*)&c, 1) < 0) { perror("IP_MULTICAST_LOOP"); exit(1); } return (TCL_OK); } } else if (argc == 5) { if (strcmp(argv[1], "open") == 0) { u_int32_t addr = LookupHostAddr(argv[2]); int port = htons(atoi(argv[3])); int ttl = atoi(argv[4]); if (open(addr, port, ttl) < 0) tcl.result("0"); else tcl.result("1"); return (TCL_OK); } } return (Network::command(argc, argv));}int IPNetwork::open(u_int32_t addr, int port, int ttl){ addr_ = addr; port_ = port; ttl_ = ttl; ssock_ = openssock(addr, port, ttl); if (ssock_ < 0) return (-1); /* * Connecting the send socket also bound the local address. * On a multihomed host we need to bind the receive socket * to the same local address the kernel has chosen to send on. */ sockaddr_in local; localname(&local); local_ = local.sin_addr.s_addr; rsock_ = openrsock(addr, port, local); if (rsock_ < 0) { (void)::close(ssock_); return (-1); } last_reset_ = 0; return (0);}int IPNetwork::close(){ if (ssock_ >= 0) { ::close(ssock_); ::close(rsock_); ssock_ = rsock_ = -1; } return (0);}void IPNetwork::localname(sockaddr_in* p){ memset((char *)p, 0, sizeof(*p)); p->sin_family = AF_INET; int len = sizeof(*p); if (getsockname(ssock_, (struct sockaddr *)p, &len) < 0) { perror("getsockname"); p->sin_addr.s_addr = 0; p->sin_port = 0; }}void IPNetwork::reset(){ time_t t = time(0); int d = int(t - last_reset_); if (d > 3) { last_reset_ = t; (void)::close(ssock_); ssock_ = openssock(addr_, port_, ttl_); sockaddr_in local; localname(&local); }}int IPNetwork::openrsock(u_int32_t addr, u_short port, const struct sockaddr_in& local){ int fd; struct sockaddr_in sin; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket"); exit(1); } nonblock(fd); int on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) { perror("SO_REUSEADDR"); }#ifdef SO_REUSEPORT on = 1; if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&on, sizeof(on)) < 0) { perror("SO_REUSEPORT"); exit(1); }#endif memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = port;#ifdef IP_ADD_MEMBERSHIP if (IN_CLASSD(ntohl(addr))) { /* * Try to bind the multicast address as the socket * dest address. On many systems this won't work * so fall back to a destination of INADDR_ANY if * the first bind fails. */ sin.sin_addr.s_addr = addr; if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { sin.sin_addr.s_addr = INADDR_ANY; if (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { perror("bind"); exit(1); } } /* * XXX This is bogus multicast setup that really * shouldn't have to be done (group membership should be * implicit in the IP class D address, route should contain * ttl & no loopback flag, etc.). Steve Deering has promised * to fix this for the 4.4bsd release. We're all waiting * with bated breath. */ struct ip_mreq mr; mr.imr_multiaddr.s_addr = addr; mr.imr_interface.s_addr = INADDR_ANY; if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mr, sizeof(mr)) < 0) { perror("IP_ADD_MEMBERSHIP"); exit(1); } } else#endif { /* * bind the local host's address to this socket. If that * fails, another vic probably has the addresses bound so * just exit. */ sin.sin_addr.s_addr = local.sin_addr.s_addr; if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); exit(1); } /* * (try to) connect the foreign host's address to this socket. */ sin.sin_port = 0; sin.sin_addr.s_addr = addr; connect(fd, (struct sockaddr *)&sin, sizeof(sin)); } /* * XXX don't need this for the session socket. */ int bufsize = 80 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize = 32 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) perror("SO_RCVBUF"); } return (fd);}int IPNetwork::openssock(u_int32_t addr, u_short port, int ttl) const{ int fd; struct sockaddr_in sin; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { perror("socket"); exit(1); } nonblock(fd); memset((char *)&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = port; sin.sin_addr.s_addr = addr; if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("connect"); exit(1); } if (IN_CLASSD(ntohl(addr))) {#ifdef IP_ADD_MEMBERSHIP unsigned char c; /* turn off loopback */ c = 0; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &c, 1) < 0) { perror("IP_MULTICAST_LOOP"); exit(1); } /* set the multicast TTL */ u_char t; t = (ttl > 255) ? 255 : (ttl < 0) ? 0 : ttl; if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, (const char*)&t, sizeof(t)) < 0) { perror("IP_MULTICAST_TTL"); exit(1); }#else fprintf(stderr, "\not compiled with support for IP multicast\n\you must specify a unicast destination\n"); exit(1);#endif } /* * XXX don't need this for the session socket. */ int bufsize = 80 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize)) < 0) { bufsize = 48 * 1024; if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(bufsize)) < 0) perror("SO_SNDBUF"); } return (fd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -