📄 net.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.cc,v 1.2 1996/06/05 01:24:27 aswan Exp $ */#include <stdlib.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <fcntl.h>#include <errno.h>#include <string.h>#include <sys/socket.h>#include <sys/uio.h>#include "net.h"//#include "crypt.h"/* * Linux does not have sendmsg */#if defined(__linux__)#define MAXPACKETSIZE (1500-28)static intsendmsg(int s, struct msghdr* mh, int flags){ u_char wrkbuf[MAXPACKETSIZE]; int len = mh->msg_iovlen; struct iovec* iov = mh->msg_iov; u_char* cp; u_char* ep; for (cp = wrkbuf, ep = wrkbuf + MAXPACKETSIZE; --len >= 0; ++iov) { int plen = iov->iov_len; if (cp + plen >= ep) { errno = E2BIG; return (-1); } memcpy(cp, iov->iov_base, plen); cp += plen; } return (send(s, (char*)wrkbuf, cp - wrkbuf, flags));}#endifNetwork::Network() : addr_(0), local_(0), port_(0), ttl_(0), rsock_(-1), ssock_(-1), crypt_(0){}Network::~Network(){}int Network::command(int argc, const char*const* argv){ if (argc == 2) { Tcl& tcl = Tcl::instance(); char* cp = tcl.buffer(); if (strcmp(argv[1], "addr") == 0) strcpy(cp, intoa(addr_)); else if (strcmp(argv[1], "interface") == 0) strcpy(cp, intoa(local_)); else if (strcmp(argv[1], "port") == 0) sprintf(cp, "%d", ntohs(port_)); else if (strcmp(argv[1], "ttl") == 0) sprintf(cp, "%d", ttl_); else return (TclObject::command(argc, argv)); tcl.result(cp); return (TCL_OK); } else if (argc == 3) { if (strcmp(argv[1], "crypt") == 0) { /* * 'crypt ""' will turn of encryption because * lookup() will return null. */ crypt_ = (Crypt*)TclObject::lookup(argv[2]); return (TCL_OK); } } return (TclObject::command(argc, argv));}void Network::nonblock(int fd){ int flags = fcntl(fd, F_GETFL, 0);#if defined(hpux) || defined(__hpux) flags |= O_NONBLOCK;#else flags |= O_NONBLOCK|O_NDELAY;#endif if (fcntl(fd, F_SETFL, flags) == -1) { perror("fcntl: F_SETFL"); exit(1); }}u_char* Network::wrkbuf_;int Network::wrkbuflen_;void Network::expand_wrkbuf(int len){ if (wrkbuflen_ == 0) wrkbuf_ = (u_char*)malloc(len); else wrkbuf_ = (u_char*)realloc((u_char*)wrkbuf_, len); wrkbuflen_ = len;}void Network::dosend(u_char* buf, int len, int fd){ int cc = ::send(fd, (char*)buf, len, 0); if (cc < 0) { switch (errno) { case ECONNREFUSED: /* no one listening at some site - ignore */#if defined(__osf__) || defined(_AIX) /* * 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 know 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();#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. */ (void)::send(ssock_, (char*)buf, len, 0); break; default: perror("send"); return; } }}void Network::send(u_char* buf, int len){ if (crypt_) //buf = crypt_->Encrypt(buf, len); dosend(buf, len, ssock_);}/* * Copy a scatter/gather packet to the work buffer and * return it's length. */int Network::cpmsg(const msghdr& mh){ int len, i; for (len = 0, i = 0; i < mh.msg_iovlen; ++i) len += mh.msg_iov[i].iov_len; expand_wrkbuf(len); u_char* cp = wrkbuf_; for (i = 0; i < mh.msg_iovlen; ++i) { int cc = mh.msg_iov[i].iov_len; memcpy(cp, mh.msg_iov[i].iov_base, cc); cp += cc; } return (len);}void Network::sendmsg(const msghdr& mh){ if (crypt_) { int cc = cpmsg(mh); send(wrkbuf_, cc); return; } int cc = ::sendmsg(ssock_, (msghdr*)&mh, 0); if (cc < 0) { switch (errno) { case ECONNREFUSED: /* no one listening at some site - ignore */#if defined(__osf__) || defined(_AIX) reset();#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. */ (void)::sendmsg(ssock_, (msghdr*)&mh, 0); break; default: perror("sendmsg"); return; } }}int Network::dorecv(u_char* buf, int len, u_int32_t& from, int fd){ errno = 0; sockaddr_in sfrom; int fromlen = sizeof(sfrom); int cc = ::recvfrom(fd, (char*)buf, len, 0, (sockaddr*)&sfrom, &fromlen); if (cc < 0) { if (errno != EWOULDBLOCK) perror("recvfrom"); return (-1); } from = sfrom.sin_addr.s_addr; return (cc);}int Network::recv(u_char* buf, int len, u_int32_t& from){ if (crypt_) { if (len > wrkbuflen_) expand_wrkbuf(len); int cc = dorecv(wrkbuf_, len, from, rsock_); //return (crypt_->Decrypt(wrkbuf_, cc, buf)); } return (dorecv(buf, len, from, rsock_));}void Network::reset(){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -