int CUDTUnited::bind(const UDTSOCKET u, const UDPSOCKET* udpsaock, const sockaddr* name, int namelen) { CUDTSocket* s = locate(u); if (NULL == s) throw CUDTException(5, 4, 0); CGuard cg(s->m_ControlLock); // cannot bind a socket more than once if (INIT != s->m_Status) throw CUDTException(5, 0, 0); // check the size of SOCKADDR structure if (AF_INET == s->m_iIPversion) { if (namelen != sizeof(sockaddr_in)) throw CUDTException(5, 3, 0); } else { if (namelen != sizeof(sockaddr_in6)) throw CUDTException(5, 3, 0); } s->m_pUDT->open(); updateMux(s, name, udpsaock); s->m_Status = OPENED; // copy address information of local node s->m_pUDT->m_pSndQueue->m_pChannel->getSockAddr(s->m_pSelfAddr); return 0; }
void CChannel::setUDPSockOpt() { if ((0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char *)&m_iRcvBufSize, sizeof(int))) || (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char *)&m_iSndBufSize, sizeof(int)))) throw CUDTException(1, 3, NET_ERROR); timeval tv; tv.tv_sec = 0; #if defined (BSD) || defined (OSX) // Known BSD bug as the day I wrote this code. // A small time out value will cause the socket to block forever. tv.tv_usec = 10000; #else tv.tv_usec = 100; #endif #ifdef UNIX // Set non-blocking I/O // UNIX does not support SO_RCVTIMEO int opts = fcntl(m_iSocket, F_GETFL); if (-1 == fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) throw CUDTException(1, 3, NET_ERROR); #elif WIN32 DWORD ot = 1; //milliseconds if (setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeof(DWORD)) < 0) throw CUDTException(1, 3, NET_ERROR); #else // Set receiving time-out value if (setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval)) < 0) throw CUDTException(1, 3, NET_ERROR); #endif }
UDTSOCKET CUDTUnited::newSocket(int af, int type) { if ((type != SOCK_STREAM) && (type != SOCK_DGRAM)) throw CUDTException(5, 3, 0); CUDTSocket* ns = NULL; try { ns = new CUDTSocket; ns->m_pUDT = new CUDT; if (AF_INET == af) { ns->m_pSelfAddr = (sockaddr*)(new sockaddr_in); ((sockaddr_in*)(ns->m_pSelfAddr))->sin_port = 0; } else { ns->m_pSelfAddr = (sockaddr*)(new sockaddr_in6); ((sockaddr_in6*)(ns->m_pSelfAddr))->sin6_port = 0; } } catch (...) { delete ns; throw CUDTException(3, 2, 0); } CGuard::enterCS(m_IDLock); ns->m_SocketID = -- m_SocketID; CGuard::leaveCS(m_IDLock); ns->m_Status = INIT; ns->m_ListenSocket = 0; ns->m_pUDT->m_SocketID = ns->m_SocketID; ns->m_pUDT->m_iSockType = (SOCK_STREAM == type) ? UDT_STREAM : UDT_DGRAM; ns->m_pUDT->m_iIPversion = ns->m_iIPversion = af; ns->m_pUDT->m_pCache = m_pCache; // protect the m_Sockets structure. CGuard::enterCS(m_ControlLock); try { m_Sockets[ns->m_SocketID] = ns; } catch (...) { //failure and rollback CGuard::leaveCS(m_ControlLock); delete ns; ns = NULL; } CGuard::leaveCS(m_ControlLock); if (NULL == ns) throw CUDTException(3, 2, 0); return ns->m_SocketID; }
int CUDTUnited::postRecv(UDTSOCKET u, const sockaddr* addr, const char* buf, uint32_t len) { CUDTSocket* s = locate(u); if (NULL == s) throw CUDTException(5, 4, 0); s->m_pUDT->m_pRcvQueue->postRecv(addr, buf, len); return 0; }
int CUDTUnited::listen(const UDTSOCKET u, const sockaddr* peer, int backlog) { CUDTSocket* s = locate(u); if (NULL == s) throw CUDTException(5, 4, 0); CGuard cg(s->m_ControlLock); // do nothing if the socket is already listening if (LISTENING == s->m_Status) return 0; // a socket can listen only if is in OPENED status if (OPENED != s->m_Status) throw CUDTException(5, 5, 0); // listen is not supported in rendezvous connection setup if (s->m_pUDT->m_bRendezvous) throw CUDTException(5, 7, 0); if (backlog <= 0) throw CUDTException(5, 3, 0); s->m_uiBackLog = backlog; try { s->m_pQueuedSockets = new std::set<UDTSOCKET>; s->m_pAcceptSockets = new std::set<UDTSOCKET>; } catch (...) { delete s->m_pQueuedSockets; delete s->m_pAcceptSockets; throw CUDTException(3, 2, 0); } s->m_pUDT->listen(peer); s->m_Status = LISTENING; return 0; }
void CChannel::open(const sockaddr* addr) { // construct an socket m_iSocket = socket(m_iIPversion, SOCK_DGRAM, 0); #ifdef WIN32 if (INVALID_SOCKET == m_iSocket) #else if (m_iSocket < 0) #endif throw CUDTException(1, 0, NET_ERROR); if (NULL != addr) { socklen_t namelen = m_iSockAddrSize; if (0 != bind(m_iSocket, addr, namelen)) throw CUDTException(1, 3, NET_ERROR); } else { //sendto or WSASendTo will also automatically bind the socket addrinfo hints; addrinfo* res; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = m_iIPversion; hints.ai_socktype = SOCK_DGRAM; if (0 != getaddrinfo(NULL, "0", &hints, &res)) throw CUDTException(1, 3, NET_ERROR); if (0 != bind(m_iSocket, res->ai_addr, res->ai_addrlen)) throw CUDTException(1, 3, NET_ERROR); freeaddrinfo(res); } setUDPSockOpt(); }
void CChannel::setUDPSockOpt() { #if defined(BSD) || defined(OSX) // BSD system will fail setsockopt if the requested buffer size exceeds system maximum value int maxsize = 64000; if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int))) setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&maxsize, sizeof(int)); if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int))) setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&maxsize, sizeof(int)); #else // for other systems, if requested is greated than maximum, the maximum value will be automactally used if ((0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVBUF, (char*)&m_iRcvBufSize, sizeof(int))) || (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_SNDBUF, (char*)&m_iSndBufSize, sizeof(int)))) throw CUDTException(1, 3, NET_ERROR); #endif timeval tv; tv.tv_sec = 0; #if defined (BSD) || defined (OSX) // Known BSD bug as the day I wrote this code. // A small time out value will cause the socket to block forever. tv.tv_usec = 10000; #else tv.tv_usec = 100; #endif #ifdef UNIX // Set non-blocking I/O // UNIX does not support SO_RCVTIMEO int opts = fcntl(m_iSocket, F_GETFL); if (-1 == fcntl(m_iSocket, F_SETFL, opts | O_NONBLOCK)) throw CUDTException(1, 3, NET_ERROR); #elif WIN32 DWORD ot = 1; //milliseconds if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&ot, sizeof(DWORD))) throw CUDTException(1, 3, NET_ERROR); #else // Set receiving time-out value if (0 != setsockopt(m_iSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(timeval))) throw CUDTException(1, 3, NET_ERROR); #endif }
CUDT* CUDTUnited::lookup(const UDTSOCKET u) { // protects the m_Sockets structure CGuard cg(m_ControlLock); std::map<UDTSOCKET, CUDTSocket*>::iterator i = m_Sockets.find(u); if ((i == m_Sockets.end()) || (i->second->m_Status == CLOSED)) throw CUDTException(5, 4, 0); return i->second->m_pUDT; }
int CUDTUnited::connect(const UDTSOCKET u, const UDPSOCKET* udpsaock, const sockaddr* name, int namelen) { CUDTSocket* s = locate(u); if (NULL == s) throw CUDTException(5, 4, 0); CGuard cg(s->m_ControlLock); // check the size of SOCKADDR structure if (AF_INET == s->m_iIPversion) { if (namelen != sizeof(sockaddr_in)) throw CUDTException(5, 3, 0); } else { if (namelen != sizeof(sockaddr_in6)) throw CUDTException(5, 3, 0); } // a socket can "connect" only if it is in INIT or OPENED status if (INIT == s->m_Status) { if (!s->m_pUDT->m_bRendezvous) { s->m_pUDT->open(); updateMux(s, name, udpsaock); s->m_Status = OPENED; } else throw CUDTException(5, 8, 0); } else if (OPENED != s->m_Status) throw CUDTException(5, 2, 0); // connect_complete() may be called before connect() returns. // So we need to update the status before connect() is called, // otherwise the status may be overwritten with wrong value (CONNECTED vs. CONNECTING). s->m_Status = CONNECTING; try { s->m_pUDT->connect(name); } catch (CUDTException e) { s->m_Status = OPENED; throw e; } // record peer address delete s->m_pPeerAddr; if (AF_INET == s->m_iIPversion) { s->m_pPeerAddr = (sockaddr*)(new sockaddr_in); memcpy(s->m_pPeerAddr, name, sizeof(sockaddr_in)); } else { s->m_pPeerAddr = (sockaddr*)(new sockaddr_in6); memcpy(s->m_pPeerAddr, name, sizeof(sockaddr_in6)); } return 0; }