• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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