unix_net.cpp

来自「symbian 下的helix player源代码」· C++ 代码 · 共 2,212 行 · 第 1/4 页

CPP
2,212
字号
/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: unix_net.cpp,v 1.6.2.4 2004/07/09 01:46:41 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#if defined _LINUX && defined __GLIBC__ && 0
#define _JAVA_GREENTHREADS
#endif

// Java with green threads needs you to use the internal entry points
// for these system calls
#ifdef _JAVA_GREENTHREADS
#define READ ::__read
#define CONNECT ::__connect
#define RECVFROM ::__recvfrom
#else
#define READ ::read
#define CONNECT ::connect
#define RECVFROM ::recvfrom
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include "hxcom.h"
#include "hxbuffer.h"
#include "timebuff.h"
#include "hxtick.h"
#include "netbyte.h"
#include "platform/unix/unix_net.h"		//	Our declaration
#include "hxheap.h"
#include "hxslist.h"
#include "hxcom.h"
#include "hxengin.h"
#include "hxstrutl.h"
#include <errno.h>

#ifdef _IRIX
#include <bstring.h>		// 	used in FD_ZERO
#endif
// #include "netplay.h"		//	why?

#ifdef _AIX
#include <sys/select.h>
#endif

#include <sys/types.h> //for waitpid
#include <sys/wait.h>  //for waitpid

#include <fcntl.h>

#ifdef _UNIX_THREADS_SUPPORTED
#include "hxthread.h"
#endif  

int unix_net::InBlockingMode = 0;

// This thing doesn't get initialized if this is linked into a shared library
CHXSimpleList* unix_net::readers = NULL;
// So I've done a silly thing and labelled it so.
static BOOL silly_unix_hack_initialized = FALSE;

const int HOSTSTRUCTSIZE = sizeof( hostent ); 

unix_net::unix_net() 
{
	set_sock( INVALID_SOCKET );
	mLastError = HXR_OK;
	callRaConnect = 1;    
	bReadyToWrite = 0;
	m_SocketState = CONN_CLOSED;

	//Async DNS vars.
	CurrentAddr    = 0;
	m_DNSOnly      = FALSE;
	m_anDNSPipe[0] = nInvalidPipe;
	m_anDNSPipe[1] = nInvalidPipe;
	m_nChildProcID = 0;
	m_szPipeIP[0]  = '\0';

	
	read_pending = FALSE;
	m_lRefCount	    = 0;
	// Don't allocate this yet. Not all unix_net instances are actually
	// used to read, and if one isn't, allocating here wastes memory.
	m_pInBuffer = NULL;

	m_bReuseAddr = FALSE;
	m_bReusePort = FALSE;
	m_pAsyncHost = NULL;
        
#ifdef _UNIX_THREADS_SUPPORTED
        m_pResolver  = NULL;
#endif        
}

unix_net::~unix_net() 
{
    m_SocketState = CONN_CLOSING;
    if ((get_sock() != INVALID_SOCKET) )       
    {
	::close(get_sock());
	set_sock( INVALID_SOCKET );
    }
    m_SocketState = CONN_CLOSED;
    mConnectionOpen = 0;
    
    LISTPOSITION listpos = readers->Find(this);
    if(listpos)
    {
	readers->RemoveAt(listpos);
    }
    HX_VECTOR_DELETE(m_pInBuffer); 

    //If the DNS forked proccess is still running lets
    //kill it here.
    //Ignore any returned error, what would we do anyway?
    CleanUpChildProc();
    HX_VECTOR_DELETE(m_pAsyncHost);

#ifdef _UNIX_THREADS_SUPPORTED
    if( m_bThreadedDNS )
    {
        if(m_pResolver)
            m_pResolver->Exit(0);

        m_nResolved    = 0;
        HX_DELETE( m_pResolver );
    }
#endif  

}

void unix_net::CleanUpChildProc()
{
    //Close any open pipes as well.
    if( m_anDNSPipe[0] >= 0 )
    {
	::close( m_anDNSPipe[0] );
	m_anDNSPipe[0] = nInvalidPipe;
    }
    
    if( m_anDNSPipe[1] >= 0 )
    {
	::close( m_anDNSPipe[1] );
	m_anDNSPipe[1] = nInvalidPipe;
    }
    
    if( m_nChildProcID != 0 )
    {
	kill( m_nChildProcID, SIGKILL );
	m_nChildProcID = 0;
    }
}

unix_net * unix_net::new_socket(UINT16 type)
{
    unix_net *c = NULL;
    
    if(!silly_unix_hack_initialized)
    {
	readers = new CHXSimpleList;
	silly_unix_hack_initialized = TRUE; 
    }
    
    switch(type)
    {
    case HX_TCP_SOCKET:
	c = new unix_TCP;
	readers->AddTail(c);
	break;
	
    case HX_UDP_SOCKET:
	c = new unix_UDP;
	readers->AddTail(c);
	break;
    }
    
    return(c);
}


