• 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/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