UdpStack.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:34k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

C/C++

  1. /* ====================================================================
  2.  * The Vovida Software License, Version 1.0 
  3.  * 
  4.  * Copyright (c) 2000 Vovida Networks, Inc.  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.  * 
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in
  15.  *    the documentation and/or other materials provided with the
  16.  *    distribution.
  17.  * 
  18.  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  19.  *    and "Vovida Open Communication Application Library (VOCAL)" must
  20.  *    not be used to endorse or promote products derived from this
  21.  *    software without prior written permission. For written
  22.  *    permission, please contact vocal@vovida.org.
  23.  *
  24.  * 4. Products derived from this software may not be called "VOCAL", nor
  25.  *    may "VOCAL" appear in their name, without prior written
  26.  *    permission of Vovida Networks, Inc.
  27.  * 
  28.  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  29.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
  31.  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
  32.  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
  33.  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
  34.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  35.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  36.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  37.  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  38.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  39.  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  40.  * DAMAGE.
  41.  * 
  42.  * ====================================================================
  43.  * 
  44.  * This software consists of voluntary contributions made by Vovida
  45.  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  46.  * Inc.  For more information on Vovida Networks, Inc., please see
  47.  * <http://www.vovida.org/>.
  48.  *
  49.  */
  50. static const char* const UdpStack_cxx_Version =
  51.     "$Id: UdpStack.cxx,v 1.3 2001/06/27 01:43:47 bko Exp $";
  52. /* TODO List
  53.  * - add sendTo function to allow you to specifiy different destinations
  54.  * - add recvFrom function that tell you who the packet came from 
  55.  * - add non blockinge version fo send and receive
  56.  * - derive "ReliableUDP" stack that takes care of retransmissions
  57.  * - look into using MSG_ERRQUEUE to check for ICMP errors
  58.  * - check portability 
  59.  * - support IP6 
  60.  * - stress test 
  61.  */
  62. #include <fstream>
  63. #include <assert.h>
  64. #include <string.h> // for memset
  65. #include <errno.h>
  66. #include <iostream>
  67. #include <stdio.h>
  68. #include <netdb.h>
  69. #if defined(__FreeBSD__)
  70. #include <sys/types.h>
  71. #endif
  72. #include <netinet/in.h> // for struct sockaddr_in
  73. #include <stdlib.h>
  74. #include <strstream>
  75. #include <sys/types.h>
  76. #include <arpa/inet.h>
  77. #include <sys/socket.h>
  78. #include "VTime.hxx"
  79. #include <unistd.h>
  80. #ifndef __vxworks
  81. #include <fcntl.h>
  82. #endif
  83. #include "vovida-endian.h"
  84. #if defined(__svr4__)
  85. #include <xil/xil.h>
  86. #if (XIL_API_MINOR_VERSION - 0 == 3)
  87. typedef int socklen_t;
  88. #endif
  89. #endif
  90. #include "UdpStack.hxx"
  91. #include "cpLog.h"
  92. #include "vsock.hxx"
  93. #include "LockHelper.hxx"
  94. static VMutex G_lock;
  95. // this class hold stuff that is likely to be a problem to port
  96. class UdpStackPrivateData
  97. {
  98.     public:
  99.         /// File descriptor of socket
  100.         int socketFd;
  101.         /// Address of local computer that will receive or send the packets
  102.         struct sockaddr_in localAddr;
  103.         /// Address of remote computer that local computer receive from
  104.         /// or send to the packets
  105.         /// This address is set when doClient is called.
  106.         /// And later when setDestination() is called, this address will be the one
  107.         /// connect to. But disconnectPorts() won't remove this address.
  108.         struct sockaddr_in remoteAddr;
  109. };
  110. static const char separator[7] = "n****n";
  111. UdpStack::UdpStack ( const NetworkAddress* desHost
  112.                      /* null if this is the server */ ,
  113.                      int minPort,
  114.                      int maxPort,
  115.                      UdpMode udpMode,
  116.                      bool log_flag,
  117.                      bool isMulticast)
  118.         : localPort( -1),
  119.         remotePort( -1),
  120.         packetLossProbability( float(0.0) ),
  121.         numBytesReceived (0),
  122.         numPacketsReceived (0),
  123.         numBytesTransmitted (0),
  124.         numPacketsTransmitted (0),
  125.         mode (sendrecv),
  126.         logFlag (log_flag)
  127. {
  128.     data = new UdpStackPrivateData;
  129.     assert(data);
  130.     mode = udpMode;
  131.     // open a socket
  132.     data->socketFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  133.     cpLog (LOG_DEBUG_STACK, "UdpStack socketFd = %d", data->socketFd);
  134.     if ( data->socketFd < 0 )
  135.     {
  136.         int err = errno;
  137.         strstream errMsg;
  138.         errMsg << "UdpStack<" /* << getLclName() */
  139.         << ">::UdpStack error during socket creation: ";
  140.         errMsg << strerror(err);
  141.         errMsg << char(0);
  142.         clog << errMsg.str() << endl;
  143.         throw UdpStackException(errMsg.str());
  144.         errMsg.freeze(false);
  145.         assert(0);
  146.     }
  147.     int buf1 = 1;
  148.     int len1 = sizeof(buf1);
  149. /*
  150.     int rcvbuf = 0;
  151.     int rcvbufnew = 240 * 1024;
  152.     int rcvbufnewlen = sizeof(rcvbufnew);
  153.     int sndbuf = 0;
  154.     unsigned int rcvbuflen = 1;
  155.     unsigned int sndbuflen = 1;
  156. */
  157. #ifdef __linux__
  158.     struct protoent * protoent;
  159.     protoent = getprotobyname("icmp");
  160.     if (!protoent)
  161.     {
  162.         fprintf(stderr, "Cannot get icmp protocoln");
  163.     }
  164.     else
  165.     {
  166.         if (setsockopt(data->socketFd, protoent->p_proto, SO_BSDCOMPAT,
  167.                        (char*)&buf1, len1)
  168.                 == -1)
  169.         {
  170.             fprintf(stderr, "setsockopt error SO_BSDCOMPAT :%sn",
  171.                     strerror(errno));
  172.         }
  173. /*
  174.         if (setsockopt(data->socketFd, SOL_SOCKET, SO_RCVBUF,
  175.                        (int *)&rcvbufnew, rcvbufnewlen)
  176.                 == -1)
  177.         {
  178.             fprintf(stderr, "setsockopt error SO_RCVBUF :%sn",
  179.                     strerror(errno));
  180.         }
  181.         if (getsockopt(data->socketFd, SOL_SOCKET, SO_RCVBUF, 
  182.                        (int*)&rcvbuf, &rcvbuflen) == -1)
  183.         {
  184.             fprintf(stderr, "getsockopt error SO_RCVBUF :%sn",
  185.                     strerror(errno));
  186.         }
  187.         else
  188.         {
  189.             cerr << "SO_RCVBUF = " << rcvbuf << " rcvbuflen = " << rcvbuflen << endl;
  190.         }
  191.         if (getsockopt(data->socketFd, SOL_SOCKET, SO_SNDBUF, 
  192.                        (int*)&sndbuf, &sndbuflen) == -1)
  193.         {
  194.             fprintf(stderr, "getsockopt error SO_SNDBUF :%sn",
  195.                     strerror(errno));
  196.         }
  197.         else
  198.         {
  199.             cerr << "SO_SNDBUF = " << sndbuf << " sndbuflen = " << sndbuflen << endl;
  200.         }
  201. */
  202.     }
  203. #endif
  204.     if (isMulticast)
  205.     {
  206.         // set option to get rid of the "Address already in use" error
  207.         if (setsockopt(data->socketFd, SOL_SOCKET, SO_REUSEADDR,
  208.                        (char*)&buf1, len1)
  209.                 == -1)
  210.         {
  211.             fprintf(stderr, "setsockopt error SO_REUSEADDR :%s",
  212.                     strerror(errno));
  213.         }
  214. #ifdef __FreeBSD__
  215.         if (setsockopt(data->socketFd, SOL_SOCKET, SO_REUSEPORT,
  216.                        (char*)&buf1, len1)
  217.                 == -1)
  218.         {
  219.             fprintf(stderr, "setsockopt error SO_REUSEPORT :%s",
  220.                     strerror(errno));
  221.         }
  222. #endif
  223.     }
  224.     // set up addresses
  225.     memset((char*) &(data->localAddr), 0, sizeof((data->localAddr)));
  226.     (data->localAddr).sin_family = AF_INET;
  227.     (data->localAddr).sin_addr.s_addr = htonl(INADDR_ANY);
  228.     memset((char*) &(data->remoteAddr), 0, sizeof((data->remoteAddr)));
  229.     (data->remoteAddr).sin_family = AF_INET;
  230.     (data->remoteAddr).sin_addr.s_addr = htonl(INADDR_ANY);
  231.     switch (mode)
  232.     {
  233.         case inactive :
  234.         {
  235.             cpLog(LOG_INFO, "Udp stack is inactive");
  236.             cpLog(LOG_ERR, "desHost is saved for future use.");
  237.             doClient(desHost, desHost->getPort());
  238.         }
  239.         break;
  240.         case sendonly :
  241.         {
  242.             if ( desHost )
  243.             {
  244.                 // set the remote address
  245.                 doClient(desHost, desHost->getPort());
  246.             }
  247.             else
  248.             {
  249.                 cpLog(LOG_INFO,
  250.                       "sendonly Udp stack, desHost is needed by using setDestination()");
  251.             }
  252.         }
  253.         break;
  254.         case recvonly :
  255.         {
  256.             if ( desHost )
  257.             {
  258.                 cpLog(LOG_ERR,
  259.                       "recvonly Udp stack, desHost is saved for future use.");
  260.                 doClient(desHost, desHost->getPort());
  261.             }
  262.             else
  263.             {
  264.                 // only receive, do bind socket to local port
  265.                 doServer(minPort, maxPort);
  266.             }
  267.         }
  268.         break;
  269.         case sendrecv :
  270.         {
  271.             if ( desHost )
  272.             {
  273.                 // receive and send,
  274.                 // bind the socket to local port and set the remote address
  275.                 doServer(minPort, maxPort);
  276.                 doClient(desHost, desHost->getPort());
  277.             }
  278.             else
  279.             {
  280.                 // only receive, do bind socket to local port
  281.                 doServer(minPort, maxPort);
  282.                 cpLog(LOG_INFO,
  283.                       "sendrecv Udp stack, desHost is needed by using setDestination()");
  284.             }
  285.         }
  286.         break;
  287.         default :
  288.         cpLog(LOG_ERR, "undefined mode for udp stack");
  289.         break;
  290.     }
  291.     //    logFlag = true;
  292.     strstream logFileNameRcv;
  293.     strstream logFileNameSnd;
  294.     logFileNameRcv << "udpRcv" << "-"
  295.     << data->socketFd << "-"
  296.     << localPort << ".log"
  297.     << char(0);
  298.     logFileNameSnd << "udpSnd" << "-"
  299.     << data->socketFd << "-"
  300.     << localPort << ".log"
  301.     << char(0);
  302.     if (logFlag)
  303.     {
  304.         in_log = new ofstream(logFileNameRcv.str(), ios::app);
  305.         if (!in_log)
  306.         {
  307.             cerr << "Cannot open file "
  308.             << logFileNameRcv.str() << endl;
  309.             logFileNameRcv.freeze(false);
  310.             logFlag = false;
  311.         }
  312.         else
  313.         {
  314.             in_log->write ("UdpRcvn", 7);
  315.             strstream lcPort;
  316.             lcPort << "localPort: " << localPort << "n" << char(0);
  317.             in_log->write(lcPort.str(), strlen(lcPort.str()));
  318.             lcPort.freeze(false);
  319.             logFileNameRcv.freeze(false);
  320.             rcvCount = 0;
  321.         }
  322.         out_log = new ofstream(logFileNameSnd.str(), ios::app);
  323.         if (!out_log)
  324.         {
  325.             cerr << "Cannot open file "
  326.             << logFileNameSnd.str() << endl;
  327.             logFileNameSnd.freeze(false);
  328.             logFlag = false;
  329.         }
  330.         else
  331.         {
  332.             if (! logFlag)
  333.                 logFlag = true;
  334.             out_log->write ("UdpSndn", 7);
  335.             logFileNameSnd.freeze(false);
  336.             sndCount = 0;
  337.         }
  338.     }
  339. }
  340. void
  341. UdpStack::doServer ( int minPort,
  342.                      int maxPort )  // these are lcoal ports
  343. {
  344.     /*
  345.         cpLog (LOG_DEBUG_STACK, "UdpStack::doServer");
  346.         cpLog (LOG_DEBUG_STACK, "minPort = %d, maxPort = %d", minPort, maxPort);
  347.     */
  348.     LockHelper helper(_lock);
  349.     // this is a server
  350.     if ( (minPort == -1) && (maxPort == -1) )
  351.     {
  352.         minPort = 1024;
  353.         maxPort = 65534;
  354.     }
  355.     if ( maxPort == -1 )
  356.     {
  357.         maxPort = minPort;
  358.     }
  359.     // reset name now that the port range is defined
  360.     strstream aName;
  361.     aName << "-receiver-" << ":"
  362.     << "[" << minPort
  363.     << "-" << maxPort << "]"
  364.     << char(0);
  365.     setLclName( aName.str() );
  366.     aName.freeze(false);
  367.     // find a port to use
  368.     int portOk = false;
  369.     int err = 0;
  370.     // here it assigns the port, the local port
  371.     // & bind the addr(INADDR_ANY+port) to the socket
  372.     for ( localPort = minPort; localPort <= maxPort; localPort++ )
  373.     {
  374.         (data->localAddr).sin_port = htons(localPort);
  375.         cpLog(LOG_DEBUG_STACK, "Udp bind() fd = %d, port = %d(h_order), %d(n_order)",
  376.               data->socketFd, localPort, (data->localAddr).sin_port);
  377.         if ( bind( data->socketFd,
  378.                    (struct sockaddr*) &(data->localAddr),
  379.                    sizeof((data->localAddr)))
  380.                 != 0 )
  381.         {
  382.             err = errno;
  383.             if ( err == EADDRINUSE )
  384.             {
  385.                 continue;  // this port is in use - try the next one
  386.             }
  387.             int err = errno;
  388.             strstream errMsg;
  389.             errMsg << "UdpStack<" << getLclName()
  390.             << ">::UdpStack error during socket bind: ";
  391.             errMsg << strerror(err);
  392.             errMsg << char(0);
  393.             clog << errMsg.str() << endl;
  394.             throw UdpStackException(errMsg.str());
  395.             errMsg.freeze(false);
  396.             assert(0);
  397.         }
  398.         else
  399.         {
  400.             portOk = true;
  401.             break;
  402.         }
  403.     }
  404.     // deal with errors
  405.     if (!portOk)
  406.     {
  407.         // all ports are in use
  408.         localPort = -1;
  409.         strstream errMsg;
  410.         errMsg << "UdpStack<" << getLclName()
  411.         << ">::UdpStack all ports in range "
  412.         << minPort << " to " << maxPort
  413.         << " are in use.";
  414.         errMsg << char(0);
  415.         clog << errMsg.str() << endl;
  416.         throw UdpStackExceptionPortsInUse(errMsg.str());
  417.         errMsg.freeze(false);
  418.         assert(0);
  419.     }
  420.     // reset name now that the port is defined
  421.     strstream aName2;
  422.     aName2 << "-receiver-" << ":" << minPort << char(0);
  423.     setLclName( aName2.str() );
  424.     aName2.freeze(false);
  425. }
  426. void
  427. UdpStack::doClient ( const NetworkAddress* desHost,
  428.                      int desPort ) // This is the destination port
  429. {
  430.     /*
  431.         cpLog (LOG_DEBUG_STACK, "UdpStack::doClient");
  432.         cpLog (LOG_DEBUG_STACK, "desHost = %s, desPort = %d", 
  433.                desHost->getIpName().c_str(), desPort);
  434.     */
  435.     // this is a client
  436.     assert (desHost);
  437.     // build a name
  438.     char buf[256];
  439.     strstream aName(buf, 256);
  440.     aName << (desHost->getIpName()).c_str() << ":" << desPort << ends;
  441.     setRmtName( aName.str() );
  442.     (data->remoteAddr).sin_addr.s_addr = desHost->getIp4Address();
  443.     // set up the port data
  444.     // this is the destination port,
  445.     // The addr above plus the port is the only addr from which
  446.     // the data will received
  447.     remotePort = desPort;
  448.     if ( (remotePort == 0) || (remotePort > 65000))
  449.     {
  450.         // error -- this is an unknown port
  451.         throw UdpStackExceptionBadPort("remote port out of range");
  452.     }
  453.     (data->remoteAddr).sin_port = htons(remotePort);
  454. }
  455. void
  456. UdpStack::connectPorts()
  457. {
  458.     if ((mode == recvonly) || (mode == inactive))
  459.     {
  460.         cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
  461.         return ;
  462.     }
  463.     int result;
  464.     // conenct to server
  465.     if ((result = connect(data->socketFd,
  466.                           (struct sockaddr*) & (data->remoteAddr),
  467.                           sizeof(data->remoteAddr))) != 0)
  468.     {
  469.         int err = errno;
  470.         strstream errMsg;
  471.         errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
  472.         << ">::UdpStack error during socket connect: ";
  473.         errMsg << strerror(err);
  474.         errMsg << char(0);
  475.         clog << errMsg.str() << endl;
  476.         throw UdpStackException(errMsg.str());
  477.         errMsg.freeze(false);
  478.         assert(0);
  479.     }
  480.     //    cout << result;
  481. }
  482. // After testing, this method currently is not working on Linux and Sun4
  483. // possibily because the system are not supporting it.
  484. // Now the work around is to call connect twice.
  485. void
  486. UdpStack::disconnectPorts()
  487. {
  488.     if ((mode == recvonly) || (mode == inactive))
  489.     {
  490.         cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
  491.         return ;
  492.     }
  493.     struct sockaddr dummyAddr;
  494.     memset((char*) &dummyAddr, 0, sizeof(dummyAddr));
  495.     dummyAddr.sa_family = AF_INET;
  496.     int result;
  497.     //    cerr << "test1 " << endl;
  498.     if ((result = connect(data->socketFd,
  499.                           (struct sockaddr*) & dummyAddr,
  500.                           sizeof(dummyAddr))) != 0)
  501.     {
  502.         int err = errno;
  503.         strstream errMsg;
  504.         errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
  505.         << ">::UdpStack error during socket connect: ";
  506.         errMsg << strerror(err);
  507.         errMsg << char(0);
  508.         clog << errMsg.str() << endl;
  509.         errMsg.freeze(false);
  510. #if 0
  511.         throw UdpStackException(errMsg.str());
  512.         assert(0);
  513. #endif
  514.     }
  515.     //    cerr << result;
  516.     dummyAddr.sa_family = AF_UNSPEC;
  517.     if ((result = connect(data->socketFd,
  518.                           (struct sockaddr*) & dummyAddr,
  519.                           sizeof(dummyAddr))) != 0)
  520.     {
  521.         int err = errno;
  522.         strstream errMsg;
  523.         errMsg << "UdpStack<" << getLclName() << " " << getRmtName()
  524.         << ">::UdpStack error during socket connect: ";
  525.         errMsg << strerror(err);
  526.         errMsg << char(0);
  527.         clog << errMsg.str() << endl;
  528.         errMsg.freeze(false);
  529. #if 0
  530.         throw UdpStackException(errMsg.str());
  531.         assert(0);
  532. #endif
  533.     }
  534. }
  535. /// set the local ports
  536. /// The first time change from inactive to recvonly/sendrecv or
  537. /// change the local ports, this method needs to be called.
  538. void
  539. UdpStack::setLocal (const int minPort, int maxPort )
  540. {
  541.     cpLog (LOG_DEBUG_STACK, "UdpStack::setLocal");
  542.     cpLog (LOG_DEBUG_STACK, "minPort = %d, maxPort = %d", minPort, maxPort);
  543.     if ((mode == sendonly) || (mode == inactive))
  544.     {
  545.         cpLog(LOG_ERR, "The UdpStack is sendonly or inactive.");
  546.         return ;
  547.     }
  548.     // To reopen a new socket, since after sendto(), bind() will fail
  549.     //    if (localPort != -1)
  550.     {
  551.         int newFd;
  552.         newFd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
  553. #ifndef WIN32
  554.         if ( close (data->socketFd) != 0 )
  555. #else
  556. if ( closesocket(data->socketFd) )
  557. #endif
  558. {
  559.             cpLog(LOG_ERR, "close socketFd error!");
  560. }
  561.         data->socketFd = newFd;
  562.         if ( data->socketFd < 0 )
  563.         {
  564.             int err = errno;
  565.             strstream errMsg;
  566.             errMsg << "UdpStack<" /* << getLclName() */
  567.             << ">::UdpStack error during socket creation: ";
  568.             errMsg << strerror(err);
  569.             errMsg << char(0);
  570.             clog << errMsg.str() << endl;
  571.             throw UdpStackException(errMsg.str());
  572.             errMsg.freeze(false);
  573.             assert(0);
  574.         }
  575. #ifdef __linux__
  576.         int buf1 = 1;
  577.         int len1 = sizeof(buf1);
  578.         struct protoent * protoent;
  579.         protoent = getprotobyname("icmp");
  580.         if (!protoent)
  581.         {
  582.             fprintf(stderr, "Cannot get icmp protocoln");
  583.         }
  584.         else
  585.         {
  586.             if (setsockopt(data->socketFd, protoent->p_proto, SO_BSDCOMPAT,
  587.                            (char*)&buf1, len1)
  588.                     == -1)
  589.             {
  590.                 fprintf(stderr, "setsockopt error SO_BSDCOMPAT :%s",
  591.                         strerror(errno));
  592.             }
  593.         }
  594. #endif
  595.     }
  596.     doServer(minPort, maxPort);
  597. }
  598. /// set the default destination
  599. void
  600. UdpStack::setDestination ( const NetworkAddress* host )
  601. {
  602.     if ((mode == recvonly) || (mode == inactive))
  603.     {
  604.         cpLog(LOG_ERR, "The UdpStack is recvonly or inactive.");
  605.         return ;
  606.     }
  607.     doClient(host, host->getPort());
  608. }
  609. void
  610. UdpStack::setDestination ( const char* host, int port )
  611. {
  612.     assert(host);
  613.     NetworkAddress netAddress;
  614.     if ( host )
  615.     {
  616.         string rHostName = host;
  617.         netAddress.setPort(port);
  618.         netAddress.setHostName(rHostName);
  619.     }
  620.     setDestination (&netAddress);
  621. }
  622. /// need to delete the ne wobject after the object is used
  623. NetworkAddress *
  624. UdpStack::getDestinationHost () const
  625. {
  626.     NetworkAddress* desHost = new NetworkAddress() ;
  627.     desHost->setPort(remotePort);
  628.     char buf[256];
  629.     if(inet_ntop(AF_INET, &((data->remoteAddr).sin_addr), buf, 256) == 0)
  630.     {
  631.         cpLog(LOG_ERR, "Failed to get the host name" ); 
  632.     }
  633.     desHost->setHostName(buf);
  634.     return desHost;
  635. }
  636. int
  637. UdpStack::getSocketFD ()
  638. {
  639.     assert(data);
  640.     return data->socketFd;
  641. }
  642. void
  643. UdpStack::addToFdSet ( fd_set* set )
  644. {
  645.     assert(set);
  646.     FD_SET(data->socketFd, set);
  647. }
  648. int
  649. UdpStack::getMaxFD ( int prevMax )
  650. {
  651.     return ( getSocketFD() > prevMax ) ? getSocketFD() : prevMax;
  652. }
  653. bool
  654. UdpStack::checkIfSet ( fd_set* set )
  655. {
  656.     assert(set);
  657. #ifndef WIN32
  658.     return static_cast < bool > FD_ISSET(data->socketFd, set);
  659. #else
  660. return static_cast < bool > (FD_ISSET(data->socketFd, set));
  661. #endif
  662. }
  663. int
  664. UdpStack::receive ( const char* buf, const int bufSize )
  665. {
  666.     if ((mode == sendonly) || (mode == inactive))
  667.     {
  668.         cpLog(LOG_ERR, "The stack is not capable to receive. ");
  669.         return -1;
  670.     }
  671.     int len = recv( data->socketFd,
  672.                     (char *)buf, bufSize,
  673.                     0 /*flags */);
  674.     if ( len <= 0 )
  675.     {
  676.         int err = errno;
  677.         strstream errMsg;
  678.         errMsg << "UdpStack<" << getLclName()
  679.         << ">::receive error : ";
  680.         errMsg << strerror(err);
  681.         errMsg << char(0);
  682.         clog << errMsg.str() << endl;
  683.         errMsg.freeze(false);
  684. #if 0
  685.         throw UdpStackException(errMsg.str());
  686.         assert(0);
  687. #endif
  688.         //        cpLog(LOG_DEBUG_STACK, "UdpStack::receive pkt len=0");
  689.     }
  690.     else
  691.     {
  692.         numBytesReceived += len;
  693.         numPacketsReceived += 1;
  694.     }
  695.     if ( (logFlag) && (len > 0) )
  696.     {
  697.         strstream lenln1;
  698.         lenln1 << ++rcvCount << " " << len << "n" << char(0);
  699.         in_log->write(lenln1.str(), strlen(lenln1.str()));
  700.         in_log->write(buf, len);
  701.         in_log->write(separator, 6);
  702.         lenln1.freeze(false);
  703.     }
  704.     return len;
  705. }
  706. int
  707. UdpStack::receiveFrom ( const char* buffer,
  708.                         const int bufSize,
  709.                         NetworkAddress* sender ) // returns bytes read
  710. {
  711.     if ((mode == sendonly) || (mode == inactive))
  712.     {
  713.         cpLog(LOG_ERR, "The stack is not capable to receive. ");
  714.         return -1;
  715.     }
  716.     string hostname;
  717.     struct sockaddr_in xSrc;
  718.     unsigned int lenSrc = sizeof(xSrc);
  719.     int len = recvfrom( data->socketFd,
  720.                         (char *)buffer,
  721.                         bufSize,
  722.                         0 /*flags */ ,
  723.                         (struct sockaddr*) & xSrc,
  724.                         (socklen_t *) & lenSrc);
  725.     if ( len <= 0 )
  726.     {
  727.         int err = errno;
  728.         strstream errMsg;
  729.         errMsg << "UdpStack<" << getLclName()
  730.         << ">::receive error : ";
  731.         errMsg << strerror(err);
  732.         errMsg << char(0);
  733.         clog << errMsg.str() << endl;
  734.         errMsg.freeze(false);
  735.     }
  736.     else
  737.     {
  738.         char hbuf[256];
  739.         if(inet_ntop(AF_INET, &(xSrc.sin_addr), hbuf, 256) == 0)
  740.         {
  741.            cpLog(LOG_ERR, "failed to get the host name");
  742.         };
  743.         hostname = hbuf;
  744.         sender->setPort(ntohs(xSrc.sin_port));
  745.         sender->setHostName(hostname);
  746.         //  cout << "UDP receive from" << sender;
  747.         numBytesReceived += len;
  748.         numPacketsReceived += 1;
  749.     }
  750.     if ( (logFlag) && (len > 0) )
  751.     {
  752.         strstream lenln2;
  753.         lenln2 << ++rcvCount << " " << len << "n" << char(0);
  754.         in_log->write(lenln2.str(), strlen(lenln2.str()));
  755.         in_log->write(buffer, len);
  756.         in_log->write(separator, 6);
  757.         lenln2.freeze(false);
  758.     }
  759.     return len;
  760. }
  761. int
  762. UdpStack::receiveTimeout ( const char* buffer,
  763.                            const int bufSize,
  764.                            NetworkAddress* sender,
  765.                            int sec,
  766.                            int usec)
  767. {
  768. #ifndef __vxworks
  769.     timeval tv;
  770.     fd_set rset;
  771.     int fd = getSocketFD();
  772. #ifndef WIN32
  773.     int flags, retVal;
  774.     // set socket to non-blocking then return it back after receive call
  775.     if ((flags = fcntl(fd, F_GETFL, 0)) < 0)
  776.         return -1;
  777.     flags |= O_NONBLOCK;
  778.     if (fcntl(fd, F_SETFL, flags) < 0)
  779.         return -1;
  780. #else
  781.     int retVal;
  782.     unsigned long non_blocking = 1;
  783.     if (ioctlsocket(fd, FIONBIO, &non_blocking))
  784.         return -1;
  785. #endif
  786.     // select will return upon timeout, error or received message
  787.     FD_ZERO(&rset);
  788.     FD_SET(fd, &rset);
  789.     tv.tv_sec = sec;
  790.     tv.tv_usec = usec;
  791.     retVal = select(fd + 1, &rset, NULL, NULL, &tv);
  792.     // we don't care about no stinking error
  793.     if (retVal <= 0)
  794.         return retVal;
  795.     retVal = receiveFrom( buffer,
  796.                           bufSize,
  797.                           sender);
  798. #ifndef WIN32
  799.     flags &= ~O_NONBLOCK;
  800.     if (fcntl (fd, F_SETFL, flags) < 0)
  801.         return -1;
  802. #else
  803. non_blocking = 0;
  804. if (ioctlsocket(fd, FIONBIO, &non_blocking) != 0)
  805. return -1;
  806. #endif
  807.     return retVal;
  808. #else
  809.     cpLog(LOG_ERR, "UdpStack::receiveTimeout  * not defined in vxworks *n");
  810.     return -1;
  811. #endif
  812. }
  813. // uses send() which is better to get ICMP msg back
  814. // function returns a 0  normally
  815. void
  816. UdpStack::transmit ( const char* buf, const int length )
  817. {
  818.     if ((mode == recvonly) || (mode == inactive))
  819.     {
  820.         cpLog(LOG_ERR, "The stack is not capable to transmit. ");
  821.         return ;
  822.     }
  823.     assert(buf);
  824.     assert(length > 0);
  825.     if ( packetLossProbability > 0.0 )
  826.     {
  827.         static bool randInit = false;
  828.         if (!randInit)
  829.         {
  830.             randInit = true;
  831.             timeval tv;
  832.             gettimeofday(&tv, NULL);
  833.             long seed = tv.tv_sec + tv.tv_usec;
  834.             srandom(seed);
  835.         }
  836.         double numerator( random() & 0x7FFFFFFF );
  837.         double denominator( 0x7FFFFFFF );
  838.         double prob = numerator / denominator;
  839.         if ( prob < packetLossProbability )
  840.         {
  841.             // ok - just drop this packet
  842.             return ;
  843.         }
  844.     }
  845.     int count = send( data->socketFd,
  846.                       (char *)buf, length,
  847.                       0 /* flags */ );
  848.     if ( count < 0 )
  849.     {
  850.         int err = errno;
  851.         strstream errMsg;
  852.         errMsg << "UdpStack<" << getRmtName() << ">::transmit ";
  853.         switch (err)
  854.         {
  855.             case ECONNREFUSED:
  856.             {
  857.                 // This is the most common error - you get it if the host
  858.                 // does not exist or is nor running a program to recevice
  859.                 // the packets. This is what you get with the other side
  860.                 // crashes.
  861.                 errMsg << "Connection refused by destination host";
  862.                 errMsg << char(0);
  863.                 clog << errMsg.str() << endl;
  864. #if 0
  865.                 throw UdpStackExceptionConectionRefused(errMsg.str());
  866. #endif
  867.             }
  868.             break;
  869.             case EHOSTDOWN:
  870.             {
  871.                 errMsg << "destination host is down";
  872.                 errMsg << char(0);
  873.                 clog << errMsg.str() << endl;
  874.             }
  875.             break;
  876.             case EHOSTUNREACH:
  877.             {
  878.                 errMsg << "no route to to destination host";
  879.                 errMsg << char(0);
  880.                 clog << errMsg.str() << endl;
  881.             }
  882.             break;
  883.             default:
  884.             {
  885.                 errMsg << ": " << strerror(err);
  886.                 errMsg << char(0);
  887.                 clog << errMsg.str() << endl;
  888.             }
  889.         }
  890.  
  891.         cpLog (LOG_ERR, "UDP send() error: ");
  892.         errMsg.freeze(false);
  893. #if 0
  894.         throw UdpStackException(errMsg.str());
  895.         assert(0);
  896. #endif
  897.     }
  898.     else if ( count != length )
  899.     {
  900.         /*
  901.                 int err = errno;
  902.         */
  903.         strstream errMsg;
  904.         errMsg << "UdpStack<" << getRmtName()
  905.         << ">:transmit error is send: "
  906.         << "Asked to transmit " << length
  907.         << " bytes but only sent " << count ;
  908.         errMsg << char(0);
  909.         clog << errMsg.str() << endl;
  910.         errMsg.freeze(false);
  911. #if 0
  912.         throw UdpStackException(errMsg.str());
  913.         assert(0);
  914. #endif
  915.     }
  916.     else
  917.     {
  918.         numBytesTransmitted += count;
  919.         numPacketsTransmitted += 1;
  920.     }
  921.     if ( (logFlag) && (count > 0) )
  922.     {
  923.         strstream lenln3;
  924.         lenln3 << ++sndCount << " " << count << char(0);
  925.         out_log->write(lenln3.str(), strlen(lenln3.str()));
  926.         lenln3.freeze(false);
  927.         strstream rAddress1;
  928.         rAddress1 << " " << getRmtName() << "n" << char(0);
  929.         out_log->write(rAddress1.str(), strlen(rAddress1.str()));
  930.         rAddress1.freeze(false);
  931.         out_log->write(buf, count);
  932.         out_log->write(separator, 6);
  933.     }
  934. }
  935. int
  936. UdpStack::transmitTo ( const char* buffer,
  937.                        const int length,
  938.                        const NetworkAddress* dest )
  939. {
  940.     if ((mode == recvonly) || (mode == inactive))
  941.     {
  942.         cpLog(LOG_ERR, "The stack is not capable to transmit. ");
  943.         return 0;
  944.     }
  945.     assert(buffer);
  946.     assert(length > 0);
  947.     assert(dest);
  948.     setDestination(dest);
  949.     LockHelper helper(_lock);
  950.     struct sockaddr_in xDest;
  951.     xDest.sin_family = AF_INET;
  952.     xDest.sin_port = htons(dest->getPort());
  953.     xDest.sin_addr.s_addr = dest->getIp4Address();
  954.     int count = sendto( data->socketFd,
  955.                         (char*)buffer,
  956.                         length,
  957.                         0 ,  // flags
  958.                         (struct sockaddr*) & xDest,
  959.                         sizeof(sockaddr_in));
  960.     if ( count < 0 )
  961.     {
  962.         int err = errno;
  963.         strstream errMsg;
  964.         errMsg << "UdpStack<" << getRmtName() << ">::transmitTo ";
  965.         switch (err)
  966.         {
  967.             case ECONNREFUSED:
  968.             {
  969.                 // This is the most common error - you get it if the host
  970.                 // does not exist or is nor running a program to recevice
  971.                 // the packets. This is what you get with the other side
  972.                 // crashes.
  973.                 errMsg << "Connection refused by destination host";
  974.                 errMsg << char(0);
  975.                 clog << errMsg.str() << endl;
  976.                 return 1;
  977. #if 0
  978.                 throw UdpStackExceptionConectionRefused(errMsg.str());
  979. #endif
  980.             }
  981.             break;
  982.             case EHOSTDOWN:
  983.             {
  984.                 errMsg << "destination host is down";
  985.                 errMsg << char(0);
  986.                 clog << errMsg.str() << endl;
  987.                 return 2;
  988.             }
  989.             break;
  990.             case EHOSTUNREACH:
  991.             {
  992.                 errMsg << "no route to to destination host";
  993.                 errMsg << char(0);
  994.                 clog << errMsg.str() << endl;
  995.                 return 3;
  996.             }
  997.             break;
  998.             default:
  999.             {
  1000.                 errMsg << ": " << strerror(err);
  1001.                 errMsg << char(0);
  1002.                 clog << errMsg.str() << endl;
  1003.             }
  1004.         }
  1005.         cpLog (LOG_ERR, "UDP sendto() error: ");
  1006.         //        cerr << "UDP sendto error: " << endl;
  1007.         errMsg.freeze(false);
  1008. #if 0
  1009.         throw UdpStackException(errMsg.str());
  1010.         assert(0);
  1011. #endif
  1012.     }
  1013.     else if ( count != length )
  1014.     {
  1015.         //        int err = errno;
  1016.         strstream errMsg;
  1017.         errMsg << "UdpStack<" << getRmtName()
  1018.         << ">:transmit error is send: "
  1019.         << "Asked to transmit " << length
  1020.         << " bytes but only sent " << count ;
  1021.         errMsg << char(0);
  1022.         clog << errMsg.str() << endl;
  1023.         errMsg.freeze(false);
  1024. #if 0
  1025.         throw UdpStackException(errMsg.str());
  1026.         assert(0);
  1027. #endif
  1028.     }
  1029.     else
  1030.     {
  1031.         numBytesTransmitted += count;
  1032.         numPacketsTransmitted += 1;
  1033.     }
  1034.     if ( (logFlag) && (count > 0) )
  1035.     {
  1036.         strstream lenln4;
  1037.         lenln4 << ++sndCount << " " << count << char(0);
  1038.         out_log->write(lenln4.str(), strlen(lenln4.str()));
  1039.         lenln4.freeze(false);
  1040.         strstream rAddress2;
  1041.         rAddress2 << " " << getRmtName() << "n" << char(0);
  1042.         out_log->write(rAddress2.str(), strlen(rAddress2.str()));
  1043.         rAddress2.freeze(false);
  1044.         out_log->write(buffer, count);
  1045.         out_log->write(separator, 6);
  1046.     }
  1047.     return 0;
  1048. }
  1049. ///
  1050. void
  1051. UdpStack::joinMulticastGroup ( NetworkAddress group,
  1052.                                NetworkAddress* iface,
  1053.                                int ifaceInexe )
  1054. {
  1055. #ifndef WIN32
  1056. #if defined(__linux__)
  1057.     struct ip_mreqn mreqn;
  1058.     mreqn.imr_multiaddr.s_addr = (group.getIp4Address());
  1059.     mreqn.imr_address.s_addr = (iface->getIp4Address());
  1060.     mreqn.imr_ifindex = ifaceInexe;
  1061.     int ret;
  1062.     ret = setsockopt (getSocketFD(),
  1063.                       IPPROTO_IP,
  1064.                       IP_ADD_MEMBERSHIP,
  1065.                       (char*) & mreqn,
  1066.                       sizeof(struct ip_mreqn));
  1067.     //     cerr << "setsockopt ret = " << ret << endl;
  1068.     //     cerr << "setsockopt errno = " << errno << endl;
  1069. #else
  1070. struct ip_mreq mreq;
  1071.     mreq.imr_multiaddr.s_addr = (group.getIp4Address());
  1072.     mreq.imr_interface.s_addr = (iface->getIp4Address());
  1073.     //    mreq.imr_ifindex = ifaceInexe;
  1074.     int ret;
  1075.     ret = setsockopt (getSocketFD(),
  1076.                       IPPROTO_IP,
  1077.                       IP_ADD_MEMBERSHIP,
  1078.                       (char*) & mreq,
  1079.                       sizeof(struct ip_mreq));
  1080. #endif
  1081. #endif // !WIN32
  1082. }
  1083. ///
  1084. void
  1085. UdpStack::leaveMulticastGroup( NetworkAddress group,
  1086.                                NetworkAddress* iface,
  1087.                                int ifaceInexe )
  1088. {
  1089. #ifndef WIN32
  1090. #if defined(__linux__)
  1091.     struct ip_mreqn mreqn;
  1092.     mreqn.imr_multiaddr.s_addr = (group.getIp4Address());
  1093.     mreqn.imr_address.s_addr = (iface->getIp4Address());
  1094.     mreqn.imr_ifindex = ifaceInexe;
  1095.     setsockopt (getSocketFD(),
  1096.                 IPPROTO_IP,
  1097.                 IP_DROP_MEMBERSHIP,
  1098.                 (char*)&mreqn,
  1099.                 sizeof(struct ip_mreqn));
  1100. #else
  1101.     struct ip_mreq mreq;
  1102.     mreq.imr_multiaddr.s_addr = (group.getIp4Address());
  1103.     mreq.imr_interface.s_addr = (iface->getIp4Address());
  1104.     //    mreq.imr_ifindex = ifaceInexe;
  1105.     setsockopt (getSocketFD(),
  1106.                 IPPROTO_IP,
  1107.                 IP_DROP_MEMBERSHIP,
  1108.                 (char*)&mreq,
  1109.                 sizeof(struct ip_mreq));
  1110. #endif
  1111. #endif // !WIN32
  1112. }
  1113. UdpStack::~UdpStack()
  1114. {
  1115.     assert(data);
  1116.     if (logFlag)
  1117.     {
  1118.         in_log->close();
  1119.         out_log->close();
  1120.         delete in_log;
  1121.         delete out_log;
  1122.     }
  1123. #ifndef WIN32
  1124.     close (data->socketFd);
  1125. #else
  1126.     closesocket(data->socketFd);
  1127. #endif
  1128.     delete data;
  1129.     data = NULL;
  1130. }
  1131. int
  1132. UdpStack::getBytesReceived ()
  1133. {
  1134.     return numBytesReceived;
  1135. }
  1136. int
  1137. UdpStack::getPacketsReceived ()
  1138. {
  1139.     return numPacketsReceived;
  1140. }
  1141. int
  1142. UdpStack::getBytesTransmitted ()
  1143. {
  1144.     return numBytesTransmitted;
  1145. }
  1146. int
  1147. UdpStack::getPacketsTransmitted ()
  1148. {
  1149.     return numPacketsTransmitted;
  1150. }