channel.cpp

00001 /*****************************************************************************
00002 Copyright (c) 2001 - 2011, The Board of Trustees of the University of Illinois.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are
00007 met:
00008 
00009 * Redistributions of source code must retain the above
00010   copyright notice, this list of conditions and the
00011   following disclaimer.
00012 
00013 * Redistributions in binary form must reproduce the
00014   above copyright notice, this list of conditions
00015   and the following disclaimer in the documentation
00016   and/or other materials provided with the distribution.
00017 
00018 * Neither the name of the University of Illinois
00019   nor the names of its contributors may be used to
00020   endorse or promote products derived from this
00021   software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024 IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
00025 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00026 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
00027 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00028 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00029 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00030 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00031 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00032 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00033 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 ****************************************************************************/
00035 
00036 /****************************************************************************
00037 written by
00038    Yunhong Gu, last updated 01/27/2011
00039 *****************************************************************************/
00040 
00041 #ifndef WIN32
00042    #include <netdb.h>
00043    #include <arpa/inet.h>
00044    #include <unistd.h>
00045    #include <fcntl.h>
00046    #include <cstring>
00047    #include <cstdio>
00048    #include <cerrno>
00049 #else
00050    #include <winsock2.h>
00051    #include <ws2tcpip.h>
00052    #ifdef LEGACY_WIN32
00053       #include <wspiapi.h>
00054    #endif
00055 #endif
00056 #include "channel.h"
00057 #include "packet.h"
00058 
00059 #ifdef WIN32
00060    #define socklen_t int
00061 #endif
00062 
00063 #ifndef WIN32
00064    #define NET_ERROR errno
00065 #else
00066    #define NET_ERROR WSAGetLastError()
00067 #endif
00068 
00069 
00070 CChannel::CChannel():
00071 m_iIPversion(AF_INET),
00072 m_iSockAddrSize(sizeof(sockaddr_in)),
00073 m_iSocket(),
00074 m_iSndBufSize(65536),
00075 m_iRcvBufSize(65536)
00076 {
00077 }
00078 
00079 CChannel::CChannel(int version):
00080 m_iIPversion(version),
00081 m_iSocket(),
00082 m_iSndBufSize(65536),
00083 m_iRcvBufSize(65536)
00084 {
00085    m_iSockAddrSize = (AF_INET == m_iIPversion) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
00086 }
00087 
00088 CChannel::~CChannel()
00089 {
00090 }
00091 
00092 void CChannel::open(const sockaddr* addr)
00093 {
00094    // construct an socket
00095    m_iSocket = ::socket(m_iIPversion, SOCK_DGRAM, 0);
00096 
00097    #ifdef WIN32
00098       if (INVALID_SOCKET == m_iSocket)
00099    #else
00100       if (m_iSocket < 0)
00101    #endif
00102       throw CUDTException(1, 0, NET_ERROR);
00103 
00104    if (NULL != addr)
00105    {
00106       socklen_t namelen = m_iSockAddrSize;
00107 
00108       if (0 != ::bind(m_iSocket, addr, namelen))
00109          throw CUDTException(1, 3, NET_ERROR);
00110    }
00111    else
00112    {
00113       //sendto or WSASendTo will also automatically bind the socket
00114       addrinfo hints;
00115       addrinfo* res;
00116 
00117       memset(&hints, 0, sizeof(struct addrinfo));
00118 
00119       hints.ai_flags = AI_PASSIVE;
00120       hints.ai_family = m_iIPversion;
00121       hints.ai_socktype = SOCK_DGRAM;
00122 
00123       if (0 != ::getaddrinfo(NULL, "0", &hints, &res))
00124          throw CUDTException(1, 3, NET_ERROR);
00125 
00126       if (0 != ::bind(m_iSocket, res->ai_addr, res->ai_addrlen))
00127          throw CUDTException(1, 3, NET_ERROR);
00128 
00129       ::freeaddrinfo(res);
00130    }
00131 
00132    setUDPSockOpt();
00133 }
00134 
00135 void CChannel::open(UDPSOCKET udpsock)
00136 {
00137    m_iSocket = udpsock;
00138    setUDPSockOpt();
00139 }
00140 
00141 void CChannel::setUDPSockOpt()
00142 {
00143    #if defined(BSD) || defined(OSX)
00144       // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value
00145       int maxsize = 64000;
00146       if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int)))
00147          ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&maxsize, sizeof(int));
00148       if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int)))
00149          ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&maxsize, sizeof(int));
00150    #else
00151       // for other systems, if requested is greated than maximum, the maximum value will be automactally used
00152       if ((0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int))) ||
00153           (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int))))
00154          throw CUDTException(1, 3, NET_ERROR);
00155    #endif
00156 
00157    timeval tv;
00158    tv.tv_sec = 0;
00159    #if defined (BSD) || defined (OSX)
00160       // Known BSD bug as the day I wrote this code.
00161       // A small time out value will cause the socket to block forever.
00162       tv.tv_usec = 10000;
00163    #else
00164       tv.tv_usec = 100;
00165    #endif
00166 
00167    #ifdef UNIX
00168       // Set non-blocking I/O
00169       // UNIX does not support SO_RCVTIMEO
00170       int opts = ::fcntl(m_iSocket, F_GETFL);
00171       if (-1 == ::fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK))
00172          throw CUDTException(1, 3, NET_ERROR);
00173    #elif WIN32
00174       DWORD ot = 1; //milliseconds
00175       if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeof(DWORD)))
00176          throw CUDTException(1, 3, NET_ERROR);
00177    #else
00178       // Set receiving time-out value
00179       if (0 != ::setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval)))
00180          throw CUDTException(1, 3, NET_ERROR);
00181    #endif
00182 }
00183 
00184 void CChannel::close() const
00185 {
00186    #ifndef WIN32
00187       ::close(m_iSocket);
00188    #else
00189       ::closesocket(m_iSocket);
00190    #endif
00191 }
00192 
00193 int CChannel::getSndBufSize()
00194 {
00195    socklen_t size = sizeof(socklen_t);
00196    ::getsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize, &size);
00197    return m_iSndBufSize;
00198 }
00199 
00200 int CChannel::getRcvBufSize()
00201 {
00202    socklen_t size = sizeof(socklen_t);
00203    ::getsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, &size);
00204    return m_iRcvBufSize;
00205 }
00206 
00207 void CChannel::setSndBufSize(int size)
00208 {
00209    m_iSndBufSize = size;
00210 }
00211 
00212 void CChannel::setRcvBufSize(int size)
00213 {
00214    m_iRcvBufSize = size;
00215 }
00216 
00217 void CChannel::getSockAddr(sockaddr* addr) const
00218 {
00219    socklen_t namelen = m_iSockAddrSize;
00220    ::getsockname(m_iSocket, addr, &namelen);
00221 }
00222 
00223 void CChannel::getPeerAddr(sockaddr* addr) const
00224 {
00225    socklen_t namelen = m_iSockAddrSize;
00226    ::getpeername(m_iSocket, addr, &namelen);
00227 }
00228 
00229 int CChannel::sendto(const sockaddr* addr, CPacket& packet) const
00230 {
00231    // convert control information into network order
00232    if (packet.getFlag())
00233       for (int i = 0, n = packet.getLength() / 4; i < n; ++ i)
00234          *((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcData + i));
00235 
00236    // convert packet header into network order
00237    //for (int j = 0; j < 4; ++ j)
00238    //   packet.m_nHeader[j] = htonl(packet.m_nHeader[j]);
00239    uint32_t* p = packet.m_nHeader;
00240    for (int j = 0; j < 4; ++ j)
00241    {
00242       *p = htonl(*p);
00243       ++ p;
00244    }
00245 
00246    #ifndef WIN32
00247       msghdr mh;
00248       mh.msg_name = (sockaddr*)addr;
00249       mh.msg_namelen = m_iSockAddrSize;
00250       mh.msg_iov = (iovec*)packet.m_PacketVector;
00251       mh.msg_iovlen = 2;
00252       mh.msg_control = NULL;
00253       mh.msg_controllen = 0;
00254       mh.msg_flags = 0;
00255 
00256       int res = ::sendmsg(m_iSocket, &mh, 0);
00257    #else
00258       DWORD size = CPacket::m_iPktHdrSize + packet.getLength();
00259       int addrsize = m_iSockAddrSize;
00260       int res = ::WSASendTo(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, 0, addr, addrsize, NULL, NULL);
00261       res = (0 == res) ? size : -1;
00262    #endif
00263 
00264    // convert back into local host order
00265    //for (int k = 0; k < 4; ++ k)
00266    //   packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]);
00267    p = packet.m_nHeader;
00268    for (int k = 0; k < 4; ++ k)
00269    {
00270       *p = ntohl(*p);
00271        ++ p;
00272    }
00273 
00274    if (packet.getFlag())
00275    {
00276       for (int l = 0, n = packet.getLength() / 4; l < n; ++ l)
00277          *((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcData + l));
00278    }
00279 
00280    return res;
00281 }
00282 
00283 int CChannel::recvfrom(sockaddr* addr, CPacket& packet) const
00284 {
00285    #ifndef WIN32
00286       msghdr mh;   
00287       mh.msg_name = addr;
00288       mh.msg_namelen = m_iSockAddrSize;
00289       mh.msg_iov = packet.m_PacketVector;
00290       mh.msg_iovlen = 2;
00291       mh.msg_control = NULL;
00292       mh.msg_controllen = 0;
00293       mh.msg_flags = 0;
00294 
00295       #ifdef UNIX
00296          fd_set set;
00297          timeval tv;
00298          FD_ZERO(&set);
00299          FD_SET(m_iSocket, &set);
00300          tv.tv_sec = 0;
00301          tv.tv_usec = 10000;
00302          ::select(m_iSocket+1, &set, NULL, &set, &tv);
00303       #endif
00304 
00305       int res = ::recvmsg(m_iSocket, &mh, 0);
00306    #else
00307       DWORD size = CPacket::m_iPktHdrSize + packet.getLength();
00308       DWORD flag = 0;
00309       int addrsize = m_iSockAddrSize;
00310 
00311       int res = ::WSARecvFrom(m_iSocket, (LPWSABUF)packet.m_PacketVector, 2, &size, &flag, addr, &addrsize, NULL, NULL);
00312       res = (0 == res) ? size : -1;
00313    #endif
00314 
00315    if (res <= 0)
00316    {
00317       packet.setLength(-1);
00318       return -1;
00319    }
00320 
00321    packet.setLength(res - CPacket::m_iPktHdrSize);
00322 
00323    // convert back into local host order
00324    //for (int i = 0; i < 4; ++ i)
00325    //   packet.m_nHeader[i] = ntohl(packet.m_nHeader[i]);
00326    uint32_t* p = packet.m_nHeader;
00327    for (int i = 0; i < 4; ++ i)
00328    {
00329       *p = ntohl(*p);
00330       ++ p;
00331    }
00332 
00333    if (packet.getFlag())
00334    {
00335       for (int j = 0, n = packet.getLength() / 4; j < n; ++ j)
00336          *((uint32_t *)packet.m_pcData + j) = ntohl(*((uint32_t *)packet.m_pcData + j));
00337    }
00338 
00339    return packet.getLength();
00340 }

Generated on 9 Feb 2013 for barchart-udt-core-2.2.2 by  doxygen 1.6.1