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