mirror of
https://github.com/tribes2/engine.git
synced 2026-01-19 19:24:45 +00:00
783 lines
22 KiB
C++
783 lines
22 KiB
C++
//-----------------------------------------------------------------------------
|
|
// V12 Engine
|
|
//
|
|
// Copyright (c) 2001 GarageGames.Com
|
|
// Portions Copyright (c) 2001 by Sierra Online, Inc.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "platformX86UNIX/platformX86UNIX.h"
|
|
#include "platform/platform.h"
|
|
#include "platform/event.h"
|
|
|
|
//#include <winsock.h>
|
|
//#include <wsipx.h>
|
|
#include <sys/socket.h>
|
|
#include <unistd.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
/* for PROTO_IPX */
|
|
#include <net/if_ppp.h>
|
|
#include <netipx/ipx.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "console/console.h"
|
|
#include "platform/gameInterface.h"
|
|
#include "core/fileStream.h"
|
|
|
|
struct NameLookup
|
|
{
|
|
struct hostent *hostEnt;
|
|
int socket;
|
|
U16 port;
|
|
NameLookup *nextLookup;
|
|
};
|
|
|
|
static NameLookup *lookupList = NULL;
|
|
|
|
// process receives data and posts it to the game.
|
|
|
|
static Net::Error getLastError();
|
|
static S32 defaultPort = 28000;
|
|
static S32 netPort = 0;
|
|
static int ipxSocket = NULL;
|
|
static int udpSocket = NULL;
|
|
|
|
enum {
|
|
MaxConnections = 1024,
|
|
};
|
|
|
|
/*
|
|
HWND winsockWindow = NULL;
|
|
|
|
static LRESULT PASCAL WinsockProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
U32 error;
|
|
U32 bufLen;
|
|
U32 event;
|
|
SOCKET socket;
|
|
Net::Error err;
|
|
S32 bytesRead;
|
|
|
|
static ConnectedNotifyEvent notifyEvent;
|
|
static ConnectedReceiveEvent receiveEvent;
|
|
static ConnectedAcceptEvent acceptEvent;
|
|
|
|
switch(message)
|
|
{
|
|
case WM_USER:
|
|
error = WSAGETSELECTERROR(lParam);
|
|
event = WSAGETSELECTEVENT(lParam);
|
|
socket = wParam;
|
|
switch(event)
|
|
{
|
|
case FD_READ:
|
|
err = Net::recv(socket, receiveEvent.data, MaxPacketDataSize, &bytesRead);
|
|
if(err == Net::NoError && bytesRead != 0)
|
|
{
|
|
receiveEvent.tag = socket;
|
|
receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
|
|
Game->postEvent(receiveEvent);
|
|
}
|
|
break;
|
|
case FD_CONNECT:
|
|
notifyEvent.tag = socket;
|
|
if(error)
|
|
notifyEvent.state = ConnectedNotifyEvent::ConnectFailed;
|
|
else
|
|
notifyEvent.state = ConnectedNotifyEvent::Connected;
|
|
Game->postEvent(notifyEvent);
|
|
break;
|
|
case FD_CLOSE:
|
|
// see first if there is anything to read:
|
|
for(;;)
|
|
{
|
|
err = Net::recv(socket, receiveEvent.data, MaxPacketDataSize, &bytesRead);
|
|
if(err != Net::NoError || bytesRead == 0)
|
|
break;
|
|
|
|
receiveEvent.tag = socket;
|
|
receiveEvent.size = ConnectedReceiveEventHeaderSize + bytesRead;
|
|
Game->postEvent(receiveEvent);
|
|
}
|
|
notifyEvent.tag = socket;
|
|
notifyEvent.state = ConnectedNotifyEvent::Disconnected;
|
|
Game->postEvent(notifyEvent);
|
|
break;
|
|
case FD_ACCEPT:
|
|
acceptEvent.portTag = socket;
|
|
acceptEvent.connectionTag = Net::accept(socket, &acceptEvent.address);
|
|
if(acceptEvent.connectionTag != InvalidSocket)
|
|
{
|
|
Net::setBlocking(acceptEvent.connectionTag, false);
|
|
WSAAsyncSelect(acceptEvent.connectionTag, winsockWindow, WM_USER, FD_READ | FD_CONNECT | FD_CLOSE);
|
|
Game->postEvent(acceptEvent);
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case WM_USER + 1:
|
|
error = WSAGETASYNCERROR(lParam);
|
|
bufLen = WSAGETASYNCBUFLEN(lParam);
|
|
HANDLE handle;
|
|
handle = HANDLE(wParam);
|
|
NameLookup **walk;
|
|
for(walk = &lookupList; *walk; walk = &((*walk)->nextLookup))
|
|
{
|
|
if((*walk)->lookupHandle == handle)
|
|
{
|
|
NameLookup *temp = *walk;
|
|
struct hostent *hp = (struct hostent *) temp->hostEntStruct;
|
|
|
|
SOCKADDR_IN ipAddr;
|
|
memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(IN_ADDR));
|
|
ipAddr.sin_port = temp->port;
|
|
ipAddr.sin_family = AF_INET;
|
|
|
|
notifyEvent.tag = temp->socket;
|
|
|
|
bool wserr = ::connect(temp->socket, (PSOCKADDR) &ipAddr, sizeof(ipAddr)); // always errors out
|
|
if(wserr && WSAGetLastError() != WSAEWOULDBLOCK)
|
|
{
|
|
notifyEvent.state = ConnectedNotifyEvent::DNSFailed;
|
|
::closesocket(temp->socket);
|
|
}
|
|
else
|
|
{
|
|
WSAAsyncSelect(temp->socket, winsockWindow, WM_USER, FD_READ | FD_CONNECT | FD_CLOSE);
|
|
notifyEvent.state = ConnectedNotifyEvent::DNSResolved;
|
|
}
|
|
Game->postEvent(notifyEvent);
|
|
|
|
*walk = temp->nextLookup;
|
|
delete temp;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return DefWindowProc( hWnd, message, wParam, lParam );
|
|
}
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
bool Net::init()
|
|
{
|
|
/* nothing to do */
|
|
}
|
|
|
|
void Net::shutdown()
|
|
{
|
|
while (lookupList)
|
|
{
|
|
NameLookup *temp = lookupList;
|
|
lookupList = temp->nextLookup;
|
|
delete temp;
|
|
}
|
|
closePort();
|
|
}
|
|
|
|
static void netToIPSocketAddress(const NetAddress *address, struct sockaddr_in *sockAddr)
|
|
{
|
|
dMemset(sockAddr, 0, sizeof(struct sockaddr_in));
|
|
sockAddr->sin_family = AF_INET;
|
|
sockAddr->sin_port = htons(address->port);
|
|
char tAddr[20];
|
|
sprintf(tAddr, "%d.%d.%d.%d\n", address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3]);
|
|
//fprintf(stdout,"netToIPSocketAddress(): %s\n",tAddr);fflush(NULL);
|
|
sockAddr->sin_addr.s_addr = inet_addr(tAddr);
|
|
// sockAddr->sin_addr.s_addr = address->netNum[0]; // hopefully this will work.
|
|
}
|
|
|
|
static void IPSocketToNetAddress(const struct sockaddr_in *sockAddr, NetAddress *address)
|
|
{
|
|
address->type = NetAddress::IPAddress;
|
|
address->port = htons(sockAddr->sin_port);
|
|
char *tAddr;
|
|
tAddr = inet_ntoa(sockAddr->sin_addr);
|
|
//fprintf(stdout,"IPSocketToNetAddress(): %s\n",tAddr);fflush(NULL);
|
|
U8 nets[4];
|
|
nets[0] = atoi(strtok(tAddr, "."));
|
|
nets[1] = atoi(strtok(NULL, "."));
|
|
nets[2] = atoi(strtok(NULL, "."));
|
|
nets[3] = atoi(strtok(NULL, "."));
|
|
//fprintf(stdout,"0 = %d, 1 = %d, 2 = %d, 3 = %d\n", nets[0], nets[1], nets[2], nets[3]);
|
|
address->netNum[0] = nets[0];
|
|
address->netNum[1] = nets[1];
|
|
address->netNum[2] = nets[2];
|
|
address->netNum[3] = nets[3];
|
|
}
|
|
|
|
static void netToIPXSocketAddress(const NetAddress *address, sockaddr_ipx *sockAddr)
|
|
{
|
|
dMemset(sockAddr, 0, sizeof(sockaddr_ipx));
|
|
sockAddr->sipx_family = AF_INET;
|
|
sockAddr->sipx_port = htons(address->port);
|
|
sockAddr->sipx_network = address->netNum[0];
|
|
sockAddr->sipx_node[0] = address->nodeNum[0];
|
|
sockAddr->sipx_node[1] = address->nodeNum[1];
|
|
sockAddr->sipx_node[2] = address->nodeNum[2];
|
|
sockAddr->sipx_node[3] = address->nodeNum[3];
|
|
sockAddr->sipx_node[4] = address->nodeNum[4];
|
|
sockAddr->sipx_node[5] = address->nodeNum[5];
|
|
}
|
|
|
|
static void IPXSocketToNetAddress(const sockaddr_ipx *sockAddr, NetAddress *address)
|
|
{
|
|
address->type = NetAddress::IPXAddress;
|
|
address->port = htons(sockAddr->sipx_port);
|
|
address->netNum[0] = sockAddr->sipx_network;
|
|
address->nodeNum[0] = sockAddr->sipx_node[0];
|
|
address->nodeNum[1] = sockAddr->sipx_node[1];
|
|
address->nodeNum[2] = sockAddr->sipx_node[2];
|
|
address->nodeNum[3] = sockAddr->sipx_node[3];
|
|
address->nodeNum[4] = sockAddr->sipx_node[4];
|
|
address->nodeNum[5] = sockAddr->sipx_node[5];
|
|
}
|
|
|
|
NetSocket Net::openListenPort(U16 port)
|
|
{
|
|
if(Game->isJournalReading())
|
|
{
|
|
U32 ret;
|
|
Game->journalRead(&ret);
|
|
return NetSocket(ret);
|
|
}
|
|
NetSocket sock = openSocket();
|
|
fd_set sockFDSet;
|
|
FD_ZERO(&sockFDSet);
|
|
FD_SET(sock, &sockFDSet);
|
|
bind(sock, port);
|
|
listen(sock, 4);
|
|
setBlocking(sock, false);
|
|
if (select(sock, &sockFDSet, &sockFDSet, &sockFDSet, NULL) == -1)
|
|
Con::printf("Error: error in select()\n");
|
|
if (Game->isJournalWriting())
|
|
Game->journalWrite(U32(sock));
|
|
return sock;
|
|
}
|
|
|
|
NetSocket Net::openConnectTo(const char *addressString)
|
|
{
|
|
if(!dStrnicmp(addressString, "ipx:", 4))
|
|
return InvalidSocket;
|
|
if(!dStrnicmp(addressString, "ip:", 3))
|
|
addressString += 3; // eat off the ip:
|
|
char remoteAddr[256];
|
|
dStrcpy(remoteAddr, addressString);
|
|
|
|
char *portString = dStrchr(remoteAddr, ':');
|
|
|
|
U16 port;
|
|
if(portString)
|
|
{
|
|
*portString++ = 0;
|
|
port = htons(dAtoi(portString));
|
|
}
|
|
else
|
|
port = htons(defaultPort);
|
|
|
|
if(!dStricmp(remoteAddr, "broadcast"))
|
|
return InvalidSocket;
|
|
|
|
if(Game->isJournalReading())
|
|
{
|
|
U32 ret;
|
|
Game->journalRead(&ret);
|
|
return NetSocket(ret);
|
|
}
|
|
NetSocket sock = openSocket();
|
|
setBlocking(sock, false);
|
|
|
|
sockaddr_in ipAddr;
|
|
|
|
ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);
|
|
|
|
if(ipAddr.sin_addr.s_addr != INADDR_NONE)
|
|
{
|
|
ipAddr.sin_port = port;
|
|
ipAddr.sin_family = AF_INET;
|
|
if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) == -1)
|
|
{
|
|
Con::printf("Couldn't connect()");
|
|
::close(sock);
|
|
sock = InvalidSocket;
|
|
}
|
|
if(sock != InvalidSocket) {
|
|
fd_set sockFDSet;
|
|
FD_ZERO(&sockFDSet);
|
|
FD_SET(sock, &sockFDSet);
|
|
select(sock, &sockFDSet, &sockFDSet, &sockFDSet, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NameLookup *lookup = new NameLookup;
|
|
lookup->socket = sock;
|
|
lookup->port = port;
|
|
lookup->hostEnt = gethostbyname(remoteAddr);
|
|
|
|
if(lookup->hostEnt == NULL)
|
|
{
|
|
delete lookup;
|
|
::close(sock);
|
|
sock = InvalidSocket;
|
|
}
|
|
else
|
|
{
|
|
lookup->nextLookup = lookupList;
|
|
lookupList = lookup;
|
|
}
|
|
}
|
|
if(Game->isJournalWriting())
|
|
Game->journalWrite(U32(sock));
|
|
return sock;
|
|
}
|
|
|
|
void Net::closeConnectTo(NetSocket sock)
|
|
{
|
|
if(Game->isJournalReading())
|
|
return;
|
|
|
|
for(NameLookup **walk = &lookupList; *walk; walk = &((*walk)->nextLookup) )
|
|
{
|
|
NameLookup *lookup = *walk;
|
|
if(lookup->socket == sock)
|
|
{
|
|
close(lookup->socket);
|
|
*walk = lookup->nextLookup;
|
|
delete lookup;
|
|
return;
|
|
}
|
|
}
|
|
close(sock);
|
|
}
|
|
|
|
Net::Error Net::sendtoSocket(NetSocket socket, const U8 *buffer, int bufferSize)
|
|
{
|
|
if(Game->isJournalReading())
|
|
{
|
|
U32 e;
|
|
Game->journalRead(&e);
|
|
|
|
return (Net::Error) e;
|
|
}
|
|
Net::Error e = send(socket, buffer, bufferSize);
|
|
if(Game->isJournalWriting())
|
|
Game->journalWrite(U32(e));
|
|
return e;
|
|
}
|
|
|
|
bool Net::openPort(S32 port)
|
|
{
|
|
if(udpSocket != InvalidSocket)
|
|
close(udpSocket);
|
|
if(ipxSocket != InvalidSocket)
|
|
close(ipxSocket);
|
|
|
|
udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
ipxSocket = socket(AF_IPX, SOCK_DGRAM, 0);
|
|
|
|
if(udpSocket != InvalidSocket)
|
|
{
|
|
Net::Error error;
|
|
error = bind(udpSocket, port);
|
|
if(error == NoError)
|
|
error = setBufferSize(udpSocket, 32768);
|
|
if(error == NoError)
|
|
error = setBroadcast(udpSocket, true);
|
|
if(error == NoError)
|
|
error = setBlocking(udpSocket, false);
|
|
if(error == NoError)
|
|
Con::printf("UDP initialized on port %d", port);
|
|
else
|
|
{
|
|
close(udpSocket);
|
|
udpSocket = InvalidSocket;
|
|
Con::printf("Unable to initialize UDP - error %d", error);
|
|
}
|
|
}
|
|
if(ipxSocket != InvalidSocket)
|
|
{
|
|
Net::Error error = NoError;
|
|
sockaddr_ipx ipxAddress;
|
|
memset((char *)&ipxAddress, 0, sizeof(ipxAddress));
|
|
ipxAddress.sipx_family = AF_IPX;
|
|
ipxAddress.sipx_port = htons(port);
|
|
S32 err = ::bind(ipxSocket, (struct sockaddr *)&ipxAddress, sizeof(ipxAddress));
|
|
if(err)
|
|
error = getLastError();
|
|
if(error == NoError)
|
|
error = setBufferSize(ipxSocket, 32768);
|
|
if(error == NoError)
|
|
error = setBroadcast(ipxSocket, true);
|
|
if(error == NoError)
|
|
error = setBlocking(ipxSocket, false);
|
|
if(error == NoError)
|
|
Con::printf("IPX initialized on port %d", port);
|
|
else
|
|
{
|
|
close(ipxSocket);
|
|
ipxSocket = InvalidSocket;
|
|
Con::printf("Unable to initialize IPX - error %d", error);
|
|
}
|
|
}
|
|
netPort = port;
|
|
return ipxSocket != InvalidSocket || udpSocket != InvalidSocket;
|
|
}
|
|
|
|
void Net::closePort()
|
|
{
|
|
if(ipxSocket != InvalidSocket)
|
|
close(ipxSocket);
|
|
if(udpSocket != InvalidSocket)
|
|
close(udpSocket);
|
|
}
|
|
|
|
Net::Error Net::sendto(const NetAddress *address, const U8 *buffer, S32 bufferSize)
|
|
{
|
|
if(Game->isJournalReading())
|
|
return NoError;
|
|
|
|
if(address->type == NetAddress::IPXAddress)
|
|
{
|
|
sockaddr_ipx ipxAddr;
|
|
netToIPXSocketAddress(address, &ipxAddr);
|
|
if(::sendto(ipxSocket, (const char*)buffer, bufferSize, 0,
|
|
(sockaddr *) &ipxAddr, sizeof(sockaddr_ipx)) == -1)
|
|
return getLastError();
|
|
else
|
|
return NoError;
|
|
}
|
|
else
|
|
{
|
|
sockaddr_in ipAddr;
|
|
netToIPSocketAddress(address, &ipAddr);
|
|
if(::sendto(udpSocket, (const char*)buffer, bufferSize, 0,
|
|
(sockaddr *) &ipAddr, sizeof(sockaddr_in)) == -1)
|
|
return getLastError();
|
|
else
|
|
return NoError;
|
|
}
|
|
}
|
|
|
|
void Net::process()
|
|
{
|
|
sockaddr sa;
|
|
|
|
PacketReceiveEvent receiveEvent;
|
|
for(;;)
|
|
{
|
|
S32 addrLen = sizeof(sa);
|
|
S32 bytesRead = -1;
|
|
if(udpSocket != InvalidSocket)
|
|
bytesRead = recvfrom(udpSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
|
|
if(bytesRead == -1 && ipxSocket != InvalidSocket)
|
|
{
|
|
addrLen = sizeof(sa);
|
|
bytesRead = recvfrom(ipxSocket, (char *) receiveEvent.data, MaxPacketDataSize, 0, &sa, &addrLen);
|
|
}
|
|
|
|
if(bytesRead == -1)
|
|
break;
|
|
|
|
if(sa.sa_family == AF_INET)
|
|
IPSocketToNetAddress((sockaddr_in *) &sa, &receiveEvent.sourceAddress);
|
|
else if(sa.sa_family == AF_IPX)
|
|
IPXSocketToNetAddress((sockaddr_ipx *) &sa, &receiveEvent.sourceAddress);
|
|
else
|
|
continue;
|
|
|
|
NetAddress &na = receiveEvent.sourceAddress;
|
|
if(na.type == NetAddress::IPAddress &&
|
|
na.netNum[0] == 127 &&
|
|
na.netNum[1] == 0 &&
|
|
na.netNum[2] == 0 &&
|
|
na.netNum[3] == 1 &&
|
|
na.port == netPort)
|
|
continue;
|
|
if(bytesRead <= 0)
|
|
continue;
|
|
receiveEvent.size = PacketReceiveEventHeaderSize + bytesRead;
|
|
Game->postEvent(receiveEvent);
|
|
}
|
|
}
|
|
|
|
NetSocket Net::openSocket()
|
|
{
|
|
int retSocket;
|
|
retSocket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if(retSocket == InvalidSocket)
|
|
return InvalidSocket;
|
|
else
|
|
return retSocket;
|
|
}
|
|
|
|
Net::Error Net::closeSocket(NetSocket socket)
|
|
{
|
|
if(socket != InvalidSocket)
|
|
{
|
|
if(!close(socket))
|
|
return NoError;
|
|
else
|
|
return getLastError();
|
|
}
|
|
else
|
|
return NotASocket;
|
|
}
|
|
|
|
Net::Error Net::connect(NetSocket socket, const NetAddress *address)
|
|
{
|
|
if(address->type != NetAddress::IPAddress)
|
|
return WrongProtocolType;
|
|
sockaddr_in socketAddress;
|
|
netToIPSocketAddress(address, &socketAddress);
|
|
if(!::connect(socket, (sockaddr *) &socketAddress, sizeof(socketAddress)))
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::listen(NetSocket socket, S32 backlog)
|
|
{
|
|
if(!::listen(socket, backlog))
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
NetSocket Net::accept(NetSocket acceptSocket, NetAddress *remoteAddress)
|
|
{
|
|
sockaddr_in socketAddress;
|
|
S32 addrLen = sizeof(socketAddress);
|
|
|
|
int retVal = ::accept(acceptSocket, (sockaddr *) &socketAddress, &addrLen);
|
|
if(retVal != InvalidSocket)
|
|
{
|
|
IPSocketToNetAddress(&socketAddress, remoteAddress);
|
|
return retVal;
|
|
}
|
|
return InvalidSocket;
|
|
}
|
|
|
|
Net::Error Net::bind(NetSocket socket, U16 port)
|
|
{
|
|
S32 error;
|
|
|
|
sockaddr_in socketAddress;
|
|
dMemset((char *)&socketAddress, 0, sizeof(socketAddress));
|
|
socketAddress.sin_family = AF_INET;
|
|
// It's entirely possible that there are two NIC cards.
|
|
// We let the user specify which one the server runs on.
|
|
|
|
// thanks to [TPG]P1aGu3 for the name
|
|
const char* serverIP = Con::getVariable( "Host::BindAddress" );
|
|
// serverIP is guaranteed to be non-0.
|
|
AssertFatal( serverIP, "serverIP is NULL!" );
|
|
|
|
if( serverIP[0] != '\0' ) {
|
|
// we're not empty
|
|
socketAddress.sin_addr.s_addr = inet_addr( serverIP );
|
|
|
|
if( socketAddress.sin_addr.s_addr != INADDR_NONE ) {
|
|
Con::printf( "Binding server port to %s", serverIP );
|
|
} else {
|
|
Con::warnf( ConsoleLogEntry::General,
|
|
"inet_addr() failed for %s while binding!",
|
|
serverIP );
|
|
socketAddress.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
} else {
|
|
Con::printf( "Binding server port to default IP" );
|
|
socketAddress.sin_addr.s_addr = INADDR_ANY;
|
|
}
|
|
|
|
socketAddress.sin_port = htons(port);
|
|
error = ::bind(socket, (sockaddr *) &socketAddress, sizeof(socketAddress));
|
|
|
|
if(!error)
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::setBufferSize(NetSocket socket, S32 bufferSize)
|
|
{
|
|
S32 error;
|
|
error = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufferSize, sizeof(bufferSize));
|
|
if(!error)
|
|
error = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufferSize, sizeof(bufferSize));
|
|
if(!error)
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::setBroadcast(NetSocket socket, bool broadcast)
|
|
{
|
|
S32 bc = broadcast;
|
|
S32 error = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char*)&bc, sizeof(bc));
|
|
if(!error)
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::setBlocking(NetSocket socket, bool blockingIO)
|
|
{
|
|
int notblock = !blockingIO;
|
|
S32 error = ioctl(socket, FIONBIO, ¬block);
|
|
if(!error)
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::send(NetSocket socket, const U8 *buffer, S32 bufferSize)
|
|
{
|
|
S32 error = ::send(socket, (const char*)buffer, bufferSize, 0);
|
|
if(!error)
|
|
return NoError;
|
|
return getLastError();
|
|
}
|
|
|
|
Net::Error Net::recv(NetSocket socket, U8 *buffer, S32 bufferSize, S32 *bytesRead)
|
|
{
|
|
*bytesRead = ::recv(socket, (char*)buffer, bufferSize, 0);
|
|
if(*bytesRead == -1)
|
|
return getLastError();
|
|
return NoError;
|
|
}
|
|
|
|
bool Net::compareAddresses(const NetAddress *a1, const NetAddress *a2)
|
|
{
|
|
if((a1->type != a2->type) ||
|
|
(*((U32 *)a1->netNum) != *((U32 *)a2->netNum)) ||
|
|
(a1->port != a2->port))
|
|
return false;
|
|
|
|
if(a1->type == NetAddress::IPAddress)
|
|
return true;
|
|
for(S32 i = 0; i < 6; i++)
|
|
if(a1->nodeNum[i] != a2->nodeNum[i])
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool Net::stringToAddress(const char *addressString, NetAddress *address)
|
|
{
|
|
if(dStrnicmp(addressString, "ipx:", 4))
|
|
{
|
|
// assume IP if it doesn't have ipx: at the front.
|
|
|
|
if(!dStrnicmp(addressString, "ip:", 3))
|
|
addressString += 3; // eat off the ip:
|
|
|
|
sockaddr_in ipAddr;
|
|
char remoteAddr[256];
|
|
if(strlen(addressString) > 255)
|
|
return false;
|
|
|
|
dStrcpy(remoteAddr, addressString);
|
|
|
|
char *portString = dStrchr(remoteAddr, ':');
|
|
if(portString)
|
|
*portString++ = 0;
|
|
|
|
struct hostent *hp;
|
|
|
|
if(!dStricmp(remoteAddr, "broadcast"))
|
|
ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
|
|
else
|
|
{
|
|
ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);
|
|
if(ipAddr.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
if((hp = gethostbyname(remoteAddr)) == NULL)
|
|
return false;
|
|
else
|
|
memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr, sizeof(in_addr));
|
|
}
|
|
}
|
|
if(portString)
|
|
ipAddr.sin_port = htons(dAtoi(portString));
|
|
else
|
|
ipAddr.sin_port = htons(defaultPort);
|
|
ipAddr.sin_family = AF_INET;
|
|
IPSocketToNetAddress(&ipAddr, address);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
S32 i;
|
|
S32 port;
|
|
|
|
address->type = NetAddress::IPXAddress;
|
|
for(i = 0; i < 6; i++)
|
|
address->nodeNum[i] = 0xFF;
|
|
|
|
// it's an IPX string
|
|
addressString += 4;
|
|
if(!dStricmp(addressString, "broadcast"))
|
|
{
|
|
address->port = defaultPort;
|
|
return true;
|
|
}
|
|
else if(sscanf(addressString, "broadcast:%d", &port) == 1)
|
|
{
|
|
address->port = port;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
S32 nodeNum[6];
|
|
S32 netNum[4];
|
|
S32 count = dSscanf(addressString, "%2x%2x%2x%2x:%2x%2x%2x%2x%2x%2x:%d",
|
|
&netNum[0], &netNum[1], &netNum[2], &netNum[3],
|
|
&nodeNum[0], &nodeNum[1], &nodeNum[2], &nodeNum[3], &nodeNum[4], &nodeNum[5],
|
|
&port);
|
|
|
|
if(count == 10)
|
|
{
|
|
port = defaultPort;
|
|
count++;
|
|
}
|
|
if(count != 11)
|
|
return false;
|
|
|
|
for(i = 0; i < 6; i++)
|
|
address->nodeNum[i] = nodeNum[i];
|
|
for(i = 0; i < 4; i++)
|
|
address->netNum[i] = netNum[i];
|
|
address->port = port;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Net::addressToString(const NetAddress *address, char addressString[256])
|
|
{
|
|
if(address->type == NetAddress::IPAddress)
|
|
{
|
|
sockaddr_in ipAddr;
|
|
netToIPSocketAddress(address, &ipAddr);
|
|
|
|
if(ipAddr.sin_addr.s_addr == htonl(INADDR_BROADCAST))
|
|
dSprintf(addressString, 256, "IP:Broadcast:%d", ntohs(ipAddr.sin_port));
|
|
else
|
|
dSprintf(addressString, 256, "IP:%s:%d", inet_ntoa(ipAddr.sin_addr),
|
|
ntohs(ipAddr.sin_port));
|
|
// dSprintf(addressString, 256, "IP:%d:%d", ipAddr.sin_addr.s_addr,
|
|
// ntohs(ipAddr.sin_port));
|
|
}
|
|
else
|
|
{
|
|
dSprintf(addressString, 256, "IPX:%.2X%.2X%.2X%.2X:%.2X%.2X%.2X%.2X%.2X%.2X:%d",
|
|
address->netNum[0], address->netNum[1], address->netNum[2], address->netNum[3],
|
|
address->nodeNum[0], address->nodeNum[1], address->nodeNum[2], address->nodeNum[3], address->nodeNum[4], address->nodeNum[5],
|
|
address->port);
|
|
}
|
|
}
|
|
|
|
Net::Error getLastError()
|
|
{
|
|
return Net::UnknownError;
|
|
}
|