📄 net_ipx.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);
strcpy(my_ipx_address, IPX_AddrToString (&addr));
colon = 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -