UdpStack.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:34k
- /* ====================================================================
- * The Vovida Software License, Version 1.0
- *
- * Copyright (c) 2000 Vovida Networks, Inc. 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. The names "VOCAL", "Vovida Open Communication Application Library",
- * and "Vovida Open Communication Application Library (VOCAL)" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact vocal@vovida.org.
- *
- * 4. Products derived from this software may not be called "VOCAL", nor
- * may "VOCAL" appear in their name, without prior written
- * permission of Vovida Networks, Inc.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
- * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
- * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
- * IN EXCESS OF $1,000, NOR FOR ANY 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.
- *
- * ====================================================================
- *
- * This software consists of voluntary contributions made by Vovida
- * Networks, Inc. and many individuals on behalf of Vovida Networks,
- * Inc. For more information on Vovida Networks, Inc., please see
- * <http://www.vovida.org/>.
- *
- */
- static const char* const UdpStack_cxx_Version =
- "$Id: UdpStack.cxx,v 1.3 2001/06/27 01:43:47 bko Exp $";
- /* TODO List
- * - add sendTo function to allow you to specifiy different destinations
- * - add recvFrom function that tell you who the packet came from
- * - add non blockinge version fo send and receive
- * - derive "ReliableUDP" stack that takes care of retransmissions
- * - look into using MSG_ERRQUEUE to check for ICMP errors
- * - check portability
- * - support IP6
- * - stress test
- */
- #include <fstream>
- #include <assert.h>
- #include <string.h> // for memset
- #include <errno.h>
- #include <iostream>
- #include <stdio.h>
- #include <netdb.h>
- #if defined(__FreeBSD__)
- #include <sys/types.h>
- #endif
- #include <netinet/in.h> // for struct sockaddr_in
- #include <stdlib.h>
- #include <strstream>
- #include <sys/types.h>
- #include <arpa/inet.h>
- #include <sys/socket.h>
- #include "VTime.hxx"
- #include <unistd.h>
- #ifndef __vxworks
- #include <fcntl.h>
- #endif
- #include "vovida-endian.h"
- #if defined(__svr4__)
- #include <xil/xil.h>
- #if (XIL_API_MINOR_VERSION - 0 == 3)
- typedef int socklen_t;
- #endif
- #endif
- #include "UdpStack.hxx"
- #include "cpLog.h"
- #include "vsock.hxx"
- #include "LockHelper.hxx"
- static VMutex G_lock;
- // this class hold stuff that is likely to be a problem to port
- class UdpStackPrivateData
- {
- public:
- /// File descriptor of socket
- int socketFd;
- /// Address of local computer that will receive or send the packets
- struct sockaddr_in localAddr;
- /// Address of remote computer that local computer receive from
- /// or send to the packets
- /// This address is set when doClient is called.
- /// And later when setDestination() is called, this address will be the one
- /// connect to. But disconnectPorts() won't remove this address.
- struct sockaddr_in remoteAddr;
- };
- static const char separator[7] = "n****n";
- UdpStack::UdpStack ( const NetworkAddress* desHost
- /* null if this is the server */ ,
- int minPort,
- int maxPort,
- UdpMode udpMode,
- bool log_flag,
- bool isMulticast)
- : localPort( -1),
- remotePort( -1),
- packetLossProbability( float(0.0) ),
- numBytesReceived (0),
- numPacketsReceived (0),
- numBytesTransmitted (0),
- numPacketsTransmitted (0),
- mode (sendrecv),
- logFlag (log_flag)
- {
- data = new UdpStackPrivateData;
- assert(data);
- mode = udpMode;
- // open a socket
- data->socketFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- cpLog (LOG_DEBUG_STACK, "UdpStack socketFd = %d", data->socketFd);
- if ( data->socketFd < 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" /* << getLclName() */
- << ">::UdpStack error during socket creation: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- throw UdpStackException(errMsg.str());
- errMsg.freeze(false);
- assert(0);
- }
- int buf1 = 1;
- int len1 = sizeof(buf1);
- /*
- int rcvbuf = 0;
- int rcvbufnew = 240 * 1024;
- int rcvbufnewlen = sizeof(rcvbufnew);
- int sndbuf = 0;
- unsigned int rcvbuflen = 1;
- unsigned int sndbuflen = 1;
- */
- #ifdef __linux__
- struct protoent * protoent;
- protoent = getprotobyname("icmp");
- if (!protoent)
- {
- fprintf(stderr, "Cannot get icmp protocoln");
- }
- else
- {
- if (setsockopt(data->socketFd, protoent->p_proto, SO_BSDCOMPAT,
- (char*)&buf1, len1)
- == -1)
- {
- fprintf(stderr, "setsockopt error SO_BSDCOMPAT :%sn",
- strerror(errno));
- }
- /*
- if (setsockopt(data->socketFd, SOL_SOCKET, SO_RCVBUF,
- (int *)&rcvbufnew, rcvbufnewlen)
- == -1)
- {
- fprintf(stderr, "setsockopt error SO_RCVBUF :%sn",
- strerror(errno));
- }
- if (getsockopt(data->socketFd, SOL_SOCKET, SO_RCVBUF,
- (int*)&rcvbuf, &rcvbuflen) == -1)
- {
- fprintf(stderr, "getsockopt error SO_RCVBUF :%sn",
- strerror(errno));
- }
- else
- {
- cerr << "SO_RCVBUF = " << rcvbuf << " rcvbuflen = " << rcvbuflen << endl;
- }
- if (getsockopt(data->socketFd, SOL_SOCKET, SO_SNDBUF,
- (int*)&sndbuf, &sndbuflen) == -1)
- {
- fprintf(stderr, "getsockopt error SO_SNDBUF :%sn",
- strerror(errno));
- }
- else
- {
- cerr << "SO_SNDBUF = " << sndbuf << " sndbuflen = " << sndbuflen << endl;
- }
- */
- }
- #endif
- if (isMulticast)
- {
- // set option to get rid of the "Address already in use" error
- if (setsockopt(data->socketFd, SOL_SOCKET, SO_REUSEADDR,
- (char*)&buf1, len1)
- == -1)
- {
- fprintf(stderr, "setsockopt error SO_REUSEADDR :%s",
- strerror(errno));
- }
- #ifdef __FreeBSD__
- if (setsockopt(data->socketFd, SOL_SOCKET, SO_REUSEPORT,
- (char*)&buf1, len1)
- == -1)
- {
- fprintf(stderr, "setsockopt error SO_REUSEPORT :%s",
- strerror(errno));
- }
- #endif
- }
- // set up addresses
- memset((char*) &(data->localAddr), 0, sizeof((data->localAddr)));
- (data->localAddr).sin_family = AF_INET;
- (data->localAddr).sin_addr.s_addr = htonl(INADDR_ANY);
- memset((char*) &(data->remoteAddr), 0, sizeof((data->remoteAddr)));
- (data->remoteAddr).sin_family = AF_INET;
- (data->remoteAddr).sin_addr.s_addr = htonl(INADDR_ANY);
- switch (mode)
- {
- case inactive :
- {
- cpLog(LOG_INFO, "Udp stack is inactive");
- cpLog(LOG_ERR, "desHost is saved for future use.");
- doClient(desHost, desHost->getPort());
- }
- break;
- case sendonly :
- {
- if ( desHost )
- {
- // set the remote address
- doClient(desHost, desHost->getPort());
- }
- else
- {
- cpLog(LOG_INFO,
- "sendonly Udp stack, desHost is needed by using setDestination()");
- }
- }
- break;
- case recvonly :
- {
- if ( desHost )
- {
- cpLog(LOG_ERR,
- "recvonly Udp stack, desHost is saved for future use.");
- doClient(desHost, desHost->getPort());
- }
- else
- {
- // only receive, do bind socket to local port
- doServer(minPort, maxPort);
- }
- }
- break;
- case sendrecv :
- {
- if ( desHost )
- {
- // receive and send,
- // bind the socket to local port and set the remote address
- doServer(minPort, maxPort);
- doClient(desHost, desHost->getPort());
- }
- else
- {
- // only receive, do bind socket to local port
- doServer(minPort, maxPort);
- cpLog(LOG_INFO,
- "sendrecv Udp stack, desHost is needed by using setDestination()");
- }
- }
- break;
- default :
- cpLog(LOG_ERR, "undefined mode for udp stack");
- break;
- }
- // logFlag = true;
- strstream logFileNameRcv;
- strstream logFileNameSnd;
- logFileNameRcv << "udpRcv" << "-"
- << data->socketFd << "-"
- << localPort << ".log"
- << char(0);
- logFileNameSnd << "udpSnd" << "-"
- << data->socketFd << "-"
- << localPort << ".log"
- << char(0);
- if (logFlag)
- {
- in_log = new ofstream(logFileNameRcv.str(), ios::app);
- if (!in_log)
- {
- cerr << "Cannot open file "
- << logFileNameRcv.str() << endl;
- logFileNameRcv.freeze(false);
- logFlag = false;
- }
- else
- {
- in_log->write ("UdpRcvn", 7);
- strstream lcPort;
- lcPort << "localPort: " << localPort << "n" << char(0);
- in_log->write(lcPort.str(), strlen(lcPort.str()));
- lcPort.freeze(false);
- logFileNameRcv.freeze(false);
- rcvCount = 0;
- }
- out_log = new ofstream(logFileNameSnd.str(), ios::app);
- if (!out_log)
- {
- cerr << "Cannot open file "
- << logFileNameSnd.str() << endl;
- logFileNameSnd.freeze(false);
- logFlag = false;
- }
- else
- {
- if (! logFlag)
- logFlag = true;
- out_log->write ("UdpSndn", 7);
- logFileNameSnd.freeze(false);
- sndCount = 0;
- }
- }
- }
- void
- UdpStack::doServer ( int minPort,
- int maxPort ) // these are lcoal ports
- {
- /*
- cpLog (LOG_DEBUG_STACK, "UdpStack::doServer");
- cpLog (LOG_DEBUG_STACK, "minPort = %d, maxPort = %d", minPort, maxPort);
- */
- LockHelper helper(_lock);
- // this is a server
- if ( (minPort == -1) && (maxPort == -1) )
- {
- minPort = 1024;
- maxPort = 65534;
- }
- if ( maxPort == -1 )
- {
- maxPort = minPort;
- }
- // reset name now that the port range is defined
- strstream aName;
- aName << "-receiver-" << ":"
- << "[" << minPort
- << "-" << maxPort << "]"
- << char(0);
- setLclName( aName.str() );
- aName.freeze(false);
- // find a port to use
- int portOk = false;
- int err = 0;
- // here it assigns the port, the local port
- // & bind the addr(INADDR_ANY+port) to the socket
- for ( localPort = minPort; localPort <= maxPort; localPort++ )
- {
- (data->localAddr).sin_port = htons(localPort);
- cpLog(LOG_DEBUG_STACK, "Udp bind() fd = %d, port = %d(h_order), %d(n_order)",
- data->socketFd, localPort, (data->localAddr).sin_port);
- if ( bind( data->socketFd,
- (struct sockaddr*) &(data->localAddr),
- sizeof((data->localAddr)))
- != 0 )
- {
- err = errno;
- if ( err == EADDRINUSE )
- {
- continue; // this port is in use - try the next one
- }
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName()
- << ">::UdpStack error during socket bind: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- throw UdpStackException(errMsg.str());
- errMsg.freeze(false);
- assert(0);
- }
- else
- {
- portOk = true;
- break;
- }
- }
- // deal with errors
- if (!portOk)
- {
- // all ports are in use
- localPort = -1;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName()
- << ">::UdpStack all ports in range "
- << minPort << " to " << maxPort
- << " are in use.";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- throw UdpStackExceptionPortsInUse(errMsg.str());
- errMsg.freeze(false);
- assert(0);
- }
- // reset name now that the port is defined
- strstream aName2;
- aName2 << "-receiver-" << ":" << minPort << char(0);
- setLclName( aName2.str() );
- aName2.freeze(false);
- }
- void
- UdpStack::doClient ( const NetworkAddress* desHost,
- int desPort ) // This is the destination port
- {
- /*
- cpLog (LOG_DEBUG_STACK, "UdpStack::doClient");
- cpLog (LOG_DEBUG_STACK, "desHost = %s, desPort = %d",
- desHost->getIpName().c_str(), desPort);
- */
- // this is a client
- assert (desHost);
- // build a name
- char buf[256];
- strstream aName(buf, 256);
- aName << (desHost->getIpName()).c_str() << ":" << desPort << ends;
- setRmtName( aName.str() );
- (data->remoteAddr).sin_addr.s_addr = desHost->getIp4Address();
- // set up the port data
- // this is the destination port,
- // The addr above plus the port is the only addr from which
- // the data will received
- remotePort = desPort;
- if ( (remotePort == 0) || (remotePort > 65000))
- {
- // error -- this is an unknown port
- throw UdpStackExceptionBadPort("remote port out of range");
- }
- (data->remoteAddr).sin_port = htons(remotePort);
- }
- void
- UdpStack::connectPorts()
- {
- if ((mode == recvonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
- return ;
- }
- int result;
- // conenct to server
- if ((result = connect(data->socketFd,
- (struct sockaddr*) & (data->remoteAddr),
- sizeof(data->remoteAddr))) != 0)
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
- << ">::UdpStack error during socket connect: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- throw UdpStackException(errMsg.str());
- errMsg.freeze(false);
- assert(0);
- }
- // cout << result;
- }
- // After testing, this method currently is not working on Linux and Sun4
- // possibily because the system are not supporting it.
- // Now the work around is to call connect twice.
- void
- UdpStack::disconnectPorts()
- {
- if ((mode == recvonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
- return ;
- }
- struct sockaddr dummyAddr;
- memset((char*) &dummyAddr, 0, sizeof(dummyAddr));
- dummyAddr.sa_family = AF_INET;
- int result;
- // cerr << "test1 " << endl;
- if ((result = connect(data->socketFd,
- (struct sockaddr*) & dummyAddr,
- sizeof(dummyAddr))) != 0)
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
- << ">::UdpStack error during socket connect: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- // cerr << result;
- dummyAddr.sa_family = AF_UNSPEC;
- if ((result = connect(data->socketFd,
- (struct sockaddr*) & dummyAddr,
- sizeof(dummyAddr))) != 0)
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
- << ">::UdpStack error during socket connect: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- }
- /// set the local ports
- /// The first time change from inactive to recvonly/sendrecv or
- /// change the local ports, this method needs to be called.
- void
- UdpStack::setLocal (const int minPort, int maxPort )
- {
- cpLog (LOG_DEBUG_STACK, "UdpStack::setLocal");
- cpLog (LOG_DEBUG_STACK, "minPort = %d, maxPort = %d", minPort, maxPort);
- if ((mode == sendonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The UdpStack is sendonly or inactive.");
- return ;
- }
- // To reopen a new socket, since after sendto(), bind() will fail
- // if (localPort != -1)
- {
- int newFd;
- newFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- #ifndef WIN32
- if ( close (data->socketFd) != 0 )
- #else
- if ( closesocket(data->socketFd) )
- #endif
- {
- cpLog(LOG_ERR, "close socketFd error!");
- }
- data->socketFd = newFd;
- if ( data->socketFd < 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" /* << getLclName() */
- << ">::UdpStack error during socket creation: ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- throw UdpStackException(errMsg.str());
- errMsg.freeze(false);
- assert(0);
- }
- #ifdef __linux__
- int buf1 = 1;
- int len1 = sizeof(buf1);
- struct protoent * protoent;
- protoent = getprotobyname("icmp");
- if (!protoent)
- {
- fprintf(stderr, "Cannot get icmp protocoln");
- }
- else
- {
- if (setsockopt(data->socketFd, protoent->p_proto, SO_BSDCOMPAT,
- (char*)&buf1, len1)
- == -1)
- {
- fprintf(stderr, "setsockopt error SO_BSDCOMPAT :%s",
- strerror(errno));
- }
- }
- #endif
- }
- doServer(minPort, maxPort);
- }
- /// set the default destination
- void
- UdpStack::setDestination ( const NetworkAddress* host )
- {
- if ((mode == recvonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
- return ;
- }
- doClient(host, host->getPort());
- }
- void
- UdpStack::setDestination ( const char* host, int port )
- {
- assert(host);
- NetworkAddress netAddress;
- if ( host )
- {
- string rHostName = host;
- netAddress.setPort(port);
- netAddress.setHostName(rHostName);
- }
- setDestination (&netAddress);
- }
- /// need to delete the ne wobject after the object is used
- NetworkAddress *
- UdpStack::getDestinationHost () const
- {
- NetworkAddress* desHost = new NetworkAddress() ;
- desHost->setPort(remotePort);
- char buf[256];
- if(inet_ntop(AF_INET, &((data->remoteAddr).sin_addr), buf, 256) == 0)
- {
- cpLog(LOG_ERR, "Failed to get the host name" );
- }
- desHost->setHostName(buf);
- return desHost;
- }
- int
- UdpStack::getSocketFD ()
- {
- assert(data);
- return data->socketFd;
- }
- void
- UdpStack::addToFdSet ( fd_set* set )
- {
- assert(set);
- FD_SET(data->socketFd, set);
- }
- int
- UdpStack::getMaxFD ( int prevMax )
- {
- return ( getSocketFD() > prevMax ) ? getSocketFD() : prevMax;
- }
- bool
- UdpStack::checkIfSet ( fd_set* set )
- {
- assert(set);
- #ifndef WIN32
- return static_cast < bool > FD_ISSET(data->socketFd, set);
- #else
- return static_cast < bool > (FD_ISSET(data->socketFd, set));
- #endif
- }
- int
- UdpStack::receive ( const char* buf, const int bufSize )
- {
- if ((mode == sendonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The stack is not capable to receive. ");
- return -1;
- }
- int len = recv( data->socketFd,
- (char *)buf, bufSize,
- 0 /*flags */);
- if ( len <= 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName()
- << ">::receive error : ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- // cpLog(LOG_DEBUG_STACK, "UdpStack::receive pkt len=0");
- }
- else
- {
- numBytesReceived += len;
- numPacketsReceived += 1;
- }
- if ( (logFlag) && (len > 0) )
- {
- strstream lenln1;
- lenln1 << ++rcvCount << " " << len << "n" << char(0);
- in_log->write(lenln1.str(), strlen(lenln1.str()));
- in_log->write(buf, len);
- in_log->write(separator, 6);
- lenln1.freeze(false);
- }
- return len;
- }
- int
- UdpStack::receiveFrom ( const char* buffer,
- const int bufSize,
- NetworkAddress* sender ) // returns bytes read
- {
- if ((mode == sendonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The stack is not capable to receive. ");
- return -1;
- }
- string hostname;
- struct sockaddr_in xSrc;
- unsigned int lenSrc = sizeof(xSrc);
- int len = recvfrom( data->socketFd,
- (char *)buffer,
- bufSize,
- 0 /*flags */ ,
- (struct sockaddr*) & xSrc,
- (socklen_t *) & lenSrc);
- if ( len <= 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getLclName()
- << ">::receive error : ";
- errMsg << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- }
- else
- {
- char hbuf[256];
- if(inet_ntop(AF_INET, &(xSrc.sin_addr), hbuf, 256) == 0)
- {
- cpLog(LOG_ERR, "failed to get the host name");
- };
- hostname = hbuf;
- sender->setPort(ntohs(xSrc.sin_port));
- sender->setHostName(hostname);
- // cout << "UDP receive from" << sender;
- numBytesReceived += len;
- numPacketsReceived += 1;
- }
- if ( (logFlag) && (len > 0) )
- {
- strstream lenln2;
- lenln2 << ++rcvCount << " " << len << "n" << char(0);
- in_log->write(lenln2.str(), strlen(lenln2.str()));
- in_log->write(buffer, len);
- in_log->write(separator, 6);
- lenln2.freeze(false);
- }
- return len;
- }
- int
- UdpStack::receiveTimeout ( const char* buffer,
- const int bufSize,
- NetworkAddress* sender,
- int sec,
- int usec)
- {
- #ifndef __vxworks
- timeval tv;
- fd_set rset;
- int fd = getSocketFD();
- #ifndef WIN32
- int flags, retVal;
- // set socket to non-blocking then return it back after receive call
- if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
- return -1;
- flags |= O_NONBLOCK;
- if (fcntl(fd, F_SETFL, flags) < 0)
- return -1;
- #else
- int retVal;
- unsigned long non_blocking = 1;
- if (ioctlsocket(fd, FIONBIO, &non_blocking))
- return -1;
- #endif
- // select will return upon timeout, error or received message
- FD_ZERO(&rset);
- FD_SET(fd, &rset);
- tv.tv_sec = sec;
- tv.tv_usec = usec;
- retVal = select(fd + 1, &rset, NULL, NULL, &tv);
- // we don't care about no stinking error
- if (retVal <= 0)
- return retVal;
- retVal = receiveFrom( buffer,
- bufSize,
- sender);
- #ifndef WIN32
- flags &= ~O_NONBLOCK;
- if (fcntl (fd, F_SETFL, flags) < 0)
- return -1;
- #else
- non_blocking = 0;
- if (ioctlsocket(fd, FIONBIO, &non_blocking) != 0)
- return -1;
- #endif
- return retVal;
- #else
- cpLog(LOG_ERR, "UdpStack::receiveTimeout * not defined in vxworks *n");
- return -1;
- #endif
- }
- // uses send() which is better to get ICMP msg back
- // function returns a 0 normally
- void
- UdpStack::transmit ( const char* buf, const int length )
- {
- if ((mode == recvonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The stack is not capable to transmit. ");
- return ;
- }
- assert(buf);
- assert(length > 0);
- if ( packetLossProbability > 0.0 )
- {
- static bool randInit = false;
- if (!randInit)
- {
- randInit = true;
- timeval tv;
- gettimeofday(&tv, NULL);
- long seed = tv.tv_sec + tv.tv_usec;
- srandom(seed);
- }
- double numerator( random() & 0x7FFFFFFF );
- double denominator( 0x7FFFFFFF );
- double prob = numerator / denominator;
- if ( prob < packetLossProbability )
- {
- // ok - just drop this packet
- return ;
- }
- }
- int count = send( data->socketFd,
- (char *)buf, length,
- 0 /* flags */ );
- if ( count < 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getRmtName() << ">::transmit ";
- switch (err)
- {
- case ECONNREFUSED:
- {
- // This is the most common error - you get it if the host
- // does not exist or is nor running a program to recevice
- // the packets. This is what you get with the other side
- // crashes.
- errMsg << "Connection refused by destination host";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- #if 0
- throw UdpStackExceptionConectionRefused(errMsg.str());
- #endif
- }
- break;
- case EHOSTDOWN:
- {
- errMsg << "destination host is down";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- }
- break;
- case EHOSTUNREACH:
- {
- errMsg << "no route to to destination host";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- }
- break;
- default:
- {
- errMsg << ": " << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- }
- }
-
- cpLog (LOG_ERR, "UDP send() error: ");
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- else if ( count != length )
- {
- /*
- int err = errno;
- */
- strstream errMsg;
- errMsg << "UdpStack<" << getRmtName()
- << ">:transmit error is send: "
- << "Asked to transmit " << length
- << " bytes but only sent " << count ;
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- else
- {
- numBytesTransmitted += count;
- numPacketsTransmitted += 1;
- }
- if ( (logFlag) && (count > 0) )
- {
- strstream lenln3;
- lenln3 << ++sndCount << " " << count << char(0);
- out_log->write(lenln3.str(), strlen(lenln3.str()));
- lenln3.freeze(false);
- strstream rAddress1;
- rAddress1 << " " << getRmtName() << "n" << char(0);
- out_log->write(rAddress1.str(), strlen(rAddress1.str()));
- rAddress1.freeze(false);
- out_log->write(buf, count);
- out_log->write(separator, 6);
- }
- }
- int
- UdpStack::transmitTo ( const char* buffer,
- const int length,
- const NetworkAddress* dest )
- {
- if ((mode == recvonly) || (mode == inactive))
- {
- cpLog(LOG_ERR, "The stack is not capable to transmit. ");
- return 0;
- }
- assert(buffer);
- assert(length > 0);
- assert(dest);
- setDestination(dest);
- LockHelper helper(_lock);
- struct sockaddr_in xDest;
- xDest.sin_family = AF_INET;
- xDest.sin_port = htons(dest->getPort());
- xDest.sin_addr.s_addr = dest->getIp4Address();
- int count = sendto( data->socketFd,
- (char*)buffer,
- length,
- 0 , // flags
- (struct sockaddr*) & xDest,
- sizeof(sockaddr_in));
- if ( count < 0 )
- {
- int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getRmtName() << ">::transmitTo ";
- switch (err)
- {
- case ECONNREFUSED:
- {
- // This is the most common error - you get it if the host
- // does not exist or is nor running a program to recevice
- // the packets. This is what you get with the other side
- // crashes.
- errMsg << "Connection refused by destination host";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- return 1;
- #if 0
- throw UdpStackExceptionConectionRefused(errMsg.str());
- #endif
- }
- break;
- case EHOSTDOWN:
- {
- errMsg << "destination host is down";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- return 2;
- }
- break;
- case EHOSTUNREACH:
- {
- errMsg << "no route to to destination host";
- errMsg << char(0);
- clog << errMsg.str() << endl;
- return 3;
- }
- break;
- default:
- {
- errMsg << ": " << strerror(err);
- errMsg << char(0);
- clog << errMsg.str() << endl;
- }
- }
- cpLog (LOG_ERR, "UDP sendto() error: ");
- // cerr << "UDP sendto error: " << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- else if ( count != length )
- {
- // int err = errno;
- strstream errMsg;
- errMsg << "UdpStack<" << getRmtName()
- << ">:transmit error is send: "
- << "Asked to transmit " << length
- << " bytes but only sent " << count ;
- errMsg << char(0);
- clog << errMsg.str() << endl;
- errMsg.freeze(false);
- #if 0
- throw UdpStackException(errMsg.str());
- assert(0);
- #endif
- }
- else
- {
- numBytesTransmitted += count;
- numPacketsTransmitted += 1;
- }
- if ( (logFlag) && (count > 0) )
- {
- strstream lenln4;
- lenln4 << ++sndCount << " " << count << char(0);
- out_log->write(lenln4.str(), strlen(lenln4.str()));
- lenln4.freeze(false);
- strstream rAddress2;
- rAddress2 << " " << getRmtName() << "n" << char(0);
- out_log->write(rAddress2.str(), strlen(rAddress2.str()));
- rAddress2.freeze(false);
- out_log->write(buffer, count);
- out_log->write(separator, 6);
- }
- return 0;
- }
- ///
- void
- UdpStack::joinMulticastGroup ( NetworkAddress group,
- NetworkAddress* iface,
- int ifaceInexe )
- {
- #ifndef WIN32
- #if defined(__linux__)
- struct ip_mreqn mreqn;
- mreqn.imr_multiaddr.s_addr = (group.getIp4Address());
- mreqn.imr_address.s_addr = (iface->getIp4Address());
- mreqn.imr_ifindex = ifaceInexe;
- int ret;
- ret = setsockopt (getSocketFD(),
- IPPROTO_IP,
- IP_ADD_MEMBERSHIP,
- (char*) & mreqn,
- sizeof(struct ip_mreqn));
- // cerr << "setsockopt ret = " << ret << endl;
- // cerr << "setsockopt errno = " << errno << endl;
- #else
- struct ip_mreq mreq;
- mreq.imr_multiaddr.s_addr = (group.getIp4Address());
- mreq.imr_interface.s_addr = (iface->getIp4Address());
- // mreq.imr_ifindex = ifaceInexe;
- int ret;
- ret = setsockopt (getSocketFD(),
- IPPROTO_IP,
- IP_ADD_MEMBERSHIP,
- (char*) & mreq,
- sizeof(struct ip_mreq));
- #endif
- #endif // !WIN32
- }
- ///
- void
- UdpStack::leaveMulticastGroup( NetworkAddress group,
- NetworkAddress* iface,
- int ifaceInexe )
- {
- #ifndef WIN32
- #if defined(__linux__)
- struct ip_mreqn mreqn;
- mreqn.imr_multiaddr.s_addr = (group.getIp4Address());
- mreqn.imr_address.s_addr = (iface->getIp4Address());
- mreqn.imr_ifindex = ifaceInexe;
- setsockopt (getSocketFD(),
- IPPROTO_IP,
- IP_DROP_MEMBERSHIP,
- (char*)&mreqn,
- sizeof(struct ip_mreqn));
- #else
- struct ip_mreq mreq;
- mreq.imr_multiaddr.s_addr = (group.getIp4Address());
- mreq.imr_interface.s_addr = (iface->getIp4Address());
- // mreq.imr_ifindex = ifaceInexe;
- setsockopt (getSocketFD(),
- IPPROTO_IP,
- IP_DROP_MEMBERSHIP,
- (char*)&mreq,
- sizeof(struct ip_mreq));
- #endif
- #endif // !WIN32
- }
- UdpStack::~UdpStack()
- {
- assert(data);
- if (logFlag)
- {
- in_log->close();
- out_log->close();
- delete in_log;
- delete out_log;
- }
- #ifndef WIN32
- close (data->socketFd);
- #else
- closesocket(data->socketFd);
- #endif
- delete data;
- data = NULL;
- }
- int
- UdpStack::getBytesReceived ()
- {
- return numBytesReceived;
- }
- int
- UdpStack::getPacketsReceived ()
- {
- return numPacketsReceived;
- }
- int
- UdpStack::getBytesTransmitted ()
- {
- return numBytesTransmitted;
- }
- int
- UdpStack::getPacketsTransmitted ()
- {
- return numPacketsTransmitted;
- }