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 |