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 27namespace webrtc { 28namespace test { 29UdpSocketPosix::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 72UdpSocketPosix::~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 95int32_t UdpSocketPosix::ChangeUniqueId(const int32_t id) 96{ 97 _id = id; 98 return 0; 99} 100 101bool 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 123bool 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 136int32_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 145bool 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 157int32_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 172SOCKET UdpSocketPosix::GetFd() { return _socket; } 173 174bool UdpSocketPosix::ValidHandle() 175{ 176 return _socket != INVALID_SOCKET; 177} 178 179bool 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 190void 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 233bool UdpSocketPosix::WantsIncoming() { return _wantsIncoming; } 234 235void 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 255void 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 274bool 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