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