예제 #1
0
        public int bind(UDTSOCKET u, Socket udpsock)
        {
            UdtSocketInternal s = locate(u);

            if (null == s)
            {
                throw new UdtException(5, 4, 0);
            }

            lock (s.m_ControlLock)
            {
                // cannot bind a socket more than once
                if (UDTSTATUS.INIT != s.m_Status)
                {
                    throw new UdtException(5, 0, 0);
                }

                IPEndPoint name = (IPEndPoint)udpsock.LocalEndPoint;
                s.m_pUDT.open();
                updateMux(s, name, udpsock);
                s.m_Status = UDTSTATUS.OPENED;
                // copy address information of local node
                s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref s.m_pSelfAddr);
                return(0);
            }
        }
예제 #2
0
        public UDTSOCKET newSocket(AddressFamily af, SocketType type)
        {
            if ((type != SocketType.Stream) && (type != SocketType.Dgram))
            {
                throw new UdtException(5, 3, 0);
            }

            UdtSocketInternal ns = new UdtSocketInternal();

            ns.m_pUDT      = new UDT();
            ns.m_pSelfAddr = new IPEndPoint(IPAddress.Any, 0);

            lock (m_IDLock)
            {
                ns.m_SocketID = --m_SocketID;
            }

            ns.m_Status            = UDTSTATUS.INIT;
            ns.m_ListenSocket      = 0;
            ns.m_pUDT.m_SocketID   = ns.m_SocketID;
            ns.m_pUDT.m_iSockType  = type;
            ns.m_pUDT.m_iIPversion = af;
            ns.m_pUDT.m_pCache     = m_pCache;

            // protect the m_Sockets structure.
            lock (m_ControlLock)
            {
                m_Sockets[ns.m_SocketID] = ns;
            }

            return(ns.m_SocketID);
        }
예제 #3
0
        public int close(UDTSOCKET u)
        {
            UdtSocketInternal s = locate(u);

            if (null == s)
            {
                throw new UdtException(5, 4, 0);
            }

            lock (s.m_ControlLock)
            {
                if (s.m_Status == UDTSTATUS.LISTENING)
                {
                    if (s.m_pUDT.m_bBroken)
                    {
                        return(0);
                    }

                    s.m_TimeStamp      = Timer.getTime();
                    s.m_pUDT.m_bBroken = true;

                    // broadcast all "accept" waiting
                    s.m_AcceptCond.Set();

                    return(0);
                }

                s.m_pUDT.close();

                // synchronize with garbage collection.
                lock (m_ControlLock)
                {
                    // since "s" is located before m_ControlLock, locate it again in case it became invalid
                    if (!m_Sockets.TryGetValue(u, out s) || s.m_Status == UDTSTATUS.CLOSED)
                    {
                        return(0);
                    }

                    s.m_Status = UDTSTATUS.CLOSED;

                    // a socket will not be immediated removed when it is closed
                    // in order to prevent other methods from accessing invalid address
                    // a timer is started and the socket will be removed after approximately 1 second
                    s.m_TimeStamp = Timer.getTime();

                    m_Sockets.Remove(s.m_SocketID);
                    m_ClosedSockets.Add(s.m_SocketID, s);

                    Timer.triggerEvent();

                    return(0);
                }
            }
        }
