mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			300 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			300 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * SRT - Secure, Reliable, Transport
 | 
						|
 * Copyright (c) 2018 Haivision Systems Inc.
 | 
						|
 * 
 | 
						|
 * This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 | 
						|
 * 
 | 
						|
 */
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
Copyright (c) 2001 - 2010, The Board of Trustees of the University of Illinois.
 | 
						|
All rights reserved.
 | 
						|
 | 
						|
Redistribution and use in source and binary forms, with or without
 | 
						|
modification, are permitted provided that the following conditions are
 | 
						|
met:
 | 
						|
 | 
						|
* Redistributions of source code must retain the above
 | 
						|
  copyright notice, this list of conditions and the
 | 
						|
  following disclaimer.
 | 
						|
 | 
						|
* Redistributions in binary form must reproduce the
 | 
						|
  above copyright notice, this list of conditions
 | 
						|
  and the following disclaimer in the documentation
 | 
						|
  and/or other materials provided with the distribution.
 | 
						|
 | 
						|
* Neither the name of the University of Illinois
 | 
						|
  nor the names of its contributors may be used to
 | 
						|
  endorse or promote products derived from this
 | 
						|
  software without specific prior written permission.
 | 
						|
 | 
						|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 | 
						|
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 | 
						|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | 
						|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
						|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
						|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
						|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
						|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
						|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
						|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
						|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
/*****************************************************************************
 | 
						|
written by
 | 
						|
   Yunhong Gu, last updated 09/28/2010
 | 
						|
modified by
 | 
						|
   Haivision Systems Inc.
 | 
						|
*****************************************************************************/
 | 
						|
 | 
						|
#ifndef __UDT_API_H__
 | 
						|
#define __UDT_API_H__
 | 
						|
 | 
						|
 | 
						|
#include <map>
 | 
						|
#include <vector>
 | 
						|
#include <string>
 | 
						|
#include "netinet_any.h"
 | 
						|
#include "udt.h"
 | 
						|
#include "packet.h"
 | 
						|
#include "queue.h"
 | 
						|
#include "cache.h"
 | 
						|
#include "epoll.h"
 | 
						|
#include "handshake.h"
 | 
						|
 | 
						|
class CUDT;
 | 
						|
 | 
						|
class CUDTSocket
 | 
						|
{
 | 
						|
public:
 | 
						|
   CUDTSocket();
 | 
						|
   ~CUDTSocket();
 | 
						|
 | 
						|
   SRT_SOCKSTATUS m_Status;                  //< current socket state
 | 
						|
 | 
						|
   /// Time when the socket is closed.
 | 
						|
   /// When the socket is closed, it is not removed immediately from the list
 | 
						|
   /// of sockets in order to prevent other methods from accessing invalid address.
 | 
						|
   /// A timer is started and the socket will be removed after approximately
 | 
						|
   /// 1 second (see CUDTUnited::checkBrokenSockets()).
 | 
						|
   uint64_t m_ClosureTimeStamp;
 | 
						|
 | 
						|
   int m_iIPversion;                         //< IP version
 | 
						|
   sockaddr* m_pSelfAddr;                    //< pointer to the local address of the socket
 | 
						|
   sockaddr* m_pPeerAddr;                    //< pointer to the peer address of the socket
 | 
						|
 | 
						|
   SRTSOCKET m_SocketID;                     //< socket ID
 | 
						|
   SRTSOCKET m_ListenSocket;                 //< ID of the listener socket; 0 means this is an independent socket
 | 
						|
 | 
						|
   SRTSOCKET m_PeerID;                       //< peer socket ID
 | 
						|
   int32_t m_iISN;                           //< initial sequence number, used to tell different connection from same IP:port
 | 
						|
 | 
						|
   CUDT* m_pUDT;                             //< pointer to the UDT entity
 | 
						|
 | 
						|
   std::set<SRTSOCKET>* m_pQueuedSockets;    //< set of connections waiting for accept()
 | 
						|
   std::set<SRTSOCKET>* m_pAcceptSockets;    //< set of accept()ed connections
 | 
						|
 | 
						|
   pthread_cond_t m_AcceptCond;              //< used to block "accept" call
 | 
						|
   pthread_mutex_t m_AcceptLock;             //< mutex associated to m_AcceptCond
 | 
						|
 | 
						|
   unsigned int m_uiBackLog;                 //< maximum number of connections in queue
 | 
						|
 | 
						|
   int m_iMuxID;                             //< multiplexer ID
 | 
						|
 | 
						|
   pthread_mutex_t m_ControlLock;            //< lock this socket exclusively for control APIs: bind/listen/connect
 | 
						|
 | 
						|
   static int64_t getPeerSpec(SRTSOCKET id, int32_t isn)
 | 
						|
   {
 | 
						|
       return (id << 30) + isn;
 | 
						|
   }
 | 
						|
   int64_t getPeerSpec()
 | 
						|
   {
 | 
						|
       return getPeerSpec(m_PeerID, m_iISN);
 | 
						|
   }
 | 
						|
 | 
						|
private:
 | 
						|
   CUDTSocket(const CUDTSocket&);
 | 
						|
   CUDTSocket& operator=(const CUDTSocket&);
 | 
						|
};
 | 
						|
 | 
						|