// init_drivers() should do any network driver initialization here
// params is a pointer to a platform specfic defined struct that 
// contains an required initialization data

HX_RESULT unix_net::init_drivers(void *params)
{
	return(HXR_OK);
}


/* 	close_drivers() should close any network drivers used by the program
 	NOTE: The program MUST not make any other calls to the network drivers
 	until init_drivers() has been called */

HX_RESULT unix_net::close_drivers(void *params)
{
	return(HXR_OK);
}

HX_RESULT 
unix_net::get_host_name(char *name, int namelen)
{
    if (::gethostname(name, namelen) == 0)
    {
	return HXR_OK;
    }
    else
    {
	return HXR_FAIL;
    }
}

HX_RESULT 
unix_net::get_host_by_name(char *name, REF(struct hostent*) pHostent)
{
    if (pHostent = ::gethostbyname(name))
    {
        return HXR_OK;
    }
    else
    {
        return HXR_FAIL;
    }    
}

HX_RESULT unix_net::host_to_ip_str( char *host, char *ip, UINT32 ulIPBufLen)
{
    HX_RESULT           theErr = HXR_OK;
    ULONG32             dwAddress;
    struct sockaddr_in  rInAddress;
    struct hostent*     pHostEntry;

    //	Let's look for this in the cache first
    if (conn::is_cached( host, &dwAddress))
    {
	//Found it, copy the 32bit address into rInAddress
	//w/o calling memcpy()
	rInAddress.sin_addr.s_addr  = dwAddress;
    }
    else
    { 
	// Do DNS on the host name
	if (!(pHostEntry = gethostbyname( host )))
	{
	    // Error
	    theErr = HXR_DNR;
	}

	// Return w/o attempting any copies if there's an error
	if (theErr != HXR_OK)
	{
	    goto FuncExit;
	}
		
	// copy the ip address into rInAddress w/o calling memcpy()                    
        struct in_addr** ppAddr = (struct in_addr**)(pHostEntry->h_addr_list);
        memcpy(&rInAddress.sin_addr, ppAddr[0], sizeof(struct in_addr)); /* Flawfinder: ignore */
	
	// add to the dns cache
	conn::add_to_cache(host, (ULONG32) rInAddress.sin_addr.s_addr ); 
    }

    // Convert the ULONG32 IP address into a string and copy it into ip
    SafeStrCpy( ip, inet_ntoa( rInAddress.sin_addr ) , ulIPBufLen);

    // Single exit point
 FuncExit:

    return( theErr );
}

ULONG32	unix_net::AddRef()
{
    return InterlockedIncrement(&m_lRefCount);
}

ULONG32 unix_net::Release()
{
    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;
    return 0;
}

/*
*   reuse_addr/reuse_port has to be called before a sock binds.  however, 
*   socket is not available until it binds as it is implemented.  So, set a 
*   flag here and do the actual setsockopt right before a sock binds.
*   Look in init_unix().
*/
HX_RESULT	
unix_net::reuse_addr(BOOL enable)
{
    m_bReuseAddr = enable;
    return HXR_OK;
}

HX_RESULT	
unix_net::reuse_port(BOOL enable)
{
    m_bReusePort = enable;
    return HXR_OK;
}

HX_RESULT unix_net::init_unix(UINT16 type, UINT32 local_addr, UINT16 port, 
                              UINT16 blocking)
{                                        
    int                s = INVALID_SOCKET;
    struct sockaddr_in addr;
#ifdef _BEOS
    char    mode = 1;
#else
    int	    mode = 1;
#endif
    
    mLastError = HXR_OK;
#ifdef _BEOS
    s = socket(AF_INET, type, 0);
#else
    s = socket(PF_INET, type, 0);
#endif
    if (s < 0) 
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	return mLastError;
    }
    
    if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char*)&m_bReuseAddr, sizeof(m_bReuseAddr)) < 0) 
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	goto sock_err;
    }

#if defined SO_REUSEPORT
    if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (const char*)&m_bReusePort, sizeof(m_bReusePort)) < 0) 
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	goto sock_err;
    }
#endif    
        
    memset(&addr, 0, sizeof addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(local_addr);
    addr.sin_port = htons(port);
    
    if (::bind(s, (sockaddr*)&addr, sizeof addr) < 0) 
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	goto sock_err;
    }
#ifdef FIONBIO
    if (!blocking && ioctl(s, FIONBIO, &mode) < 0) 
