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