📄 unix_net.cpp
字号:
/* ***** 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 libraryCHXSimpleList* 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 dataHX_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 */UINT32unix_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); }#endifHX_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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -