mirror of
https://git.code.sf.net/p/quake/quakeforge-old
synced 2024-11-29 15:12:17 +00:00
c3f5581b0a
Unchained, Ultimate, Ultra, Up Yours, Underworld, Underground, Unified, Unity, etc. You know the drill. This takes care of the "standalone" problem with the wrong name, and the recent snafu with multiple developers working on the same files simultaneously...expect me (and probably others) to start locking dirs when updates are taking place. And yes, this update is really as large as it looks. Software only at the moment, but I will have the makefile updated to build the GL builds as well.
706 lines
18 KiB
C
706 lines
18 KiB
C
/*
|
|
Copyright (C) 1996-1997 Id Software, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
// net_ipx.c
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dpmi.h>
|
|
|
|
#include "quakedef.h"
|
|
#include "dosisms.h"
|
|
#include "net_ipx.h"
|
|
|
|
#define EIO 5 /* I/O error */
|
|
|
|
#define AF_NETWARE 64
|
|
|
|
#define IPX_OPEN 0
|
|
#define IPX_CLOSE 1
|
|
#define IPX_GETROUTE 2
|
|
#define IPX_SEND 3
|
|
#define IPX_LISTEN 4
|
|
#define IPX_SCHEDULEEVENT 5
|
|
#define IPX_CANCEL 6
|
|
#define IPX_SCHEDULESPECIALEVENT 7
|
|
#define IPX_GETINTERVALMARKER 8
|
|
#define IPX_GETADDRESS 9
|
|
#define IPX_RELINQUISH 10
|
|
|
|
#define PTYPE_UNKNOWN 0
|
|
#define PTYPE_RIP 1
|
|
#define PTYPE_ECHO 2
|
|
#define PTYPE_ERROR 3
|
|
#define PTYPE_IPX 4
|
|
#define PTYPE_SPX 5
|
|
|
|
#pragma pack(1)
|
|
|
|
typedef struct
|
|
{
|
|
byte network[4];
|
|
byte node[6];
|
|
short socket;
|
|
} IPXaddr;
|
|
|
|
struct sockaddr_ipx
|
|
{
|
|
short sipx_family;
|
|
IPXaddr sipx_addr;
|
|
char sipx_zero[2];
|
|
};
|
|
#define sipx_port sipx_addr.socket
|
|
|
|
typedef struct
|
|
{
|
|
short checkSum;
|
|
short length;
|
|
byte transportControl;
|
|
byte type;
|
|
IPXaddr destination;
|
|
IPXaddr source;
|
|
} IPXheader;
|
|
|
|
typedef struct ECBStructure
|
|
{
|
|
struct ECBStructure *link;
|
|
unsigned short ESR_off;
|
|
unsigned short ESR_seg;
|
|
byte inUse;
|
|
byte completionCode;
|
|
short socket;
|
|
byte IPXWorkspace[4];
|
|
byte driverWorkspace[12];
|
|
byte immediateAddress[6];
|
|
short fragCount;
|
|
short fragOff;
|
|
short fragSeg;
|
|
short fragSize;
|
|
} ECB;
|
|
|
|
#pragma pack()
|
|
|
|
typedef struct
|
|
{
|
|
ECB ecb;
|
|
IPXheader header;
|
|
int sequence;
|
|
char data[NET_DATAGRAMSIZE];
|
|
} ipx_lowmem_buffer_t;
|
|
|
|
#define LOWMEMSIZE (100 * 1024)
|
|
#define LOWMEMSAVE 256
|
|
#define IPXBUFFERS ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t))
|
|
#define IPXSOCKBUFFERS 5
|
|
#define IPXSOCKETS (IPXBUFFERS / IPXSOCKBUFFERS)
|
|
|
|
// each socket's socketbuffer 0 is used for sending, the others for listening
|
|
|
|
typedef struct
|
|
{
|
|
char reserved[LOWMEMSAVE];
|
|
ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS];
|
|
} ipx_lowmem_area_t;
|
|
|
|
|
|
static int ipxsocket[IPXSOCKETS];
|
|
static ECB *readlist[IPXSOCKETS];
|
|
static int sequence[IPXSOCKETS];
|
|
static int handlesInUse;
|
|
static ipx_lowmem_area_t *lma;
|
|
static char *lowmem_buffer;
|
|
static int lowmem_bufseg;
|
|
static int lowmem_bufoff;
|
|
static unsigned short ipx_cs;
|
|
static unsigned short ipx_ip;
|
|
static int net_acceptsocket = -1;
|
|
static int net_controlsocket;
|
|
|
|
static void IPX_PollProcedure(void);
|
|
static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure};
|
|
|
|
//=============================================================================
|
|
|
|
static void IPX_GetLocalAddress(IPXaddr *addr)
|
|
{
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_GETADDRESS;
|
|
regs.x.es = lowmem_bufseg;
|
|
regs.x.si = lowmem_bufoff;
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
Q_memcpy(addr, lowmem_buffer, 10);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget)
|
|
{
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_GETROUTE;
|
|
regs.x.es = lowmem_bufseg;
|
|
regs.x.si = lowmem_bufoff;
|
|
regs.x.di = lowmem_bufoff + sizeof(IPXaddr);
|
|
Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr));
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
if (regs.h.al)
|
|
return -1;
|
|
Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6);
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
static void IPX_ListenForPacket(ECB *ecb)
|
|
{
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_LISTEN;
|
|
regs.x.es = ptr2real(ecb) >> 4;
|
|
regs.x.si = ptr2real(ecb) & 0xf;
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
static void IPX_RelinquishControl(void)
|
|
{
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_RELINQUISH;
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
}
|
|
|
|
|
|
void IPX_PollProcedure(void)
|
|
{
|
|
IPX_RelinquishControl();
|
|
SchedulePollProcedure(&pollProcedure, 0.01);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
static void ProcessReadyList(int s)
|
|
{
|
|
int n;
|
|
ECB *ecb;
|
|
ECB *prev;
|
|
|
|
for (n = 1; n < IPXSOCKBUFFERS; n++)
|
|
{
|
|
if (lma->socketbuffer[s][n].ecb.inUse == 0)
|
|
{
|
|
for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link)
|
|
{
|
|
if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence)
|
|
break;
|
|
prev = ecb;
|
|
}
|
|
if (ecb)
|
|
lma->socketbuffer[s][n].ecb.link = ecb;
|
|
else
|
|
lma->socketbuffer[s][n].ecb.link = NULL;
|
|
if (prev)
|
|
prev->link = &lma->socketbuffer[s][n].ecb;
|
|
else
|
|
readlist[s] = &lma->socketbuffer[s][n].ecb;
|
|
lma->socketbuffer[s][n].ecb.inUse = 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_Init(void)
|
|
{
|
|
int s;
|
|
int n;
|
|
struct qsockaddr addr;
|
|
char *colon;
|
|
|
|
if (COM_CheckParm ("-noipx"))
|
|
return -1;
|
|
|
|
// find the IPX far call entry point
|
|
regs.x.ax = 0x7a00;
|
|
__dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s);
|
|
if (regs.h.al != 0xff)
|
|
{
|
|
Con_Printf("IPX not detected\n");
|
|
return -1;
|
|
}
|
|
ipx_cs = regs.x.es;
|
|
ipx_ip = regs.x.di;
|
|
|
|
// grab a chunk of memory down in DOS land
|
|
lowmem_buffer = dos_getmemory(LOWMEMSIZE);
|
|
if (!lowmem_buffer)
|
|
{
|
|
Con_Printf("IPX_Init: Not enough low memory\n");
|
|
return -1;
|
|
}
|
|
lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
|
|
lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
|
|
|
|
// init socket handles & buffers
|
|
handlesInUse = 0;
|
|
lma = (ipx_lowmem_area_t *)lowmem_buffer;
|
|
for (s = 0; s < IPXSOCKETS; s++)
|
|
{
|
|
ipxsocket[s] = 0;
|
|
for (n = 0; n < IPXSOCKBUFFERS; n++)
|
|
{
|
|
lma->socketbuffer[s][n].ecb.link = NULL;
|
|
lma->socketbuffer[s][n].ecb.ESR_off = 0;
|
|
lma->socketbuffer[s][n].ecb.ESR_seg = 0;
|
|
lma->socketbuffer[s][n].ecb.socket = 0;
|
|
lma->socketbuffer[s][n].ecb.inUse = 0xff;
|
|
lma->socketbuffer[s][n].ecb.completionCode = 0;
|
|
lma->socketbuffer[s][n].ecb.fragCount = 1;
|
|
lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf;
|
|
lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4;
|
|
lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
|
}
|
|
}
|
|
|
|
if ((net_controlsocket = IPX_OpenSocket (0)) == -1)
|
|
{
|
|
dos_freememory(lowmem_buffer);
|
|
Con_DPrintf ("IPX_Init: Unable to open control socket\n");
|
|
return -1;
|
|
}
|
|
|
|
SchedulePollProcedure(&pollProcedure, 0.01);
|
|
|
|
IPX_GetSocketAddr (net_controlsocket, &addr);
|
|
Q_strcpy(my_ipx_address, IPX_AddrToString (&addr));
|
|
colon = Q_strrchr (my_ipx_address, ':');
|
|
if (colon)
|
|
*colon = 0;
|
|
|
|
Con_Printf("IPX initialized\n");
|
|
ipxAvailable = true;
|
|
return net_controlsocket;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
void IPX_Shutdown(void)
|
|
{
|
|
IPX_Listen (false);
|
|
IPX_CloseSocket (net_controlsocket);
|
|
dos_freememory(lowmem_buffer);
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
void IPX_Listen (qboolean state)
|
|
{
|
|
// enable listening
|
|
if (state)
|
|
{
|
|
if (net_acceptsocket != -1)
|
|
return;
|
|
if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1)
|
|
Sys_Error ("IPX_Listen: Unable to open accept socket\n");
|
|
return;
|
|
}
|
|
|
|
// disable listening
|
|
if (net_acceptsocket == -1)
|
|
return;
|
|
IPX_CloseSocket (net_acceptsocket);
|
|
net_acceptsocket = -1;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_OpenSocket(int port)
|
|
{
|
|
int handle;
|
|
int n;
|
|
unsigned short socket;
|
|
|
|
if (handlesInUse == IPXSOCKETS)
|
|
return -1;
|
|
|
|
// open the IPX socket
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_OPEN;
|
|
regs.h.al = 0;
|
|
regs.x.dx = htons(port);
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
if (regs.h.al == 0xfe)
|
|
{
|
|
Con_DPrintf("IPX_OpenSocket: all sockets in use\n");
|
|
return -1;
|
|
}
|
|
if (regs.h.al == 0xff)
|
|
{
|
|
Con_DPrintf("IPX_OpenSocket: socket already open\n");
|
|
return -1;
|
|
}
|
|
if (regs.h.al != 0)
|
|
{
|
|
Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al);
|
|
return -1;
|
|
}
|
|
socket = regs.x.dx;
|
|
|
|
// grab a handle; fill in the ECBs, and get them listening
|
|
for (handle = 0; handle < IPXSOCKETS; handle++)
|
|
{
|
|
if (ipxsocket[handle] == 0)
|
|
{
|
|
ipxsocket[handle] = socket;
|
|
readlist[handle] = NULL;
|
|
sequence[handle] = 0;
|
|
for (n = 0; n < IPXSOCKBUFFERS; n ++)
|
|
{
|
|
lma->socketbuffer[handle][n].ecb.socket = socket;
|
|
lma->socketbuffer[handle][n].ecb.inUse = 0;
|
|
if (n)
|
|
IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb);
|
|
}
|
|
handlesInUse++;
|
|
return handle;
|
|
}
|
|
}
|
|
|
|
// "this will NEVER happen"
|
|
Sys_Error("IPX_OpenSocket: handle allocation failed\n");
|
|
return -1;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_CloseSocket(int handle)
|
|
{
|
|
// if there's a send in progress, give it one last chance
|
|
if (lma->socketbuffer[handle][0].ecb.inUse != 0)
|
|
IPX_RelinquishControl();
|
|
|
|
// close the socket (all pending sends/received are cancelled)
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_CLOSE;
|
|
regs.x.dx = ipxsocket[handle];
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
|
|
ipxsocket[handle] = 0;
|
|
handlesInUse--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_Connect (int handle, struct qsockaddr *addr)
|
|
{
|
|
IPXaddr ipxaddr;
|
|
|
|
Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
|
|
if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
|
|
{
|
|
Con_Printf("Get Local Target failed\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_CheckNewConnections (void)
|
|
{
|
|
int n;
|
|
|
|
if (net_acceptsocket == -1)
|
|
return -1;
|
|
|
|
for (n = 1; n < IPXSOCKBUFFERS; n ++)
|
|
if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0)
|
|
return net_acceptsocket;
|
|
return -1;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr)
|
|
{
|
|
ECB *ecb;
|
|
ipx_lowmem_buffer_t *rcvbuf;
|
|
int copylen;
|
|
|
|
ProcessReadyList(handle);
|
|
tryagain:
|
|
if (readlist[handle] == NULL)
|
|
return 0;
|
|
ecb = readlist[handle];
|
|
readlist[handle] = ecb->link;
|
|
|
|
if (ecb->completionCode != 0)
|
|
{
|
|
Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode);
|
|
ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
|
IPX_ListenForPacket(ecb);
|
|
goto tryagain;
|
|
}
|
|
|
|
rcvbuf = (ipx_lowmem_buffer_t *)ecb;
|
|
|
|
// copy the data up to the buffer
|
|
copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader));
|
|
if (len < copylen)
|
|
Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen);
|
|
Q_memcpy(buf, rcvbuf->data, copylen);
|
|
|
|
// fill in the addr if they want it
|
|
if (addr)
|
|
{
|
|
((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE;
|
|
Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr));
|
|
((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0;
|
|
((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0;
|
|
}
|
|
|
|
// update the send ecb's immediate address
|
|
Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6);
|
|
|
|
// get this ecb listening again
|
|
rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
|
|
IPX_ListenForPacket(&rcvbuf->ecb);
|
|
return copylen;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_Broadcast (int handle, byte *buf, int len)
|
|
{
|
|
struct sockaddr_ipx addr;
|
|
int ret;
|
|
|
|
Q_memset(addr.sipx_addr.network, 0x00, 4);
|
|
Q_memset(addr.sipx_addr.node, 0xff, 6);
|
|
addr.sipx_port = htons(net_hostport);
|
|
Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6);
|
|
ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr);
|
|
return ret;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr)
|
|
{
|
|
// has the previous send completed?
|
|
while (lma->socketbuffer[handle][0].ecb.inUse != 0)
|
|
IPX_RelinquishControl();
|
|
|
|
switch (lma->socketbuffer[handle][0].ecb.completionCode)
|
|
{
|
|
case 0x00: // success
|
|
case 0xfc: // request cancelled
|
|
break;
|
|
|
|
case 0xfd: // malformed packet
|
|
default:
|
|
Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode);
|
|
break;
|
|
|
|
case 0xfe: // packet undeliverable
|
|
case 0xff: // unable to send packet
|
|
Con_Printf("IPX lost route, trying to re-establish\n");
|
|
|
|
// look for a new route
|
|
if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
|
|
return -1;
|
|
|
|
// re-send the one that failed
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_SEND;
|
|
regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
|
|
regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
|
|
// report that we did not send the current one
|
|
return 0;
|
|
}
|
|
|
|
// ecb : length
|
|
lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len;
|
|
|
|
// ipx header : type
|
|
lma->socketbuffer[handle][0].header.type = PTYPE_IPX;
|
|
|
|
// ipx header : destination
|
|
Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
|
|
|
|
// sequence number
|
|
lma->socketbuffer[handle][0].sequence = sequence[handle];
|
|
sequence[handle]++;
|
|
|
|
// copy down the data
|
|
Q_memcpy(lma->socketbuffer[handle][0].data, buf, len);
|
|
|
|
regs.x.cs = ipx_cs;
|
|
regs.x.ip = ipx_ip;
|
|
regs.x.bx = IPX_SEND;
|
|
regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
|
|
regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
|
|
__dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
|
|
|
|
return len;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
char *IPX_AddrToString (struct qsockaddr *addr)
|
|
{
|
|
static char buf[28];
|
|
|
|
sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.network[0],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.network[1],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.network[2],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.network[3],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[0],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[1],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[2],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[3],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[4],
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.node[5],
|
|
ntohs(((struct sockaddr_ipx *)addr)->sipx_port)
|
|
);
|
|
return buf;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_StringToAddr (char *string, struct qsockaddr *addr)
|
|
{
|
|
int val;
|
|
char buf[3];
|
|
|
|
buf[2] = 0;
|
|
Q_memset(addr, 0, sizeof(struct qsockaddr));
|
|
addr->sa_family = AF_NETWARE;
|
|
|
|
#define DO(src,dest) \
|
|
buf[0] = string[src]; \
|
|
buf[1] = string[src + 1]; \
|
|
if (sscanf (buf, "%x", &val) != 1) \
|
|
return -1; \
|
|
((struct sockaddr_ipx *)addr)->sipx_addr.dest = val
|
|
|
|
DO(0, network[0]);
|
|
DO(2, network[1]);
|
|
DO(4, network[2]);
|
|
DO(6, network[3]);
|
|
DO(9, node[0]);
|
|
DO(11, node[1]);
|
|
DO(13, node[2]);
|
|
DO(15, node[3]);
|
|
DO(17, node[4]);
|
|
DO(19, node[5]);
|
|
#undef DO
|
|
|
|
sscanf (&string[22], "%u", &val);
|
|
((struct sockaddr_ipx *)addr)->sipx_port = htons(val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_GetSocketAddr (int handle, struct qsockaddr *addr)
|
|
{
|
|
Q_memset(addr, 0, sizeof(struct qsockaddr));
|
|
addr->sa_family = AF_NETWARE;
|
|
IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr);
|
|
((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle];
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
|
|
{
|
|
Q_strcpy(name, IPX_AddrToString(addr));
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_GetAddrFromName (char *name, struct qsockaddr *addr)
|
|
{
|
|
int n;
|
|
char buf[32];
|
|
|
|
n = Q_strlen(name);
|
|
|
|
if (n == 12)
|
|
{
|
|
sprintf(buf, "00000000:%s:%u", name, net_hostport);
|
|
return IPX_StringToAddr (buf, addr);
|
|
}
|
|
if (n == 21)
|
|
{
|
|
sprintf(buf, "%s:%u", name, net_hostport);
|
|
return IPX_StringToAddr (buf, addr);
|
|
}
|
|
if (n > 21 && n <= 27)
|
|
return IPX_StringToAddr (name, addr);
|
|
|
|
return -1;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
|
|
{
|
|
if (addr1->sa_family != addr2->sa_family)
|
|
return -1;
|
|
|
|
if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10))
|
|
return -1;
|
|
|
|
if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|
|
|
|
int IPX_GetSocketPort (struct qsockaddr *addr)
|
|
{
|
|
return ntohs(((struct sockaddr_ipx *)addr)->sipx_port);
|
|
}
|
|
|
|
|
|
int IPX_SetSocketPort (struct qsockaddr *addr, int port)
|
|
{
|
|
((struct sockaddr_ipx *)addr)->sipx_port = htons(port);
|
|
return 0;
|
|
}
|
|
|
|
//=============================================================================
|