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 {
UdpSocketPosix(const int32_t id,UdpSocketManager * mgr,bool ipV6Enable)29 UdpSocketPosix::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
~UdpSocketPosix()71 UdpSocketPosix::~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
SetCallback(CallbackObj obj,IncomingSocketCallback cb)94 bool 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
SetSockopt(int32_t level,int32_t optname,const int8_t * optval,int32_t optlen)116 bool 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
SetTOS(int32_t serviceType)129 int32_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
Bind(const SocketAddress & name)138 bool 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
SendTo(const int8_t * buf,size_t len,const SocketAddress & to)150 int32_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
GetFd()165 SOCKET UdpSocketPosix::GetFd() { return _socket; }
166
ValidHandle()167 bool UdpSocketPosix::ValidHandle()
168 {
169 return _socket != INVALID_SOCKET;
170 }
171
SetQos(int32_t,int32_t,int32_t,int32_t,int32_t,int32_t,const SocketAddress &,int32_t)172 bool 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
HasIncoming()183 void 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
WantsIncoming()226 bool UdpSocketPosix::WantsIncoming() { return _wantsIncoming; }
227
CloseBlocking()228 void 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
ReadyForDeletion()248 void 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
CleanUp()267 bool 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