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_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 |
| 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 |