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