예제 #4
0
        public int connect(UDTSOCKET u, IPEndPoint name)
        {
            UdtSocketInternal s = locate(u);

            if (null == s)
            {
                throw new UdtException(5, 4, 0);
            }

            lock (s.m_ControlLock)
            {
                // a socket can "connect" only if it is in INIT or UDTSTATUS.OPENED status
                if (UDTSTATUS.INIT == s.m_Status)
                {
                    if (!s.m_pUDT.m_bRendezvous)
                    {
                        s.m_pUDT.open();
                        updateMux(s);
                        s.m_Status = UDTSTATUS.OPENED;
                    }
                    else
                    {
                        throw new UdtException(5, 8, 0);
                    }
                }
                else if (UDTSTATUS.OPENED != s.m_Status)
                {
                    throw new UdtException(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 = UDTSTATUS.CONNECTING;
                try
                {
                    s.m_pUDT.connect(name);
                }
                catch (UdtException e)
                {
                    s.m_Status = UDTSTATUS.OPENED;
                    throw e;
                }

                // record peer address
                s.m_pPeerAddr = name;

                return(0);
            }
        }
예제 #5
0
        public void connect_complete(UDTSOCKET u)
        {
            UdtSocketInternal s = locate(u);

            if (null == s)
            {
                throw new UdtException(5, 4, 0);
            }

            // copy address information of local node
            // the local port must be correctly assigned BEFORE CUDT.connect(),
            // otherwise if connect() fails, the multiplexer cannot be located by garbage collection and will cause leak
            s.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref s.m_pSelfAddr);
            ConvertIPAddress.ToUintArray(s.m_pSelfAddr.Address, ref s.m_pUDT.m_piSelfIP);

            s.m_Status = UDTSTATUS.CONNECTED;
        }
예제 #6
0
        public int listen(UDTSOCKET u, int backlog)
        {
            UdtSocketInternal s = locate(u);

            if (null == s)
            {
                throw new UdtException(5, 4, 0);
            }

            lock (s.m_ControlLock)
            {
                // do nothing if the socket is already listening
                if (UDTSTATUS.LISTENING == s.m_Status)
                {
                    return(0);
                }

                // a socket can listen only if is in UDTSTATUS.OPENED status
                if (UDTSTATUS.OPENED != s.m_Status)
                {
                    throw new UdtException(5, 5, 0);
                }

                // listen is not supported in rendezvous connection setup
                if (s.m_pUDT.m_bRendezvous)
                {
                    throw new UdtException(5, 7, 0);
                }

                if (backlog <= 0)
                {
                    throw new UdtException(5, 3, 0);
                }

                s.m_uiBackLog = (uint)backlog;

                s.m_pQueuedSockets = new HashSet <UDTSOCKET>();
                s.m_pAcceptSockets = new HashSet <UDTSOCKET>();

                s.m_pUDT.listen();

                s.m_Status = UDTSTATUS.LISTENING;

                return(0);
            }
        }
예제 #7
0
        void updateMux(UdtSocketInternal s, UdtSocketInternal ls)
        {
            lock (m_ControlLock)
            {
                int port = ls.m_pSelfAddr.Port;

                // find the listener's address
                foreach (KeyValuePair <int, Multiplexer> item in m_mMultiplexer)
                {
                    if (item.Value.m_iPort == port)
                    {
                        // reuse the existing multiplexer
                        Multiplexer multiplexer = item.Value;
                        ++multiplexer.m_iRefCount;
                        s.m_pUDT.m_pSndQueue = multiplexer.m_pSndQueue;
                        s.m_pUDT.m_pRcvQueue = multiplexer.m_pRcvQueue;
                        s.m_iMuxID           = multiplexer.m_iID;
                        return;
                    }
                }
            }
        }
예제 #8
0
        //            void setError(UdtException e)
        //{
        //                CGuard tg(m_TLSLock);
        //                delete(UdtException *)TlsGetValue(m_TLSError);
        //                TlsSetValue(m_TLSError, e);
        //                m_mTLSRecord[GetCurrentThreadId()] = e;
        //            }

        //            UdtException getError()
        //{
        //                CGuard tg(m_TLSLock);
        //                if (null == TlsGetValue(m_TLSError))
        //                {
        //                    UdtException* e = new UdtException;
        //                    TlsSetValue(m_TLSError, e);
        //                    m_mTLSRecord[GetCurrentThreadId()] = e;
        //                }
        //                return (UdtException*)TlsGetValue(m_TLSError);
        //            }

        //            void checkTLSValue()
        //{
        //                CGuard tg(m_TLSLock);

        //                vector<DWORD> tbr;
        //                for (map<DWORD, UdtException*>.iterator i = m_mTLSRecord.begin(); i != m_mTLSRecord.end(); ++i)
        //                {
        //                    HANDLE h = OpenThread(THREAD_QUERY_INFORMATION, FALSE, i.first);
        //                    if (null == h)
        //                    {
        //                        tbr.push_back(i.first);
        //                        break;
        //                    }
        //                    if (WAIT_OBJECT_0 == WaitForSingleObject(h, 0))
        //                    {
        //                        delete i.second;
        //                        tbr.push_back(i.first);
        //                    }
        //                    CloseHandle(h);
        //                }
        //                for (vector<DWORD>.iterator j = tbr.begin(); j != tbr.end(); ++j)
        //                    m_mTLSRecord.erase(*j);
        //            }

        void updateMux(UdtSocketInternal s, IPEndPoint addr = null, Socket udpsock = null)
        {
            lock (m_ControlLock)
            {
                Multiplexer m;
                if ((s.m_pUDT.m_bReuseAddr) && (null != addr))
                {
                    int port = addr.Port;

                    // find a reusable address
                    foreach (KeyValuePair <int, Multiplexer> item in m_mMultiplexer)
                    {
                        // reuse the existing multiplexer
                        m = item.Value;
                        if ((m.m_iIPversion == s.m_pUDT.m_iIPversion) && (m.m_iMSS == s.m_pUDT.m_iMSS) && m.m_bReusable)
                        {
                            if (m.m_iPort == port)
                            {
                                // reuse the existing multiplexer
                                ++m.m_iRefCount;
                                s.m_pUDT.m_pSndQueue = m.m_pSndQueue;
                                s.m_pUDT.m_pRcvQueue = m.m_pRcvQueue;
                                s.m_iMuxID           = m.m_iID;
                                return;
                            }
                        }
                    }
                }

                // a new multiplexer is needed
                m              = new Multiplexer();
                m.m_iMSS       = s.m_pUDT.m_iMSS;
                m.m_iIPversion = s.m_pUDT.m_iIPversion;
                m.m_iRefCount  = 1;
                m.m_bReusable  = s.m_pUDT.m_bReuseAddr;
                m.m_iID        = s.m_SocketID;

                m.m_pChannel = new Channel(s.m_pUDT.m_iIPversion);
                m.m_pChannel.setSndBufSize(s.m_pUDT.m_iUDPSndBufSize);
                m.m_pChannel.setRcvBufSize(s.m_pUDT.m_iUDPRcvBufSize);

                try
                {
                    if (null != udpsock)
                    {
                        m.m_pChannel.open(udpsock);
                    }
                    else
                    {
                        m.m_pChannel.open(addr);
                    }
                }
                catch (UdtException e)
                {
                    m.m_pChannel.close();
                    throw e;
                }

                IPEndPoint sa = new IPEndPoint(IPAddress.Any, 0);
                m.m_pChannel.getSockAddr(ref sa);
                m.m_iPort = sa.Port;

                m.m_pTimer = new Timer();

                m.m_pSndQueue = new SndQueue();
                m.m_pSndQueue.init(m.m_pChannel, m.m_pTimer);
                m.m_pRcvQueue = new RcvQueue();
                m.m_pRcvQueue.init(32, s.m_pUDT.m_iPayloadSize, m.m_iIPversion, 1024, m.m_pChannel, m.m_pTimer);

                m_mMultiplexer[m.m_iID] = m;

                s.m_pUDT.m_pSndQueue = m.m_pSndQueue;
                s.m_pUDT.m_pRcvQueue = m.m_pRcvQueue;
                s.m_iMuxID           = m.m_iID;
            }
        }
예제 #9
0
        public UDTSOCKET accept(UDTSOCKET listen, ref IPEndPoint addr)
        {
            if (null != addr)
            {
                throw new UdtException(5, 3, 0);
            }

            UdtSocketInternal ls = locate(listen);

            if (ls == null)
            {
                throw new UdtException(5, 4, 0);
            }

            // the "listen" socket must be in UDTSTATUS.LISTENING status
            if (UDTSTATUS.LISTENING != ls.m_Status)
            {
                throw new UdtException(5, 6, 0);
            }

            // no "accept" in rendezvous connection setup
            if (ls.m_pUDT.m_bRendezvous)
            {
                throw new UdtException(5, 7, 0);
            }

            UDTSOCKET u        = UDT.INVALID_SOCK;
            bool      accepted = false;

            // !!only one conection can be set up each time!!
            while (!accepted)
            {
                lock (ls.m_AcceptLock)
                {
                    if (ls.m_pQueuedSockets.Count > 0)
                    {
                        HashSet <UDTSOCKET> .Enumerator e = ls.m_pQueuedSockets.GetEnumerator();
                        e.MoveNext();
                        u = e.Current;
                        ls.m_pAcceptSockets.Add(u);
                        ls.m_pQueuedSockets.Remove(u);

                        accepted = true;
                    }
                    else if (!ls.m_pUDT.m_bSynRecving)
                    {
                        accepted = true;
                    }
                }

                if (!accepted & (UDTSTATUS.LISTENING == ls.m_Status))
                {
                    ls.m_AcceptCond.WaitOne(Timeout.Infinite);
                }

                if ((UDTSTATUS.LISTENING != ls.m_Status) || ls.m_pUDT.m_bBroken)
                {
                    // Send signal to other threads that are waiting to accept.
                    ls.m_AcceptCond.Set();
                    accepted = true;
                }

                //if (ls.m_pQueuedSockets.Count == 0)
                //    m_EPoll.update_events(listen, ls.m_pUDT.m_sPollID, UDT_EPOLL_IN, false);
            }

            if (u == UDT.INVALID_SOCK)
            {
                // non-blocking receiving, no connection available
                if (!ls.m_pUDT.m_bSynRecving)
                {
                    throw new UdtException(6, 2, 0);
                }

                // listening socket is closed
                throw new UdtException(5, 6, 0);
            }

            addr = locate(u).m_pPeerAddr;

            return(u);
        }
예제 #10
0
        public int newConnection(UDTSOCKET listen, IPEndPoint peer, Handshake hs)
        {
            UdtSocketInternal ns = null;
            UdtSocketInternal ls = locate(listen);

            if (null == ls)
            {
                return(-1);
            }

            // if this connection has already been processed
            if (null != (ns = locate(peer, hs.m_iID, hs.m_iISN)))
            {
                if (ns.m_pUDT.m_bBroken)
                {
                    // last connection from the "peer" address has been broken
                    ns.m_Status    = UDTSTATUS.CLOSED;
                    ns.m_TimeStamp = Timer.getTime();

                    lock (ls.m_AcceptLock)
                    {
                        ls.m_pQueuedSockets.Remove(ns.m_SocketID);
                        ls.m_pAcceptSockets.Remove(ns.m_SocketID);
                    }
                }
                else
                {
                    // connection already exist, this is a repeated connection request
                    // respond with existing HS information

                    hs.m_iISN            = ns.m_pUDT.m_iISN;
                    hs.m_iMSS            = ns.m_pUDT.m_iMSS;
                    hs.m_iFlightFlagSize = ns.m_pUDT.m_iFlightFlagSize;
                    hs.m_iReqType        = -1;
                    hs.m_iID             = ns.m_SocketID;

                    return(0);

                    //except for this situation a new connection should be started
                }
            }

            // exceeding backlog, refuse the connection request
            if (ls.m_pQueuedSockets.Count >= ls.m_uiBackLog)
            {
                return(-1);
            }

            ns             = new UdtSocketInternal();
            ns.m_pUDT      = new UDT(ls.m_pUDT);
            ns.m_pSelfAddr = new IPEndPoint(IPAddress.Any, 0);
            ns.m_pPeerAddr = peer;

            lock (m_IDLock)
            {
                ns.m_SocketID = --m_SocketID;
            }

            ns.m_ListenSocket    = listen;
            ns.m_iIPversion      = ls.m_iIPversion;
            ns.m_pUDT.m_SocketID = ns.m_SocketID;
            ns.m_PeerID          = hs.m_iID;
            ns.m_iISN            = hs.m_iISN;

            int error = 0;

            try
            {
                // bind to the same addr of listening socket
                ns.m_pUDT.open();
                updateMux(ns, ls);
                ns.m_pUDT.connect(peer, hs);
            }
            catch (Exception e)
            {
                error = 1;
                goto ERR_ROLLBACK;
            }

            ns.m_Status = UDTSTATUS.CONNECTED;

            // copy address information of local node
            ns.m_pUDT.m_pSndQueue.m_pChannel.getSockAddr(ref ns.m_pSelfAddr);
            ConvertIPAddress.ToUintArray(ns.m_pSelfAddr.Address, ref ns.m_pUDT.m_piSelfIP);

            // protect the m_Sockets structure.
            lock (m_ControlLock)
            {
                m_Sockets[ns.m_SocketID] = ns;
                HashSet <int> sockets;
                if (!m_PeerRec.TryGetValue((ns.m_PeerID << 30) + ns.m_iISN, out sockets))
                {
                    sockets = new HashSet <int>();
                    m_PeerRec.Add((ns.m_PeerID << 30) + ns.m_iISN, sockets);
                }

                sockets.Add(ns.m_SocketID);
            }

            lock (ls.m_AcceptLock)
            {
                ls.m_pQueuedSockets.Add(ns.m_SocketID);
            }

            // acknowledge users waiting for new connections on the listening socket
            //m_EPoll.update_events(listen, ls.m_pUDT.m_sPollID, UDT_EPOLL_IN, true);

            Timer.triggerEvent();

ERR_ROLLBACK:
            if (error > 0)
            {
                ns.m_pUDT.close();
                ns.m_Status    = UDTSTATUS.CLOSED;
                ns.m_TimeStamp = Timer.getTime();

                return(-1);
            }

            // wake up a waiting accept() call
            ls.m_AcceptCond.Set();

            return(1);
        }