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/voice_engine/test/channel_transport/udp_socket2_win.h" | |
12 | |
13 #include <assert.h> | |
14 #include <stdlib.h> | |
15 #include <winsock2.h> | |
16 | |
17 #include "webrtc/base/format_macros.h" | |
18 #include "webrtc/system_wrappers/include/sleep.h" | |
19 #include "webrtc/voice_engine/test/channel_transport/traffic_control_win.h" | |
20 #include "webrtc/voice_engine/test/channel_transport/udp_socket2_manager_win.h" | |
21 | |
22 #pragma warning(disable : 4311) | |
23 | |
24 namespace webrtc { | |
25 namespace test { | |
26 | |
27 typedef struct _QOS_DESTADDR | |
28 { | |
29 QOS_OBJECT_HDR ObjectHdr; | |
30 const struct sockaddr* SocketAddress; | |
31 ULONG SocketAddressLength; | |
32 } QOS_DESTADDR, *LPQOS_DESTADDR; | |
33 | |
34 typedef const QOS_DESTADDR* LPCQOS_DESTADDR; | |
35 | |
36 // TODO (patrikw): seems to be defined in ws2ipdef.h as 3. How come it's | |
37 // redefined here (as a different value)? | |
38 #define IP_TOS 8 | |
39 | |
40 #define QOS_GENERAL_ID_BASE 2000 | |
41 #define QOS_OBJECT_DESTADDR (0x00000004 + QOS_GENERAL_ID_BASE) | |
42 | |
43 UdpSocket2Windows::UdpSocket2Windows(const int32_t id, | |
44 UdpSocketManager* mgr, bool ipV6Enable, | |
45 bool disableGQOS) | |
46 : _id(id), | |
47 _qos(true), | |
48 _iProtocol(0), | |
49 _outstandingCalls(0), | |
50 _outstandingCallComplete(0), | |
51 _terminate(false), | |
52 _addedToMgr(false), | |
53 delete_event_(true, false), | |
54 _outstandingCallsDisabled(false), | |
55 _clientHandle(NULL), | |
56 _flowHandle(NULL), | |
57 _filterHandle(NULL), | |
58 _flow(NULL), | |
59 _gtc(NULL), | |
60 _pcp(-2), | |
61 _receiveBuffers(0) | |
62 { | |
63 WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, | |
64 "UdpSocket2Windows::UdpSocket2Windows()"); | |
65 | |
66 _wantsIncoming = false; | |
67 _mgr = static_cast<UdpSocket2ManagerWindows *>(mgr); | |
68 | |
69 _obj = NULL; | |
70 _incomingCb = NULL; | |
71 _socket = INVALID_SOCKET; | |
72 _ptrCbRWLock = RWLockWrapper::CreateRWLock(); | |
73 _ptrDestRWLock = RWLockWrapper::CreateRWLock(); | |
74 _ptrSocketRWLock = RWLockWrapper::CreateRWLock(); | |
75 | |
76 // Check if QoS is supported. | |
77 BOOL bProtocolFound = FALSE; | |
78 WSAPROTOCOL_INFO *lpProtocolBuf = NULL; | |
79 WSAPROTOCOL_INFO pProtocolInfo; | |
80 | |
81 if(!disableGQOS) | |
82 { | |
83 DWORD dwBufLen = 0; | |
84 // Set dwBufLen to the size needed to retreive all the requested | |
85 // information from WSAEnumProtocols. | |
86 int32_t nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen); | |
87 lpProtocolBuf = (WSAPROTOCOL_INFO*)malloc(dwBufLen); | |
88 nRet = WSAEnumProtocols(NULL, lpProtocolBuf, &dwBufLen); | |
89 | |
90 if (ipV6Enable) | |
91 { | |
92 _iProtocol=AF_INET6; | |
93 } else { | |
94 _iProtocol=AF_INET; | |
95 } | |
96 | |
97 for (int32_t i=0; i<nRet; i++) | |
98 { | |
99 if (_iProtocol == lpProtocolBuf[i].iAddressFamily && | |
100 IPPROTO_UDP == lpProtocolBuf[i].iProtocol) | |
101 { | |
102 if ((XP1_QOS_SUPPORTED == | |
103 (XP1_QOS_SUPPORTED & lpProtocolBuf[i].dwServiceFlags1))) | |
104 { | |
105 pProtocolInfo = lpProtocolBuf[i]; | |
106 bProtocolFound = TRUE; | |
107 break; | |
108 } | |
109 } | |
110 } | |
111 } | |
112 | |
113 if(!bProtocolFound) | |
114 { | |
115 free(lpProtocolBuf); | |
116 _qos=false; | |
117 WEBRTC_TRACE( | |
118 kTraceError, | |
119 kTraceTransport, | |
120 _id, | |
121 "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR_NO_QOS,\ | |
122 !bProtocolFound"); | |
123 } else { | |
124 | |
125 _socket = WSASocket(FROM_PROTOCOL_INFO, FROM_PROTOCOL_INFO, | |
126 FROM_PROTOCOL_INFO,&pProtocolInfo, 0, | |
127 WSA_FLAG_OVERLAPPED); | |
128 free(lpProtocolBuf); | |
129 | |
130 if (_socket != INVALID_SOCKET) | |
131 { | |
132 return; | |
133 } else { | |
134 _qos = false; | |
135 WEBRTC_TRACE( | |
136 kTraceError, | |
137 kTraceTransport, | |
138 _id, | |
139 "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR_NO_QOS"); | |
140 } | |
141 } | |
142 // QoS not supported. | |
143 if(ipV6Enable) | |
144 { | |
145 _socket = WSASocket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, 0 , 0, | |
146 WSA_FLAG_OVERLAPPED); | |
147 }else | |
148 { | |
149 _socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, 0 , 0, | |
150 WSA_FLAG_OVERLAPPED); | |
151 } | |
152 if (_socket == INVALID_SOCKET) | |
153 { | |
154 WEBRTC_TRACE( | |
155 kTraceError, | |
156 kTraceTransport, | |
157 _id, | |
158 "UdpSocket2Windows::UdpSocket2Windows(), INVALID_SOCKET,\ | |
159 WSAerror: %d", | |
160 WSAGetLastError()); | |
161 } | |
162 | |
163 // Disable send buffering on the socket to improve CPU usage. | |
164 // This is done by setting SO_SNDBUF to 0. | |
165 int32_t nZero = 0; | |
166 int32_t nRet = setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, | |
167 (char*)&nZero, sizeof(nZero)); | |
168 if( nRet == SOCKET_ERROR ) | |
169 { | |
170 WEBRTC_TRACE( | |
171 kTraceError, | |
172 kTraceTransport, | |
173 _id, | |
174 "UdpSocket2Windows::UdpSocket2Windows(), SOCKET_ERROR,\ | |
175 WSAerror: %d", | |
176 WSAGetLastError()); | |
177 } | |
178 } | |
179 | |
180 UdpSocket2Windows::~UdpSocket2Windows() | |
181 { | |
182 WEBRTC_TRACE(kTraceMemory, kTraceTransport, _id, | |
183 "UdpSocket2Windows::~UdpSocket2Windows()"); | |
184 | |
185 delete_event_.Wait(rtc::Event::kForever); | |
186 | |
187 | |
188 delete _ptrCbRWLock; | |
189 delete _ptrDestRWLock; | |
190 delete _ptrSocketRWLock; | |
191 | |
192 if (_flow) | |
193 { | |
194 free(_flow); | |
195 _flow = NULL; | |
196 } | |
197 | |
198 if (_gtc) | |
199 { | |
200 if(_filterHandle) | |
201 { | |
202 _gtc->TcDeleteFilter(_filterHandle); | |
203 } | |
204 if(_flowHandle) | |
205 { | |
206 _gtc->TcDeleteFlow(_flowHandle); | |
207 } | |
208 TrafficControlWindows::Release( _gtc); | |
209 } | |
210 } | |
211 | |
212 bool UdpSocket2Windows::ValidHandle() | |
213 { | |
214 return GetFd() != INVALID_SOCKET; | |
215 } | |
216 | |
217 bool UdpSocket2Windows::SetCallback(CallbackObj obj, IncomingSocketCallback cb) | |
218 { | |
219 _ptrCbRWLock->AcquireLockExclusive(); | |
220 _obj = obj; | |
221 _incomingCb = cb; | |
222 _ptrCbRWLock->ReleaseLockExclusive(); | |
223 | |
224 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
225 "UdpSocket2Windows(%d)::SetCallback ",(int32_t)this); | |
226 if(_addedToMgr) | |
227 { | |
228 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
229 "UdpSocket2Windows(%d)::SetCallback alreadey added", | |
230 (int32_t) this); | |
231 return false; | |
232 | |
233 } | |
234 if (_mgr->AddSocket(this)) | |
235 { | |
236 WEBRTC_TRACE( | |
237 kTraceDebug, kTraceTransport, _id, | |
238 "UdpSocket2Windows(%d)::SetCallback socket added to manager", | |
239 (int32_t)this); | |
240 _addedToMgr = true; | |
241 return true; | |
242 } | |
243 | |
244 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
245 "UdpSocket2Windows(%d)::SetCallback error adding me to mgr", | |
246 (int32_t) this); | |
247 return false; | |
248 } | |
249 | |
250 bool UdpSocket2Windows::SetSockopt(int32_t level, int32_t optname, | |
251 const int8_t* optval, int32_t optlen) | |
252 { | |
253 bool returnValue = true; | |
254 if(!AquireSocket()) | |
255 { | |
256 return false; | |
257 } | |
258 if(0 != setsockopt(_socket, level, optname, | |
259 reinterpret_cast<const char*>(optval), optlen )) | |
260 { | |
261 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
262 "UdpSocket2Windows::SetSockopt(), WSAerror:%d", | |
263 WSAGetLastError()); | |
264 returnValue = false; | |
265 } | |
266 ReleaseSocket(); | |
267 return returnValue; | |
268 } | |
269 | |
270 bool UdpSocket2Windows::StartReceiving(uint32_t receiveBuffers) | |
271 { | |
272 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
273 "UdpSocket2Windows(%d)::StartReceiving(%d)", (int32_t)this, | |
274 receiveBuffers); | |
275 | |
276 _wantsIncoming = true; | |
277 | |
278 int32_t numberOfReceiveBuffersToCreate = | |
279 receiveBuffers - _receiveBuffers.Value(); | |
280 numberOfReceiveBuffersToCreate = (numberOfReceiveBuffersToCreate < 0) ? | |
281 0 : numberOfReceiveBuffersToCreate; | |
282 | |
283 int32_t error = 0; | |
284 for(int32_t i = 0; | |
285 i < numberOfReceiveBuffersToCreate; | |
286 i++) | |
287 { | |
288 if(PostRecv()) | |
289 { | |
290 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
291 "UdpSocket2Windows::StartReceiving() i=%d", i); | |
292 error = -1; | |
293 break; | |
294 } | |
295 ++_receiveBuffers; | |
296 } | |
297 if(error == -1) | |
298 { | |
299 return false; | |
300 } | |
301 | |
302 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
303 "Socket receiving using:%d number of buffers", | |
304 _receiveBuffers.Value()); | |
305 return true; | |
306 } | |
307 | |
308 bool UdpSocket2Windows::StopReceiving() | |
309 { | |
310 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
311 "UdpSocket2Windows::StopReceiving()"); | |
312 _wantsIncoming = false; | |
313 return true; | |
314 } | |
315 | |
316 bool UdpSocket2Windows::Bind(const SocketAddress& name) | |
317 { | |
318 const struct sockaddr* addr = | |
319 reinterpret_cast<const struct sockaddr*>(&name); | |
320 bool returnValue = true; | |
321 if(!AquireSocket()) | |
322 { | |
323 return false; | |
324 } | |
325 if (0 != bind(_socket, addr, sizeof(SocketAddress))) | |
326 { | |
327 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
328 "UdpSocket2Windows::Bind() WSAerror: %d", | |
329 WSAGetLastError()); | |
330 returnValue = false; | |
331 } | |
332 ReleaseSocket(); | |
333 return returnValue; | |
334 } | |
335 | |
336 int32_t UdpSocket2Windows::SendTo(const int8_t* buf, size_t len, | |
337 const SocketAddress& to) | |
338 { | |
339 int32_t retVal = 0; | |
340 int32_t error = 0; | |
341 PerIoContext* pIoContext = _mgr->PopIoContext(); | |
342 if(pIoContext == 0) | |
343 { | |
344 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
345 "UdpSocket2Windows(%d)::SendTo(), pIoContext==0", | |
346 (int32_t) this); | |
347 return -1; | |
348 } | |
349 // sizeof(pIoContext->buffer) is smaller than the highest number that | |
350 // can be represented by a size_t. | |
351 if(len >= sizeof(pIoContext->buffer)) | |
352 { | |
353 WEBRTC_TRACE( | |
354 kTraceError, | |
355 kTraceTransport, | |
356 _id, | |
357 "UdpSocket2Windows(%d)::SendTo(), len= %" PRIuS | |
358 " > buffer_size = %d", | |
359 (int32_t) this, | |
360 len,sizeof(pIoContext->buffer)); | |
361 len = sizeof(pIoContext->buffer); | |
362 } | |
363 | |
364 memcpy(pIoContext->buffer,buf,len); | |
365 pIoContext->wsabuf.buf = pIoContext->buffer; | |
366 pIoContext->wsabuf.len = static_cast<ULONG>(len); | |
367 pIoContext->fromLen=sizeof(SocketAddress); | |
368 pIoContext->ioOperation = OP_WRITE; | |
369 pIoContext->nTotalBytes = len; | |
370 pIoContext->nSentBytes=0; | |
371 | |
372 DWORD numOfbytesSent = 0; | |
373 const struct sockaddr* addr = reinterpret_cast<const struct sockaddr*>(&to); | |
374 | |
375 if(!AquireSocket()) | |
376 { | |
377 _mgr->PushIoContext(pIoContext); | |
378 return -1; | |
379 } | |
380 // Assume that the WSASendTo call will be successfull to make sure that | |
381 // _outstandingCalls is positive. Roll back if WSASendTo failed. | |
382 if(!NewOutstandingCall()) | |
383 { | |
384 _mgr->PushIoContext(pIoContext); | |
385 ReleaseSocket(); | |
386 return -1; | |
387 } | |
388 retVal = WSASendTo(_socket, &pIoContext->wsabuf, 1, &numOfbytesSent, | |
389 0, addr, sizeof(SocketAddress), | |
390 &(pIoContext->overlapped), 0); | |
391 ReleaseSocket(); | |
392 | |
393 if( retVal == SOCKET_ERROR ) | |
394 { | |
395 error = WSAGetLastError(); | |
396 if(error != ERROR_IO_PENDING) | |
397 { | |
398 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
399 "UdpSocket2Windows::SendTo() WSAerror: %d",error); | |
400 } | |
401 } | |
402 if(retVal == 0 || (retVal == SOCKET_ERROR && error == ERROR_IO_PENDING)) | |
403 { | |
404 return static_cast<int32_t>(len); | |
405 } | |
406 error = _mgr->PushIoContext(pIoContext); | |
407 if(error) | |
408 { | |
409 WEBRTC_TRACE( | |
410 kTraceError, | |
411 kTraceTransport, | |
412 _id, | |
413 "UdpSocket2Windows(%d)::SendTo(), error:%d pushing ioContext", | |
414 (int32_t)this, error); | |
415 } | |
416 | |
417 // Roll back. | |
418 OutstandingCallCompleted(); | |
419 return -1; | |
420 } | |
421 | |
422 void UdpSocket2Windows::IOCompleted(PerIoContext* pIOContext, | |
423 uint32_t ioSize, uint32_t error) | |
424 { | |
425 if(pIOContext == NULL || error == ERROR_OPERATION_ABORTED) | |
426 { | |
427 if ((pIOContext != NULL) && | |
428 !pIOContext->ioInitiatedByPlatformThread && | |
429 (error == ERROR_OPERATION_ABORTED) && | |
430 (pIOContext->ioOperation == OP_READ) && | |
431 _outstandingCallsDisabled) | |
432 { | |
433 // !pIOContext->initiatedIOByPlatformThread indicate that the I/O | |
434 // was not initiated by a PlatformThread thread. | |
435 // This may happen if the thread that initiated receiving (e.g. | |
436 // by calling StartListen())) is deleted before any packets have | |
437 // been received. | |
438 // In this case there is no packet in the PerIoContext. Re-use it | |
439 // to post a new PostRecv(..). | |
440 // Note 1: the PerIoContext will henceforth be posted by a thread | |
441 // that is controlled by the socket implementation. | |
442 // Note 2: This is more likely to happen to RTCP packets as | |
443 // they are less frequent than RTP packets. | |
444 // Note 3: _outstandingCallsDisabled being false indicates | |
445 // that the socket isn't being shut down. | |
446 // Note 4: This should only happen buffers set to receive packets | |
447 // (OP_READ). | |
448 } else { | |
449 if(pIOContext == NULL) | |
450 { | |
451 WEBRTC_TRACE( | |
452 kTraceError, | |
453 kTraceTransport, | |
454 _id, | |
455 "UdpSocket2Windows::IOCompleted(%d,%d,%d), %d", | |
456 (int32_t)pIOContext, | |
457 ioSize, | |
458 error, | |
459 pIOContext ? (int32_t)pIOContext->ioOperation : -1); | |
460 } else { | |
461 WEBRTC_TRACE( | |
462 kTraceDebug, | |
463 kTraceTransport, | |
464 _id, | |
465 "UdpSocket2Windows::IOCompleted() Operation aborted"); | |
466 } | |
467 if(pIOContext) | |
468 { | |
469 int32_t remainingReceiveBuffers = --_receiveBuffers; | |
470 if(remainingReceiveBuffers < 0) | |
471 { | |
472 assert(false); | |
473 } | |
474 int32_t err = _mgr->PushIoContext(pIOContext); | |
475 if(err) | |
476 { | |
477 WEBRTC_TRACE( | |
478 kTraceError, | |
479 kTraceTransport, | |
480 _id, | |
481 "UdpSocket2Windows::IOCompleted(), err = %d, when\ | |
482 pushing ioContext after error", | |
483 err); | |
484 } | |
485 } | |
486 OutstandingCallCompleted(); | |
487 return; | |
488 } | |
489 } // if (pIOContext == NULL || error == ERROR_OPERATION_ABORTED) | |
490 | |
491 if(pIOContext->ioOperation == OP_WRITE) | |
492 { | |
493 _mgr->PushIoContext(pIOContext); | |
494 } | |
495 else if(pIOContext->ioOperation == OP_READ) | |
496 { | |
497 if(!error && ioSize != 0) | |
498 { | |
499 _ptrCbRWLock->AcquireLockShared(); | |
500 if(_wantsIncoming && _incomingCb) | |
501 { | |
502 _incomingCb(_obj, | |
503 reinterpret_cast<const int8_t*>( | |
504 pIOContext->wsabuf.buf), | |
505 ioSize, | |
506 &pIOContext->from); | |
507 } | |
508 _ptrCbRWLock->ReleaseLockShared(); | |
509 } | |
510 int32_t err = PostRecv(pIOContext); | |
511 if(err == 0) | |
512 { | |
513 // The PerIoContext was posted by a thread controlled by the socket | |
514 // implementation. | |
515 pIOContext->ioInitiatedByPlatformThread = true; | |
516 } | |
517 OutstandingCallCompleted(); | |
518 return; | |
519 } else { | |
520 // Unknown operation. Should not happen. Return pIOContext to avoid | |
521 // memory leak. | |
522 assert(false); | |
523 _mgr->PushIoContext(pIOContext); | |
524 } | |
525 OutstandingCallCompleted(); | |
526 // Don't touch any members after OutstandingCallCompleted() since the socket | |
527 // may be deleted at this point. | |
528 } | |
529 | |
530 int32_t UdpSocket2Windows::PostRecv() | |
531 { | |
532 PerIoContext* pIoContext=_mgr->PopIoContext(); | |
533 if(pIoContext == 0) | |
534 { | |
535 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
536 "UdpSocket2Windows(%d)::PostRecv(), pIoContext == 0", | |
537 (int32_t)this); | |
538 return -1; | |
539 } | |
540 // This function may have been called by thread not controlled by the socket | |
541 // implementation. | |
542 pIoContext->ioInitiatedByPlatformThread = false; | |
543 return PostRecv(pIoContext); | |
544 } | |
545 | |
546 int32_t UdpSocket2Windows::PostRecv(PerIoContext* pIoContext) | |
547 { | |
548 if(pIoContext==0) | |
549 { | |
550 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
551 "UdpSocket2Windows(%d)::PostRecv(?), pIoContext==0", | |
552 (int32_t)this); | |
553 return -1; | |
554 } | |
555 | |
556 DWORD numOfRecivedBytes = 0; | |
557 DWORD flags = 0; | |
558 pIoContext->wsabuf.buf = pIoContext->buffer; | |
559 pIoContext->wsabuf.len = sizeof(pIoContext->buffer); | |
560 pIoContext->fromLen = sizeof(SocketAddress); | |
561 pIoContext->ioOperation = OP_READ; | |
562 int32_t rxError = 0; | |
563 int32_t nRet = 0; | |
564 int32_t postingSucessfull = false; | |
565 | |
566 if(!AquireSocket()) | |
567 { | |
568 _mgr->PushIoContext(pIoContext); | |
569 return -1; | |
570 } | |
571 | |
572 // Assume that the WSARecvFrom() call will be successfull to make sure that | |
573 // _outstandingCalls is positive. Roll back if WSARecvFrom() failed. | |
574 if(!NewOutstandingCall()) | |
575 { | |
576 _mgr->PushIoContext(pIoContext); | |
577 ReleaseSocket(); | |
578 return -1; | |
579 } | |
580 for(int32_t tries = 0; tries < 10; tries++) | |
581 { | |
582 nRet = WSARecvFrom( | |
583 _socket, | |
584 &(pIoContext->wsabuf), | |
585 1, | |
586 &numOfRecivedBytes, | |
587 &flags, | |
588 reinterpret_cast<struct sockaddr*>(&(pIoContext->from)), | |
589 &(pIoContext->fromLen), | |
590 &(pIoContext->overlapped), | |
591 0); | |
592 | |
593 if( nRet == SOCKET_ERROR) | |
594 { | |
595 rxError = WSAGetLastError(); | |
596 if(rxError != ERROR_IO_PENDING) | |
597 { | |
598 WEBRTC_TRACE( | |
599 kTraceError, | |
600 kTraceTransport, | |
601 _id, | |
602 "UdpSocket2Windows(%d)::PostRecv(?), WSAerror:%d when\ | |
603 posting new recieve,trie:%d", | |
604 (int32_t)this, | |
605 rxError, | |
606 tries); | |
607 // Tell the OS that this is a good place to context switch if | |
608 // it wants to. | |
609 SleepMs(0); | |
610 } | |
611 } | |
612 if((rxError == ERROR_IO_PENDING) || (nRet == 0)) | |
613 { | |
614 postingSucessfull = true; | |
615 break; | |
616 } | |
617 } | |
618 ReleaseSocket(); | |
619 | |
620 if(postingSucessfull) | |
621 { | |
622 return 0; | |
623 } | |
624 int32_t remainingReceiveBuffers = --_receiveBuffers; | |
625 if(remainingReceiveBuffers < 0) | |
626 { | |
627 assert(false); | |
628 } | |
629 int32_t error = _mgr->PushIoContext(pIoContext); | |
630 if(error) | |
631 { | |
632 WEBRTC_TRACE( | |
633 kTraceError, | |
634 kTraceTransport, | |
635 _id, | |
636 "UdpSocket2Windows(%d)::PostRecv(?), error:%d when PushIoContext", | |
637 (int32_t)this, | |
638 error); | |
639 } | |
640 // Roll back. | |
641 OutstandingCallCompleted(); | |
642 return -1; | |
643 } | |
644 | |
645 void UdpSocket2Windows::CloseBlocking() | |
646 { | |
647 LINGER lingerStruct; | |
648 | |
649 lingerStruct.l_onoff = 1; | |
650 lingerStruct.l_linger = 0; | |
651 if(AquireSocket()) | |
652 { | |
653 setsockopt(_socket, SOL_SOCKET, SO_LINGER, | |
654 reinterpret_cast<const char*>(&lingerStruct), | |
655 sizeof(lingerStruct)); | |
656 ReleaseSocket(); | |
657 } | |
658 | |
659 _wantsIncoming = false; | |
660 // Reclaims the socket and prevents it from being used again. | |
661 InvalidateSocket(); | |
662 DisableNewOutstandingCalls(); | |
663 delete this; | |
664 } | |
665 | |
666 bool UdpSocket2Windows::SetQos(int32_t serviceType, | |
667 int32_t tokenRate, | |
668 int32_t bucketSize, | |
669 int32_t peekBandwith, | |
670 int32_t minPolicedSize, | |
671 int32_t maxSduSize, | |
672 const SocketAddress &stRemName, | |
673 int32_t overrideDSCP) | |
674 { | |
675 if(_qos == false) | |
676 { | |
677 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
678 "UdpSocket2Windows::SetQos(), socket not capable of QOS"); | |
679 return false; | |
680 } | |
681 if(overrideDSCP != 0) | |
682 { | |
683 FLOWSPEC f; | |
684 int32_t err = CreateFlowSpec(serviceType, tokenRate, bucketSize, | |
685 peekBandwith, minPolicedSize, | |
686 maxSduSize, &f); | |
687 if(err == -1) | |
688 { | |
689 return false; | |
690 } | |
691 | |
692 SocketAddress socketName; | |
693 struct sockaddr_in* name = | |
694 reinterpret_cast<struct sockaddr_in*>(&socketName); | |
695 int nameLength = sizeof(SocketAddress); | |
696 if(AquireSocket()) | |
697 { | |
698 getsockname(_socket, (struct sockaddr*)name, &nameLength); | |
699 ReleaseSocket(); | |
700 } | |
701 | |
702 if(serviceType == 0) | |
703 { | |
704 // Disable TOS byte setting. | |
705 return SetTrafficControl(0, -1, name, &f, &f) == 0; | |
706 } | |
707 return SetTrafficControl(overrideDSCP, -1, name, &f, &f) == 0; | |
708 } | |
709 | |
710 QOS Qos; | |
711 DWORD BytesRet; | |
712 QOS_DESTADDR QosDestaddr; | |
713 | |
714 memset (&Qos, QOS_NOT_SPECIFIED, sizeof(QOS)); | |
715 | |
716 Qos.SendingFlowspec.ServiceType = serviceType; | |
717 Qos.SendingFlowspec.TokenRate = tokenRate; | |
718 Qos.SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; | |
719 Qos.SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; | |
720 Qos.SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; | |
721 Qos.SendingFlowspec.Latency = QOS_NOT_SPECIFIED; | |
722 Qos.SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
723 Qos.SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; | |
724 | |
725 // Only ServiceType is needed for receiving. | |
726 Qos.ReceivingFlowspec.ServiceType = serviceType; | |
727 Qos.ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED; | |
728 Qos.ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; | |
729 Qos.ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; | |
730 Qos.ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED; | |
731 Qos.ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; | |
732 Qos.ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
733 Qos.ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; | |
734 | |
735 Qos.ProviderSpecific.len = 0; | |
736 | |
737 Qos.ProviderSpecific.buf = NULL; | |
738 | |
739 ZeroMemory((int8_t *)&QosDestaddr, sizeof(QosDestaddr)); | |
740 | |
741 OSVERSIONINFOEX osvie; | |
742 osvie.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); | |
743 GetVersionEx((LPOSVERSIONINFO)&osvie); | |
744 | |
745 // Operating system Version number dwMajorVersion dwMinorVersion | |
746 // Windows 7 6.1 6 1 | |
747 // Windows Server 2008 R2 6.1 6 1 | |
748 // Windows Server 2008 6.0 6 0 | |
749 // Windows Vista 6.0 6 0 | |
750 // Windows Server 2003 R2 5.2 5 2 | |
751 // Windows Server 2003 5.2 5 2 | |
752 // Windows XP 5.1 5 1 | |
753 // Windows 2000 5.0 5 0 | |
754 | |
755 // SERVICE_NO_QOS_SIGNALING and QOS_DESTADDR should not be used if version | |
756 // is 6.0 or greater. | |
757 if(osvie.dwMajorVersion >= 6) | |
758 { | |
759 Qos.SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
760 Qos.ReceivingFlowspec.ServiceType = serviceType; | |
761 | |
762 } else { | |
763 Qos.SendingFlowspec.MinimumPolicedSize = | |
764 QOS_NOT_SPECIFIED | SERVICE_NO_QOS_SIGNALING; | |
765 Qos.ReceivingFlowspec.ServiceType = | |
766 serviceType | SERVICE_NO_QOS_SIGNALING; | |
767 | |
768 QosDestaddr.ObjectHdr.ObjectType = QOS_OBJECT_DESTADDR; | |
769 QosDestaddr.ObjectHdr.ObjectLength = sizeof(QosDestaddr); | |
770 QosDestaddr.SocketAddress = (SOCKADDR *)&stRemName; | |
771 if (AF_INET6 == _iProtocol) | |
772 { | |
773 QosDestaddr.SocketAddressLength = sizeof(SocketAddressInVersion6); | |
774 } else { | |
775 QosDestaddr.SocketAddressLength = sizeof(SocketAddressIn); | |
776 } | |
777 | |
778 Qos.ProviderSpecific.len = QosDestaddr.ObjectHdr.ObjectLength; | |
779 Qos.ProviderSpecific.buf = (char*)&QosDestaddr; | |
780 } | |
781 | |
782 if(!AquireSocket()) { | |
783 return false; | |
784 } | |
785 // To set QoS with SIO_SET_QOS the socket must be locally bound first | |
786 // or the call will fail with error code 10022. | |
787 int32_t result = WSAIoctl(GetFd(), SIO_SET_QOS, &Qos, sizeof(QOS), | |
788 NULL, 0, &BytesRet, NULL,NULL); | |
789 ReleaseSocket(); | |
790 if (result == SOCKET_ERROR) | |
791 { | |
792 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
793 "UdpSocket2Windows::SetQos() WSAerror : %d", | |
794 WSAGetLastError()); | |
795 return false; | |
796 } | |
797 return true; | |
798 } | |
799 | |
800 int32_t UdpSocket2Windows::SetTOS(int32_t serviceType) | |
801 { | |
802 SocketAddress socketName; | |
803 | |
804 struct sockaddr_in* name = | |
805 reinterpret_cast<struct sockaddr_in*>(&socketName); | |
806 int nameLength = sizeof(SocketAddress); | |
807 if(AquireSocket()) | |
808 { | |
809 getsockname(_socket, (struct sockaddr*)name, &nameLength); | |
810 ReleaseSocket(); | |
811 } | |
812 | |
813 int32_t res = SetTrafficControl(serviceType, -1, name); | |
814 if (res == -1) | |
815 { | |
816 OSVERSIONINFO OsVersion; | |
817 OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
818 GetVersionEx (&OsVersion); | |
819 | |
820 if ((OsVersion.dwMajorVersion == 4)) // NT 4.0 | |
821 { | |
822 if(SetSockopt(IPPROTO_IP,IP_TOS , | |
823 (int8_t*)&serviceType, 4) != 0) | |
824 { | |
825 return -1; | |
826 } | |
827 } | |
828 } | |
829 return res; | |
830 } | |
831 | |
832 int32_t UdpSocket2Windows::SetPCP(int32_t pcp) | |
833 { | |
834 SocketAddress socketName; | |
835 struct sockaddr_in* name = | |
836 reinterpret_cast<struct sockaddr_in*>(&socketName); | |
837 int nameLength = sizeof(SocketAddress); | |
838 if(AquireSocket()) | |
839 { | |
840 getsockname(_socket, (struct sockaddr*)name, &nameLength); | |
841 ReleaseSocket(); | |
842 } | |
843 return SetTrafficControl(-1, pcp, name); | |
844 } | |
845 | |
846 int32_t UdpSocket2Windows::SetTrafficControl( | |
847 int32_t dscp, | |
848 int32_t pcp, | |
849 const struct sockaddr_in* name, | |
850 FLOWSPEC* send, FLOWSPEC* recv) | |
851 { | |
852 if (pcp == _pcp) | |
853 { | |
854 // No change. | |
855 pcp = -1; | |
856 } | |
857 if ((-1 == pcp) && (-1 == dscp)) | |
858 { | |
859 return 0; | |
860 } | |
861 if (!_gtc) | |
862 { | |
863 _gtc = TrafficControlWindows::GetInstance(_id); | |
864 } | |
865 if (!_gtc) | |
866 { | |
867 return -1; | |
868 } | |
869 if(_filterHandle) | |
870 { | |
871 _gtc->TcDeleteFilter(_filterHandle); | |
872 _filterHandle = NULL; | |
873 } | |
874 if(_flowHandle) | |
875 { | |
876 _gtc->TcDeleteFlow(_flowHandle); | |
877 _flowHandle = NULL; | |
878 } | |
879 if(_clientHandle) | |
880 { | |
881 _gtc->TcDeregisterClient(_clientHandle); | |
882 _clientHandle = NULL; | |
883 } | |
884 if ((0 == dscp) && (-2 == _pcp) && (-1 == pcp)) | |
885 { | |
886 // TODO (pwestin): why is this not done before deleting old filter and | |
887 // flow? This scenario should probably be documented in | |
888 // the function declaration. | |
889 return 0; | |
890 } | |
891 | |
892 TCI_CLIENT_FUNC_LIST QoSFunctions; | |
893 QoSFunctions.ClAddFlowCompleteHandler = NULL; | |
894 QoSFunctions.ClDeleteFlowCompleteHandler = NULL; | |
895 QoSFunctions.ClModifyFlowCompleteHandler = NULL; | |
896 QoSFunctions.ClNotifyHandler = (TCI_NOTIFY_HANDLER)MyClNotifyHandler; | |
897 // Register the client with Traffic control interface. | |
898 HANDLE ClientHandle; | |
899 ULONG result = _gtc->TcRegisterClient(CURRENT_TCI_VERSION, NULL, | |
900 &QoSFunctions,&ClientHandle); | |
901 if(result != NO_ERROR) | |
902 { | |
903 // This is likely caused by the application not being run as | |
904 // administrator. | |
905 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
906 "TcRegisterClient returned %d", result); | |
907 return result; | |
908 } | |
909 | |
910 // Find traffic control-enabled network interfaces that matches this | |
911 // socket's IP address. | |
912 ULONG BufferSize = 0; | |
913 result = _gtc->TcEnumerateInterfaces(ClientHandle, &BufferSize, NULL); | |
914 | |
915 if(result != NO_ERROR && result != ERROR_INSUFFICIENT_BUFFER) | |
916 { | |
917 _gtc->TcDeregisterClient(ClientHandle); | |
918 return result; | |
919 } | |
920 | |
921 if(result != ERROR_INSUFFICIENT_BUFFER) | |
922 { | |
923 // Empty buffer contains all control-enabled network interfaces. I.e. | |
924 // QoS is not enabled. | |
925 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
926 "QOS faild since QOS is not installed on the interface"); | |
927 | |
928 _gtc->TcDeregisterClient(ClientHandle); | |
929 return -1; | |
930 } | |
931 | |
932 PTC_IFC_DESCRIPTOR pInterfaceBuffer = | |
933 (PTC_IFC_DESCRIPTOR)malloc(BufferSize); | |
934 if(pInterfaceBuffer == NULL) | |
935 { | |
936 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
937 "Out ot memory failure"); | |
938 _gtc->TcDeregisterClient(ClientHandle); | |
939 return ERROR_NOT_ENOUGH_MEMORY; | |
940 } | |
941 | |
942 result = _gtc->TcEnumerateInterfaces(ClientHandle, &BufferSize, | |
943 pInterfaceBuffer); | |
944 | |
945 if(result != NO_ERROR) | |
946 { | |
947 WEBRTC_TRACE( | |
948 kTraceError, | |
949 kTraceTransport, | |
950 _id, | |
951 "Critical: error enumerating interfaces when passing in correct\ | |
952 buffer size: %d", result); | |
953 _gtc->TcDeregisterClient(ClientHandle); | |
954 free(pInterfaceBuffer); | |
955 return result; | |
956 } | |
957 | |
958 PTC_IFC_DESCRIPTOR oneinterface; | |
959 HANDLE ifcHandle, iFilterHandle, iflowHandle; | |
960 bool addrFound = false; | |
961 ULONG filterSourceAddress = ULONG_MAX; | |
962 | |
963 // Find the interface corresponding to the local address. | |
964 for(oneinterface = pInterfaceBuffer; | |
965 oneinterface != (PTC_IFC_DESCRIPTOR) | |
966 (((int8_t*)pInterfaceBuffer) + BufferSize); | |
967 oneinterface = (PTC_IFC_DESCRIPTOR) | |
968 ((int8_t *)oneinterface + oneinterface->Length)) | |
969 { | |
970 | |
971 char interfaceName[500]; | |
972 WideCharToMultiByte(CP_ACP, 0, oneinterface->pInterfaceName, -1, | |
973 interfaceName, sizeof(interfaceName), 0, 0 ); | |
974 | |
975 PNETWORK_ADDRESS_LIST addresses = | |
976 &(oneinterface->AddressListDesc.AddressList); | |
977 for(LONG i = 0; i < addresses->AddressCount ; i++) | |
978 { | |
979 // Only look at TCP/IP addresses. | |
980 if(addresses->Address[i].AddressType != NDIS_PROTOCOL_ID_TCP_IP) | |
981 { | |
982 continue; | |
983 } | |
984 | |
985 NETWORK_ADDRESS_IP* pIpAddr = | |
986 (NETWORK_ADDRESS_IP*)&(addresses->Address[i].Address); | |
987 struct in_addr in; | |
988 in.S_un.S_addr = pIpAddr->in_addr; | |
989 if(pIpAddr->in_addr == name->sin_addr.S_un.S_addr) | |
990 { | |
991 filterSourceAddress = pIpAddr->in_addr; | |
992 addrFound = true; | |
993 } | |
994 } | |
995 if(!addrFound) | |
996 { | |
997 continue; | |
998 } else | |
999 { | |
1000 break; | |
1001 } | |
1002 } | |
1003 if(!addrFound) | |
1004 { | |
1005 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
1006 "QOS faild since address is not found"); | |
1007 _gtc->TcDeregisterClient(ClientHandle); | |
1008 free(pInterfaceBuffer); | |
1009 return -1; | |
1010 } | |
1011 result = _gtc->TcOpenInterfaceW(oneinterface->pInterfaceName, ClientHandle, | |
1012 NULL, &ifcHandle); | |
1013 if(result != NO_ERROR) | |
1014 { | |
1015 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
1016 "Error opening interface: %d", result); | |
1017 _gtc->TcDeregisterClient(ClientHandle); | |
1018 free(pInterfaceBuffer); | |
1019 return result; | |
1020 } | |
1021 | |
1022 // Create flow if one doesn't exist. | |
1023 if (!_flow) | |
1024 { | |
1025 bool addPCP = ((pcp >= 0) || ((-1 == pcp) && (_pcp >= 0))); | |
1026 int allocSize = sizeof(TC_GEN_FLOW) + sizeof(QOS_DS_CLASS) + | |
1027 (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0); | |
1028 _flow = (PTC_GEN_FLOW)malloc(allocSize); | |
1029 | |
1030 _flow->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; | |
1031 _flow->SendingFlowspec.Latency = QOS_NOT_SPECIFIED; | |
1032 _flow->SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; | |
1033 _flow->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
1034 _flow->SendingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; | |
1035 _flow->SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; | |
1036 _flow->SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; | |
1037 _flow->SendingFlowspec.TokenRate = QOS_NOT_SPECIFIED; | |
1038 | |
1039 _flow->ReceivingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; | |
1040 _flow->ReceivingFlowspec.Latency = QOS_NOT_SPECIFIED; | |
1041 _flow->ReceivingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; | |
1042 _flow->ReceivingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
1043 _flow->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; | |
1044 _flow->ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; | |
1045 _flow->ReceivingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; | |
1046 _flow->ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED; | |
1047 | |
1048 QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects; | |
1049 dsClass->DSField = 0; | |
1050 dsClass->ObjectHdr.ObjectType = QOS_OBJECT_DS_CLASS; | |
1051 dsClass->ObjectHdr.ObjectLength = sizeof(QOS_DS_CLASS); | |
1052 | |
1053 if (addPCP) | |
1054 { | |
1055 QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1); | |
1056 trafficClass->TrafficClass = 0; | |
1057 trafficClass->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS; | |
1058 trafficClass->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS); | |
1059 } | |
1060 | |
1061 _flow->TcObjectsLength = sizeof(QOS_DS_CLASS) + | |
1062 (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0); | |
1063 } else if (-1 != pcp) { | |
1064 // Reallocate memory since pcp has changed. | |
1065 PTC_GEN_FLOW oldFlow = _flow; | |
1066 bool addPCP = (pcp >= 0); | |
1067 int allocSize = sizeof(TC_GEN_FLOW) + sizeof(QOS_DS_CLASS) + | |
1068 (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0); | |
1069 _flow = (PTC_GEN_FLOW)malloc(allocSize); | |
1070 | |
1071 // Copy old flow. | |
1072 _flow->ReceivingFlowspec = oldFlow->ReceivingFlowspec; | |
1073 _flow->SendingFlowspec = oldFlow->SendingFlowspec; | |
1074 // The DS info is always the first object. | |
1075 QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects; | |
1076 QOS_DS_CLASS* oldDsClass = (QOS_DS_CLASS*)oldFlow->TcObjects; | |
1077 dsClass->DSField = oldDsClass->DSField; | |
1078 dsClass->ObjectHdr.ObjectType = oldDsClass->ObjectHdr.ObjectType; | |
1079 dsClass->ObjectHdr.ObjectLength = oldDsClass->ObjectHdr.ObjectLength; | |
1080 | |
1081 if (addPCP) | |
1082 { | |
1083 QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1); | |
1084 trafficClass->TrafficClass = 0; | |
1085 trafficClass->ObjectHdr.ObjectType = QOS_OBJECT_TRAFFIC_CLASS; | |
1086 trafficClass->ObjectHdr.ObjectLength = sizeof(QOS_TRAFFIC_CLASS); | |
1087 } | |
1088 | |
1089 _flow->TcObjectsLength = sizeof(QOS_DS_CLASS) + | |
1090 (addPCP ? sizeof(QOS_TRAFFIC_CLASS) : 0); | |
1091 free(oldFlow); | |
1092 } | |
1093 | |
1094 // Setup send and receive flow and DS object. | |
1095 if (dscp >= 0) | |
1096 { | |
1097 if (!send || (0 == dscp)) | |
1098 { | |
1099 _flow->SendingFlowspec.DelayVariation = QOS_NOT_SPECIFIED; | |
1100 _flow->SendingFlowspec.Latency = QOS_NOT_SPECIFIED; | |
1101 _flow->SendingFlowspec.MaxSduSize = QOS_NOT_SPECIFIED; | |
1102 _flow->SendingFlowspec.MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
1103 _flow->SendingFlowspec.PeakBandwidth = | |
1104 (0 == dscp ? QOS_NOT_SPECIFIED : POSITIVE_INFINITY_RATE); | |
1105 _flow->SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; | |
1106 _flow->SendingFlowspec.TokenBucketSize = QOS_NOT_SPECIFIED; | |
1107 // 128000 * 10 is 10mbit/s. | |
1108 _flow->SendingFlowspec.TokenRate = | |
1109 (0 == dscp ? QOS_NOT_SPECIFIED : 128000 * 10); | |
1110 } | |
1111 else | |
1112 { | |
1113 _flow->SendingFlowspec.DelayVariation = send->DelayVariation; | |
1114 _flow->SendingFlowspec.Latency = send->Latency; | |
1115 _flow->SendingFlowspec.MaxSduSize = send->MaxSduSize; | |
1116 _flow->SendingFlowspec.MinimumPolicedSize = | |
1117 send->MinimumPolicedSize; | |
1118 _flow->SendingFlowspec.PeakBandwidth = send->PeakBandwidth; | |
1119 _flow->SendingFlowspec.PeakBandwidth = POSITIVE_INFINITY_RATE; | |
1120 _flow->SendingFlowspec.ServiceType = send->ServiceType; | |
1121 _flow->SendingFlowspec.TokenBucketSize = send->TokenBucketSize; | |
1122 _flow->SendingFlowspec.TokenRate = send->TokenRate; | |
1123 } | |
1124 | |
1125 if (!recv || (0 == dscp)) | |
1126 { | |
1127 _flow->ReceivingFlowspec.DelayVariation = | |
1128 _flow->SendingFlowspec.DelayVariation; | |
1129 _flow->ReceivingFlowspec.Latency = _flow->SendingFlowspec.Latency; | |
1130 _flow->ReceivingFlowspec.MaxSduSize = | |
1131 _flow->SendingFlowspec.MaxSduSize; | |
1132 _flow->ReceivingFlowspec.MinimumPolicedSize = | |
1133 _flow->SendingFlowspec.MinimumPolicedSize; | |
1134 _flow->ReceivingFlowspec.PeakBandwidth = QOS_NOT_SPECIFIED; | |
1135 _flow->ReceivingFlowspec.ServiceType = | |
1136 0 == dscp ? SERVICETYPE_BESTEFFORT : SERVICETYPE_CONTROLLEDLOAD; | |
1137 _flow->ReceivingFlowspec.TokenBucketSize = | |
1138 _flow->SendingFlowspec.TokenBucketSize; | |
1139 _flow->ReceivingFlowspec.TokenRate = | |
1140 _flow->SendingFlowspec.TokenRate; | |
1141 } else { | |
1142 _flow->ReceivingFlowspec.DelayVariation = recv->DelayVariation; | |
1143 _flow->ReceivingFlowspec.Latency = recv->Latency; | |
1144 _flow->ReceivingFlowspec.MaxSduSize = recv->MaxSduSize; | |
1145 _flow->ReceivingFlowspec.MinimumPolicedSize = | |
1146 recv->MinimumPolicedSize; | |
1147 _flow->ReceivingFlowspec.PeakBandwidth = recv->PeakBandwidth; | |
1148 _flow->ReceivingFlowspec.ServiceType = recv->ServiceType; | |
1149 _flow->ReceivingFlowspec.TokenBucketSize = recv->TokenBucketSize; | |
1150 _flow->ReceivingFlowspec.TokenRate = QOS_NOT_SPECIFIED; | |
1151 } | |
1152 | |
1153 // Setup DS (for DSCP value). | |
1154 // DS is always the first object. | |
1155 QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects; | |
1156 dsClass->DSField = dscp; | |
1157 } | |
1158 | |
1159 // Setup PCP (802.1p priority in 802.1Q/VLAN tagging) | |
1160 if (pcp >= 0) | |
1161 { | |
1162 // DS is always first object. | |
1163 QOS_DS_CLASS* dsClass = (QOS_DS_CLASS*)_flow->TcObjects; | |
1164 QOS_TRAFFIC_CLASS* trafficClass = (QOS_TRAFFIC_CLASS*)(dsClass + 1); | |
1165 trafficClass->TrafficClass = pcp; | |
1166 } | |
1167 | |
1168 result = _gtc->TcAddFlow(ifcHandle, NULL, 0, _flow, &iflowHandle); | |
1169 if(result != NO_ERROR) | |
1170 { | |
1171 _gtc->TcCloseInterface(ifcHandle); | |
1172 _gtc->TcDeregisterClient(ClientHandle); | |
1173 free(pInterfaceBuffer); | |
1174 return -1; | |
1175 } | |
1176 | |
1177 IP_PATTERN filterPattern, mask; | |
1178 | |
1179 ZeroMemory((int8_t*)&filterPattern, sizeof(IP_PATTERN)); | |
1180 ZeroMemory((int8_t*)&mask, sizeof(IP_PATTERN)); | |
1181 | |
1182 filterPattern.ProtocolId = IPPROTO_UDP; | |
1183 // "name" fields already in network order. | |
1184 filterPattern.S_un.S_un_ports.s_srcport = name->sin_port; | |
1185 filterPattern.SrcAddr = filterSourceAddress; | |
1186 | |
1187 // Unsigned max of a type corresponds to a bitmask with all bits set to 1. | |
1188 // I.e. the filter should allow all ProtocolIds, any source port and any | |
1189 // IP address | |
1190 mask.ProtocolId = UCHAR_MAX; | |
1191 mask.S_un.S_un_ports.s_srcport = USHRT_MAX; | |
1192 mask.SrcAddr = ULONG_MAX; | |
1193 | |
1194 TC_GEN_FILTER filter; | |
1195 | |
1196 filter.AddressType = NDIS_PROTOCOL_ID_TCP_IP; | |
1197 filter.Mask = (LPVOID)&mask; | |
1198 filter.Pattern = (LPVOID)&filterPattern; | |
1199 filter.PatternSize = sizeof(IP_PATTERN); | |
1200 | |
1201 result = _gtc->TcAddFilter(iflowHandle, &filter, &iFilterHandle); | |
1202 if(result != NO_ERROR) | |
1203 { | |
1204 _gtc->TcDeleteFlow(iflowHandle); | |
1205 _gtc->TcCloseInterface(ifcHandle); | |
1206 _gtc->TcDeregisterClient(ClientHandle); | |
1207 free(pInterfaceBuffer); | |
1208 return result; | |
1209 } | |
1210 | |
1211 _flowHandle = iflowHandle; | |
1212 _filterHandle = iFilterHandle; | |
1213 _clientHandle = ClientHandle; | |
1214 if (-1 != pcp) | |
1215 { | |
1216 _pcp = pcp; | |
1217 } | |
1218 | |
1219 _gtc->TcCloseInterface(ifcHandle); | |
1220 free(pInterfaceBuffer); | |
1221 | |
1222 return 0; | |
1223 } | |
1224 | |
1225 int32_t UdpSocket2Windows::CreateFlowSpec(int32_t serviceType, | |
1226 int32_t tokenRate, | |
1227 int32_t bucketSize, | |
1228 int32_t peekBandwith, | |
1229 int32_t minPolicedSize, | |
1230 int32_t maxSduSize, | |
1231 FLOWSPEC* f) | |
1232 { | |
1233 if (!f) | |
1234 { | |
1235 return -1; | |
1236 } | |
1237 | |
1238 f->ServiceType = serviceType; | |
1239 f->TokenRate = tokenRate; | |
1240 f->TokenBucketSize = QOS_NOT_SPECIFIED; | |
1241 f->PeakBandwidth = QOS_NOT_SPECIFIED; | |
1242 f->DelayVariation = QOS_NOT_SPECIFIED; | |
1243 f->Latency = QOS_NOT_SPECIFIED; | |
1244 f->MaxSduSize = QOS_NOT_SPECIFIED; | |
1245 f->MinimumPolicedSize = QOS_NOT_SPECIFIED; | |
1246 return 0; | |
1247 } | |
1248 | |
1249 bool UdpSocket2Windows::NewOutstandingCall() | |
1250 { | |
1251 assert(!_outstandingCallsDisabled); | |
1252 | |
1253 ++_outstandingCalls; | |
1254 return true; | |
1255 } | |
1256 | |
1257 void UdpSocket2Windows::OutstandingCallCompleted() | |
1258 { | |
1259 _ptrDestRWLock->AcquireLockShared(); | |
1260 ++_outstandingCallComplete; | |
1261 if((--_outstandingCalls == 0) && _outstandingCallsDisabled) | |
1262 { | |
1263 // When there are no outstanding calls and new outstanding calls are | |
1264 // disabled it is time to terminate. | |
1265 _terminate = true; | |
1266 } | |
1267 _ptrDestRWLock->ReleaseLockShared(); | |
1268 | |
1269 if((--_outstandingCallComplete == 0) && | |
1270 (_terminate)) | |
1271 { | |
1272 // Only one thread will enter here. The thread with the last outstanding | |
1273 // call. | |
1274 delete_event_.Set(); | |
1275 } | |
1276 } | |
1277 | |
1278 void UdpSocket2Windows::DisableNewOutstandingCalls() | |
1279 { | |
1280 _ptrDestRWLock->AcquireLockExclusive(); | |
1281 if(_outstandingCallsDisabled) | |
1282 { | |
1283 // Outstandning calls are already disabled. | |
1284 _ptrDestRWLock->ReleaseLockExclusive(); | |
1285 return; | |
1286 } | |
1287 _outstandingCallsDisabled = true; | |
1288 const bool noOutstandingCalls = (_outstandingCalls.Value() == 0); | |
1289 _ptrDestRWLock->ReleaseLockExclusive(); | |
1290 | |
1291 RemoveSocketFromManager(); | |
1292 | |
1293 if(noOutstandingCalls) | |
1294 { | |
1295 delete_event_.Set(); | |
1296 } | |
1297 } | |
1298 | |
1299 void UdpSocket2Windows::RemoveSocketFromManager() | |
1300 { | |
1301 // New outstanding calls should be disabled at this point. | |
1302 assert(_outstandingCallsDisabled); | |
1303 | |
1304 if(_addedToMgr) | |
1305 { | |
1306 WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, | |
1307 "calling UdpSocketManager::RemoveSocket()"); | |
1308 if(_mgr->RemoveSocket(this)) | |
1309 { | |
1310 _addedToMgr=false; | |
1311 } | |
1312 } | |
1313 } | |
1314 | |
1315 bool UdpSocket2Windows::AquireSocket() | |
1316 { | |
1317 _ptrSocketRWLock->AcquireLockShared(); | |
1318 const bool returnValue = _socket != INVALID_SOCKET; | |
1319 if(!returnValue) | |
1320 { | |
1321 _ptrSocketRWLock->ReleaseLockShared(); | |
1322 } | |
1323 return returnValue; | |
1324 } | |
1325 | |
1326 void UdpSocket2Windows::ReleaseSocket() | |
1327 { | |
1328 _ptrSocketRWLock->ReleaseLockShared(); | |
1329 } | |
1330 | |
1331 bool UdpSocket2Windows::InvalidateSocket() | |
1332 { | |
1333 _ptrSocketRWLock->AcquireLockExclusive(); | |
1334 if(_socket == INVALID_SOCKET) | |
1335 { | |
1336 _ptrSocketRWLock->ReleaseLockExclusive(); | |
1337 return true; | |
1338 } | |
1339 // Give the socket back to the system. All socket calls will fail from now | |
1340 // on. | |
1341 if(closesocket(_socket) == SOCKET_ERROR) | |
1342 { | |
1343 WEBRTC_TRACE(kTraceError, kTraceTransport, _id, | |
1344 "UdpSocket2Windows(%d)::InvalidateSocket() WSAerror: %d", | |
1345 (int32_t)this, WSAGetLastError()); | |
1346 } | |
1347 _socket = INVALID_SOCKET; | |
1348 _ptrSocketRWLock->ReleaseLockExclusive(); | |
1349 return true; | |
1350 } | |
1351 | |
1352 } // namespace test | |
1353 } // namespace webrtc | |
OLD | NEW |