#elif SO_NONBLOCK
    if (!blocking && setsockopt(s,SOL_SOCKET,SO_NONBLOCK,&mode,1)<0)
#else
    if (!blocking && ::fcntl(get_sock(), F_SETFL, ::fcntl(get_sock(), F_GETFL, 0) | O_NONBLOCK) < 0)
#endif
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	goto sock_err;
    }
    DPRINTF(D_MSG,("unix_net::socket opened: %d\n", s));
    m_SocketState = CONN_OPEN;
    set_sock( s );

    return mLastError;
    
sock_err:
    ::close(s);
    m_SocketState = CONN_NO_CONN;
    return mLastError;
}

#if 0
/* mcast_multiple_if test */
/*
 *  it returns a number of multicast enabled NICs with a default multicast
 *  interface as the very first entry in the pIFList
 */
UINT32
unix_net::detectMcastIF(REF(BYTE**) pIFList) 
{

    struct ifconf ifc;
    int i;

    ifc.ifc_len = sizeof(buff);
    ifc.ifc_buf = buff;
	if (ioctl(skfd, SIOCGIFCONF, &ifc) >= 0) {
    {
        // XXXGo
        //printf("%s\n", pc);
	printf("%u\n", ul);
    }
    else
    {   
        printf("coudn't detect if\n");
    }
    //HX_VECTOR_DELETE(pc);
 
}
#endif

HX_RESULT unix_net::connect(const char* host, UINT16 port, UINT16 blocking, ULONG32 ulPlatform)
{
    DPRINTF(D_MSG,("unix_net::connect(): b: %d\n", blocking));
    
    bReadyToWrite = 0;
    
    //Get a host at all?
    if(!host)                 
    {
	mLastError = HXR_DNR;
	return mLastError;
    }

    //Do we have a socket yet?
    if(get_sock() < 0)                 
    {
	mLastError = HXR_NET_SOCKET_INVALID;
	return mLastError;
    }
    
    if( blocking )
    {
	//Set our state.
	m_SocketState = CONN_DNS_INPROG;
	
	//check and see if we were passed a dot format IP address.
	memset(&m_sSockAddrIn, 0, sizeof(struct sockaddr_in));    
	char* pTemp = (char*)strrchr(host, '.');
	if (pTemp && atoi(pTemp + 1))
	{
	    m_sSockAddrIn.sin_addr.s_addr = inet_addr(host);
	    
	    if ((ULONG32)m_sSockAddrIn.sin_addr.s_addr == (ULONG32)-1) 
	    {
		mLastError = HXR_DNR;
		return mLastError;
	    }
	    //Set state to show we have the address ready to go.
	    m_SocketState = CONN_CONNECT_INPROG;
	} 
	
	//do a blocking gethostbyname() call.
	if( m_SocketState == CONN_DNS_INPROG )
	{ 
	    struct hostent *h = gethostbyname(host);
	    if (!h || !h->h_addr ) 
	    {
		mLastError = HXR_DNR;
                DPRINTF(D_MSG,("unix_net::connect() HXR_INVALID_HOST\r\n"));
		CB_ConnectionComplete(0);
		return HXR_DNR;
	    }
            
            struct in_addr** ppAddr = (struct in_addr**)(h->h_addr_list);
            memcpy(&m_sSockAddrIn.sin_addr, ppAddr[0], sizeof(struct in_addr)); /* Flawfinder: ignore */

	    if (m_pAsyncHost != host)
	    {
		HX_VECTOR_DELETE(m_pAsyncHost);
		m_pAsyncHost = ::new_string(host);
	    }
	    m_AsyncPort = port; 
	}
			
	m_sSockAddrIn.sin_family = AF_INET;
	m_sSockAddrIn.sin_port = htons(port);

	// this stores info about current addr 
	CurrentAddr = m_sSockAddrIn.sin_addr.s_addr;

	if(CONNECT(get_sock(), (sockaddr*)&m_sSockAddrIn, sizeof(struct sockaddr_in)))
	{   
	    if(!blocking && (errno == EWOULDBLOCK || errno == EINPROGRESS))
	    {  
		mConnectionOpen = 1;
		nonblocking();
		CB_ConnectionComplete(1);
		return HXR_OK;
	    }
            
            DPRINTF(D_MSG,("unix_net::connect() HXR_NET_CONNECT\r\n"));
            mLastError = HXR_NET_CONNECT;
	    CB_ConnectionComplete(0);
	    return HXR_NET_CONNECT;
	}       
	 	      
	mConnectionOpen = 1;
	nonblocking();
	m_SocketState = CONN_OPEN; // Rahul
	bReadyToWrite = 1;
	CB_ConnectionComplete(1);
	return HXR_OK;
    }//blocking

    return ConnectAsync( host, port );
}


⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?