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