////////////////////////////////////////////////////////////////////////////////
 | 
						|
 | 
						|
class CUDTUnited
 | 
						|
{
 | 
						|
friend class CUDT;
 | 
						|
friend class CRendezvousQueue;
 | 
						|
 | 
						|
public:
 | 
						|
   CUDTUnited();
 | 
						|
   ~CUDTUnited();
 | 
						|
 | 
						|
public:
 | 
						|
 | 
						|
   static std::string CONID(SRTSOCKET sock);
 | 
						|
 | 
						|
      /// initialize the UDT library.
 | 
						|
      /// @return 0 if success, otherwise -1 is returned.
 | 
						|
 | 
						|
   int startup();
 | 
						|
 | 
						|
      /// release the UDT library.
 | 
						|
      /// @return 0 if success, otherwise -1 is returned.
 | 
						|
 | 
						|
   int cleanup();
 | 
						|
 | 
						|
      /// Create a new UDT socket.
 | 
						|
      /// @param [in] af IP version, IPv4 (AF_INET) or IPv6 (AF_INET6).
 | 
						|
      /// @param [in] type (ignored)
 | 
						|
      /// @return The new UDT socket ID, or INVALID_SOCK.
 | 
						|
 | 
						|
   SRTSOCKET newSocket(int af, int );
 | 
						|
 | 
						|
      /// Create a new UDT connection.
 | 
						|
      /// @param [in] listen the listening UDT socket;
 | 
						|
      /// @param [in] peer peer address.
 | 
						|
      /// @param [in,out] hs handshake information from peer side (in), negotiated value (out);
 | 
						|
      /// @return If the new connection is successfully created: 1 success, 0 already exist, -1 error.
 | 
						|
 | 
						|
   int newConnection(const SRTSOCKET listen, const sockaddr* peer, CHandShake* hs, const CPacket& hspkt,
 | 
						|
           ref_t<SRT_REJECT_REASON> r_error);
 | 
						|
 | 
						|
   int installAcceptHook(const SRTSOCKET lsn, srt_listen_callback_fn* hook, void* opaq);
 | 
						|
 | 
						|
      /// look up the UDT entity according to its ID.
 | 
						|
      /// @param [in] u the UDT socket ID.
 | 
						|
      /// @return Pointer to the UDT entity.
 | 
						|
 | 
						|
   CUDT* lookup(const SRTSOCKET u);
 | 
						|
 | 
						|
      /// Check the status of the UDT socket.
 | 
						|
      /// @param [in] u the UDT socket ID.
 | 
						|
      /// @return UDT socket status, or NONEXIST if not found.
 | 
						|
 | 
						|
   SRT_SOCKSTATUS getStatus(const SRTSOCKET u);
 | 
						|
 | 
						|
      // socket APIs
 | 
						|
 | 
						|
   int bind(const SRTSOCKET u, const sockaddr* name, int namelen);
 | 
						|
   int bind(const SRTSOCKET u, UDPSOCKET udpsock);
 | 
						|
   int listen(const SRTSOCKET u, int backlog);
 | 
						|
   SRTSOCKET accept(const SRTSOCKET listen, sockaddr* addr, int* addrlen);
 | 
						|
   int connect(const SRTSOCKET u, const sockaddr* name, int namelen, int32_t forced_isn);
 | 
						|
   int close(const SRTSOCKET u);
 | 
						|
   int getpeername(const SRTSOCKET u, sockaddr* name, int* namelen);
 | 
						|
   int getsockname(const SRTSOCKET u, sockaddr* name, int* namelen);
 | 
						|
   int select(ud_set* readfds, ud_set* writefds, ud_set* exceptfds, const timeval* timeout);
 | 
						|
   int selectEx(const std::vector<SRTSOCKET>& fds, std::vector<SRTSOCKET>* readfds, std::vector<SRTSOCKET>* writefds, std::vector<SRTSOCKET>* exceptfds, int64_t msTimeOut);
 | 
						|
   int epoll_create();
 | 
						|
   int epoll_add_usock(const int eid, const SRTSOCKET u, const int* events = NULL);
 | 
						|
   int epoll_add_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
 | 
						|
   int epoll_remove_usock(const int eid, const SRTSOCKET u);
 | 
						|
   int epoll_remove_ssock(const int eid, const SYSSOCKET s);
 | 
						|
   int epoll_update_usock(const int eid, const SRTSOCKET u, const int* events = NULL);
 | 
						|
   int epoll_update_ssock(const int eid, const SYSSOCKET s, const int* events = NULL);
 | 
						|
   int epoll_wait(const int eid, std::set<SRTSOCKET>* readfds, std::set<SRTSOCKET>* writefds, int64_t msTimeOut, std::set<SYSSOCKET>* lrfds = NULL, std::set<SYSSOCKET>* lwfds = NULL);
 | 
						|
   int epoll_uwait(const int eid, SRT_EPOLL_EVENT* fdsSet, int fdsSize, int64_t msTimeOut);
 | 
						|
   int32_t epoll_set(const int eid, int32_t flags);
 | 
						|
   int epoll_release(const int eid);
 | 
						|
 | 
						|
      /// record the UDT exception.
 | 
						|
      /// @param [in] e pointer to a UDT exception instance.
 | 
						|
 | 
						|
   void setError(CUDTException* e);
 | 
						|
 | 
						|
      /// look up the most recent UDT exception.
 | 
						|
      /// @return pointer to a UDT exception instance.
 | 
						|
 | 
						|
   CUDTException* getError();
 | 
						|
 | 
						|
private:
 | 
						|
//   void init();
 | 
						|
 | 
						|
private:
 | 
						|
   std::map<SRTSOCKET, CUDTSocket*> m_Sockets;       // stores all the socket structures
 | 
						|
 | 
						|
   pthread_mutex_t m_ControlLock;                    // used to synchronize UDT API
 | 
						|
 | 
						|
   pthread_mutex_t m_IDLock;                         // used to synchronize ID generation
 | 
						|
   SRTSOCKET m_SocketIDGenerator;                             // seed to generate a new unique socket ID
 | 
						|
 | 
						|
   std::map<int64_t, std::set<SRTSOCKET> > m_PeerRec;// record sockets from peers to avoid repeated connection request, int64_t = (socker_id << 30) + isn
 | 
						|
 | 
						|
private:
 | 
						|
   pthread_key_t m_TLSError;                         // thread local error record (last error)
 | 
						|
   static void TLSDestroy(void* e) {if (NULL != e) delete (CUDTException*)e;}
 | 
						|
 | 
						|
private:
 | 
						|
   CUDTSocket* locate(const SRTSOCKET u);
 | 
						|
   CUDTSocket* locate(const sockaddr* peer, const SRTSOCKET id, int32_t isn);
 | 
						|
   void updateMux(CUDTSocket* s, const sockaddr* addr = NULL, const UDPSOCKET* = NULL);
 | 
						|
   void updateListenerMux(CUDTSocket* s, const CUDTSocket* ls);
 | 
						|
 | 
						|
private:
 | 
						|
   std::map<int, CMultiplexer> m_mMultiplexer;		// UDP multiplexer
 | 
						|
   pthread_mutex_t m_MultiplexerLock;
 | 
						|
 | 
						|
private:
 | 
						|
   CCache<CInfoBlock>* m_pCache;			// UDT network information cache
 | 
						|
 | 
						|
private:
 | 
						|
   volatile bool m_bClosing;
 | 
						|
   pthread_mutex_t m_GCStopLock;
 | 
						|
   pthread_cond_t m_GCStopCond;
 | 
						|
 | 
						|
   pthread_mutex_t m_InitLock;
 | 
						|
   int m_iInstanceCount;				// number of startup() called by application
 | 
						|
   bool m_bGCStatus;					// if the GC thread is working (true)
 | 
						|
 | 
						|
   pthread_t m_GCThread;
 | 
						|
   static void* garbageCollect(void*);
 | 
						|
 | 
						|
   std::map<SRTSOCKET, CUDTSocket*> m_ClosedSockets;   // temporarily store closed sockets
 | 
						|
 | 
						|
   void checkBrokenSockets();
 | 
						|
   void removeSocket(const SRTSOCKET u);
 | 
						|
 | 
						|
   CEPoll m_EPoll;                                     // handling epoll data structures and events
 | 
						|
 | 
						|
private:
 | 
						|
   CUDTUnited(const CUDTUnited&);
 | 
						|
   CUDTUnited& operator=(const CUDTUnited&);
 | 
						|
};
 | 
						|
 | 
						|
