Home | History | Annotate | Download | only in channel_transport
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/test/channel_transport/udp_socket_posix.h"
     12 
     13 #include <errno.h>
     14 #include <fcntl.h>
     15 #include <netdb.h>
     16 #include <stdio.h>
     17 #include <string.h>
     18 #include <sys/ioctl.h>
     19 #include <sys/types.h>
     20 #include <time.h>
     21 #include <unistd.h>
     22 
     23 #include "webrtc/system_wrappers/interface/trace.h"
     24 #include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h"
     25 #include "webrtc/test/channel_transport/udp_socket_wrapper.h"
     26 
     27 namespace webrtc {
     28 namespace test {
     29 UdpSocketPosix::UdpSocketPosix(const int32_t id, UdpSocketManager* mgr,
     30                                bool ipV6Enable)
     31 {
     32     WEBRTC_TRACE(kTraceMemory, kTraceTransport, id,
     33                  "UdpSocketPosix::UdpSocketPosix()");
     34 
     35     _wantsIncoming = false;
     36     _mgr = mgr;
     37 
     38     _id = id;
     39     _obj = NULL;
     40     _incomingCb = NULL;
     41     _readyForDeletionCond = ConditionVariableWrapper::CreateConditionVariable();
     42     _closeBlockingCompletedCond =
     43         ConditionVariableWrapper::CreateConditionVariable();
     44     _cs = CriticalSectionWrapper::CreateCriticalSection();
     45     _readyForDeletion = false;
     46     _closeBlockingActive = false;
     47     _closeBlockingCompleted= false;
     48     if(ipV6Enable)
     49     {
     50         _socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
     51     }
     52     else {
     53         _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
     54     }
     55 
     56     // Set socket to nonblocking mode.
     57     int enable_non_blocking = 1;
     58     if(ioctl(_socket, FIONBIO, &enable_non_blocking) == -1)
     59     {
     60         WEBRTC_TRACE(kTraceWarning, kTraceTransport, id,
     61                      "Failed to make socket nonblocking");
     62     }
     63     // Enable close on fork for file descriptor so that it will not block until
     64     // forked process terminates.
     65     if(fcntl(_socket, F_SETFD, FD_CLOEXEC) == -1)
     66     {
     67         WEBRTC_TRACE(kTraceWarning, kTraceTransport, id,
     68                      "Failed to set FD_CLOEXEC for socket");
     69     }
     70 }
     71 
     72 UdpSocketPosix::~UdpSocketPosix()
     73 {
     74     if(_socket != INVALID_SOCKET)
     75     {
     76         close(_socket);
     77         _socket = INVALID_SOCKET;
     78     }
     79     if(_readyForDeletionCond)
     80     {
     81         delete _readyForDeletionCond;
     82     }
     83 
     84     if(_closeBlockingCompletedCond)
     85     {
     86         delete _closeBlockingCompletedCond;
     87     }
     88 
     89     if(_cs)
     90     {
     91         delete _cs;
     92     }
     93 }
     94 
     95 int32_t UdpSocketPosix::ChangeUniqueId(const int32_t id)
     96 {
     97     _id = id;
     98     return 0;
     99 }
    100 
    101 bool UdpSocketPosix::SetCallback(CallbackObj obj, IncomingSocketCallback cb)
    102 {
    103     _obj = obj;
    104     _incomingCb = cb;
    105 
    106     WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
    107                  "UdpSocketPosix(%p)::SetCallback", this);
    108 
    109     if (_mgr->AddSocket(this))
    110       {
    111         WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
    112                      "UdpSocketPosix(%p)::SetCallback socket added to manager",
    113                      this);
    114         return true;   // socket is now ready for action
    115       }
    116 
    117     WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
    118                  "UdpSocketPosix(%p)::SetCallback error adding me to mgr",
    119                  this);
    120     return false;
    121 }
    122 
    123 bool UdpSocketPosix::SetSockopt(int32_t level, int32_t optname,
    124                                 const int8_t* optval, int32_t optlen)
    125 {
    126    if(0 == setsockopt(_socket, level, optname, optval, optlen ))
    127    {
    128        return true;
    129    }
    130 
    131    WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
    132                 "UdpSocketPosix::SetSockopt(), error:%d", errno);
    133    return false;
    134 }
    135 
    136 int32_t UdpSocketPosix::SetTOS(int32_t serviceType)
    137 {
    138     if (SetSockopt(IPPROTO_IP, IP_TOS ,(int8_t*)&serviceType ,4) != 0)
    139     {
    140         return -1;
    141     }
    142     return 0;
    143 }
    144 
    145 bool UdpSocketPosix::Bind(const SocketAddress& name)
    146 {
    147     int size = sizeof(sockaddr);
    148     if (0 == bind(_socket, reinterpret_cast<const sockaddr*>(&name),size))
    149     {
    150         return true;
    151     }
    152     WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
    153                  "UdpSocketPosix::Bind() error: %d", errno);
    154     return false;
    155 }
    156 
    157 int32_t UdpSocketPosix::SendTo(const int8_t* buf, int32_t len,
    158                                const SocketAddress& to)
    159 {
    160     int size = sizeof(sockaddr);
    161     int retVal = sendto(_socket,buf, len, 0,
    162                         reinterpret_cast<const sockaddr*>(&to), size);
    163     if(retVal == SOCKET_ERROR)
    164     {
    165         WEBRTC_TRACE(kTraceError, kTraceTransport, _id,
    166                      "UdpSocketPosix::SendTo() error: %d", errno);
    167     }
    168 
    169     return retVal;
    170 }
    171 
    172 SOCKET UdpSocketPosix::GetFd() { return _socket; }
    173 
    174 bool UdpSocketPosix::ValidHandle()
    175 {
    176     return _socket != INVALID_SOCKET;
    177 }
    178 
    179 bool UdpSocketPosix::SetQos(int32_t /*serviceType*/,
    180                             int32_t /*tokenRate*/,
    181                             int32_t /*bucketSize*/,
    182                             int32_t /*peekBandwith*/,
    183                             int32_t /*minPolicedSize*/,
    184                             int32_t /*maxSduSize*/,
    185                             const SocketAddress& /*stRemName*/,
    186                             int32_t /*overrideDSCP*/) {
    187   return false;
    188 }
    189 
    190 void UdpSocketPosix::HasIncoming()
    191 {
    192     // replace 2048 with a mcro define and figure out
    193     // where 2048 comes from
    194     int8_t buf[2048];
    195     int retval;
    196     SocketAddress from;
    197 #if defined(WEBRTC_MAC)
    198     sockaddr sockaddrfrom;
    199     memset(&from, 0, sizeof(from));
    200     memset(&sockaddrfrom, 0, sizeof(sockaddrfrom));
    201     socklen_t fromlen = sizeof(sockaddrfrom);
    202 #else
    203     memset(&from, 0, sizeof(from));
    204     socklen_t fromlen = sizeof(from);
    205 #endif
    206 
    207 #if defined(WEBRTC_MAC)
    208         retval = recvfrom(_socket,buf, sizeof(buf), 0,
    209                           reinterpret_cast<sockaddr*>(&sockaddrfrom), &fromlen);
    210         memcpy(&from, &sockaddrfrom, fromlen);
    211         from._sockaddr_storage.sin_family = sockaddrfrom.sa_family;
    212 #else
    213         retval = recvfrom(_socket,buf, sizeof(buf), 0,
    214                           reinterpret_cast<sockaddr*>(&from), &fromlen);
    215 #endif
    216 
    217     switch(retval)
    218     {
    219     case 0:
    220         // The peer has performed an orderly shutdown.
    221         break;
    222     case SOCKET_ERROR:
    223         break;
    224     default:
    225         if (_wantsIncoming && _incomingCb)
    226         {
    227           _incomingCb(_obj, buf, retval, &from);
    228         }
    229         break;
    230     }
    231 }
    232 
    233 bool UdpSocketPosix::WantsIncoming() { return _wantsIncoming; }
    234 
    235 void UdpSocketPosix::CloseBlocking()
    236 {
    237     _cs->Enter();
    238     _closeBlockingActive = true;
    239     if(!CleanUp())
    240     {
    241         _closeBlockingActive = false;
    242         _cs->Leave();
    243         return;
    244     }
    245 
    246     while(!_readyForDeletion)
    247     {
    248         _readyForDeletionCond->SleepCS(*_cs);
    249     }
    250     _closeBlockingCompleted = true;
    251     _closeBlockingCompletedCond->Wake();
    252     _cs->Leave();
    253 }
    254 
    255 void UdpSocketPosix::ReadyForDeletion()
    256 {
    257     _cs->Enter();
    258     if(!_closeBlockingActive)
    259     {
    260         _cs->Leave();
    261         return;
    262     }
    263     close(_socket);
    264     _socket = INVALID_SOCKET;
    265     _readyForDeletion = true;
    266     _readyForDeletionCond->Wake();
    267     while(!_closeBlockingCompleted)
    268     {
    269         _closeBlockingCompletedCond->SleepCS(*_cs);
    270     }
    271     _cs->Leave();
    272 }
    273 
    274 bool UdpSocketPosix::CleanUp()
    275 {
    276     _wantsIncoming = false;
    277 
    278     if (_socket == INVALID_SOCKET)
    279     {
    280         return false;
    281     }
    282 
    283     WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id,
    284                  "calling UdpSocketManager::RemoveSocket()...");
    285     _mgr->RemoveSocket(this);
    286     // After this, the socket should may be or will be as deleted. Return
    287     // immediately.
    288     return true;
    289 }
    290 
    291 }  // namespace test
    292 }  // namespace webrtc
    293