| /* |
| * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "webrtc/test/channel_transport/udp_socket_posix.h" |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <netdb.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <sys/ioctl.h> |
| #include <sys/types.h> |
| #include <time.h> |
| #include <unistd.h> |
| |
| #include "webrtc/system_wrappers/include/trace.h" |
| #include "webrtc/test/channel_transport/udp_socket_manager_wrapper.h" |
| #include "webrtc/test/channel_transport/udp_socket_wrapper.h" |
| |
| namespace webrtc { |
| namespace test { |
| UdpSocketPosix::UdpSocketPosix(const int32_t id, UdpSocketManager* mgr, |
| bool ipV6Enable) : _id(id) |
| { |
| WEBRTC_TRACE(kTraceMemory, kTraceTransport, id, |
| "UdpSocketPosix::UdpSocketPosix()"); |
| |
| _wantsIncoming = false; |
| _mgr = mgr; |
| |
| _obj = NULL; |
| _incomingCb = NULL; |
| _readyForDeletionCond = ConditionVariableWrapper::CreateConditionVariable(); |
| _closeBlockingCompletedCond = |
| ConditionVariableWrapper::CreateConditionVariable(); |
| _cs = CriticalSectionWrapper::CreateCriticalSection(); |
| _readyForDeletion = false; |
| _closeBlockingActive = false; |
| _closeBlockingCompleted= false; |
| if(ipV6Enable) |
| { |
| _socket = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); |
| } |
| else { |
| _socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| } |
| |
| // Set socket to nonblocking mode. |
| int enable_non_blocking = 1; |
| if(ioctl(_socket, FIONBIO, &enable_non_blocking) == -1) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, id, |
| "Failed to make socket nonblocking"); |
| } |
| // Enable close on fork for file descriptor so that it will not block until |
| // forked process terminates. |
| if(fcntl(_socket, F_SETFD, FD_CLOEXEC) == -1) |
| { |
| WEBRTC_TRACE(kTraceWarning, kTraceTransport, id, |
| "Failed to set FD_CLOEXEC for socket"); |
| } |
| } |
| |
| UdpSocketPosix::~UdpSocketPosix() |
| { |
| if(_socket != INVALID_SOCKET) |
| { |
| close(_socket); |
| _socket = INVALID_SOCKET; |
| } |
| if(_readyForDeletionCond) |
| { |
| delete _readyForDeletionCond; |
| } |
| |
| if(_closeBlockingCompletedCond) |
| { |
| delete _closeBlockingCompletedCond; |
| } |
| |
| if(_cs) |
| { |
| delete _cs; |
| } |
| } |
| |
| bool UdpSocketPosix::SetCallback(CallbackObj obj, IncomingSocketCallback cb) |
| { |
| _obj = obj; |
| _incomingCb = cb; |
| |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "UdpSocketPosix(%p)::SetCallback", this); |
| |
| if (_mgr->AddSocket(this)) |
| { |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "UdpSocketPosix(%p)::SetCallback socket added to manager", |
| this); |
| return true; // socket is now ready for action |
| } |
| |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "UdpSocketPosix(%p)::SetCallback error adding me to mgr", |
| this); |
| return false; |
| } |
| |
| bool UdpSocketPosix::SetSockopt(int32_t level, int32_t optname, |
| const int8_t* optval, int32_t optlen) |
| { |
| if(0 == setsockopt(_socket, level, optname, optval, optlen )) |
| { |
| return true; |
| } |
| |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "UdpSocketPosix::SetSockopt(), error:%d", errno); |
| return false; |
| } |
| |
| int32_t UdpSocketPosix::SetTOS(int32_t serviceType) |
| { |
| if (SetSockopt(IPPROTO_IP, IP_TOS ,(int8_t*)&serviceType ,4) != 0) |
| { |
| return -1; |
| } |
| return 0; |
| } |
| |
| bool UdpSocketPosix::Bind(const SocketAddress& name) |
| { |
| int size = sizeof(sockaddr); |
| if (0 == bind(_socket, reinterpret_cast<const sockaddr*>(&name),size)) |
| { |
| return true; |
| } |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "UdpSocketPosix::Bind() error: %d", errno); |
| return false; |
| } |
| |
| int32_t UdpSocketPosix::SendTo(const int8_t* buf, size_t len, |
| const SocketAddress& to) |
| { |
| int size = sizeof(sockaddr); |
| int retVal = sendto(_socket,buf, len, 0, |
| reinterpret_cast<const sockaddr*>(&to), size); |
| if(retVal == SOCKET_ERROR) |
| { |
| WEBRTC_TRACE(kTraceError, kTraceTransport, _id, |
| "UdpSocketPosix::SendTo() error: %d", errno); |
| } |
| |
| return retVal; |
| } |
| |
| SOCKET UdpSocketPosix::GetFd() { return _socket; } |
| |
| bool UdpSocketPosix::ValidHandle() |
| { |
| return _socket != INVALID_SOCKET; |
| } |
| |
| bool UdpSocketPosix::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*/) { |
| return false; |
| } |
| |
| void UdpSocketPosix::HasIncoming() |
| { |
| // replace 2048 with a mcro define and figure out |
| // where 2048 comes from |
| int8_t buf[2048]; |
| int retval; |
| SocketAddress from; |
| #if defined(WEBRTC_MAC) |
| sockaddr sockaddrfrom; |
| memset(&from, 0, sizeof(from)); |
| memset(&sockaddrfrom, 0, sizeof(sockaddrfrom)); |
| socklen_t fromlen = sizeof(sockaddrfrom); |
| #else |
| memset(&from, 0, sizeof(from)); |
| socklen_t fromlen = sizeof(from); |
| #endif |
| |
| #if defined(WEBRTC_MAC) |
| retval = recvfrom(_socket,buf, sizeof(buf), 0, |
| reinterpret_cast<sockaddr*>(&sockaddrfrom), &fromlen); |
| memcpy(&from, &sockaddrfrom, fromlen); |
| from._sockaddr_storage.sin_family = sockaddrfrom.sa_family; |
| #else |
| retval = recvfrom(_socket,buf, sizeof(buf), 0, |
| reinterpret_cast<sockaddr*>(&from), &fromlen); |
| #endif |
| |
| switch(retval) |
| { |
| case 0: |
| // The peer has performed an orderly shutdown. |
| break; |
| case SOCKET_ERROR: |
| break; |
| default: |
| if (_wantsIncoming && _incomingCb) |
| { |
| _incomingCb(_obj, buf, retval, &from); |
| } |
| break; |
| } |
| } |
| |
| bool UdpSocketPosix::WantsIncoming() { return _wantsIncoming; } |
| |
| void UdpSocketPosix::CloseBlocking() |
| { |
| _cs->Enter(); |
| _closeBlockingActive = true; |
| if(!CleanUp()) |
| { |
| _closeBlockingActive = false; |
| _cs->Leave(); |
| return; |
| } |
| |
| while(!_readyForDeletion) |
| { |
| _readyForDeletionCond->SleepCS(*_cs); |
| } |
| _closeBlockingCompleted = true; |
| _closeBlockingCompletedCond->Wake(); |
| _cs->Leave(); |
| } |
| |
| void UdpSocketPosix::ReadyForDeletion() |
| { |
| _cs->Enter(); |
| if(!_closeBlockingActive) |
| { |
| _cs->Leave(); |
| return; |
| } |
| close(_socket); |
| _socket = INVALID_SOCKET; |
| _readyForDeletion = true; |
| _readyForDeletionCond->Wake(); |
| while(!_closeBlockingCompleted) |
| { |
| _closeBlockingCompletedCond->SleepCS(*_cs); |
| } |
| _cs->Leave(); |
| } |
| |
| bool UdpSocketPosix::CleanUp() |
| { |
| _wantsIncoming = false; |
| |
| if (_socket == INVALID_SOCKET) |
| { |
| return false; |
| } |
| |
| WEBRTC_TRACE(kTraceDebug, kTraceTransport, _id, |
| "calling UdpSocketManager::RemoveSocket()..."); |
| _mgr->RemoveSocket(this); |
| // After this, the socket should may be or will be as deleted. Return |
| // immediately. |
| return true; |
| } |
| |
| } // namespace test |
| } // namespace webrtc |