// Debug support
 | 
						|
inline std::string SockaddrToString(const sockaddr* sadr)
 | 
						|
{
 | 
						|
    void* addr =
 | 
						|
        sadr->sa_family == AF_INET ?
 | 
						|
        (void*)&((sockaddr_in*)sadr)->sin_addr
 | 
						|
        : sadr->sa_family == AF_INET6 ?
 | 
						|
        (void*)&((sockaddr_in6*)sadr)->sin6_addr
 | 
						|
        : 0;
 | 
						|
    // (cast to (void*) is required because otherwise the 2-3 arguments
 | 
						|
    // of ?: operator would have different types, which isn't allowed in C++.
 | 
						|
    if ( !addr )
 | 
						|
        return "unknown:0";
 | 
						|
 | 
						|
    std::ostringstream output;
 | 
						|
    char hostbuf[1024];
 | 
						|
    int flags;
 | 
						|
 | 
						|
#if ENABLE_GETNAMEINFO
 | 
						|
    flags = NI_NAMEREQD;
 | 
						|
#else
 | 
						|
    flags = NI_NUMERICHOST | NI_NUMERICSERV;
 | 
						|
#endif
 | 
						|
 | 
						|
    if (!getnameinfo(sadr, sizeof(*sadr), hostbuf, 1024, NULL, 0, flags))
 | 
						|
    {
 | 
						|
        output << hostbuf;
 | 
						|
    }
 | 
						|
 | 
						|
    output << ":" << ntohs(((sockaddr_in*)sadr)->sin_port); // TRICK: sin_port and sin6_port have the same offset and size
 | 
						|
    return output.str();
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#endif
 |