home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / net_ipx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-17  |  18.3 KB  |  707 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // net_ipx.c
  21.  
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <dpmi.h>
  25.  
  26. #include "quakedef.h"
  27. #include "dosisms.h"
  28. #include "net_ipx.h"
  29.  
  30. #define EIO       5 /* I/O error */
  31.  
  32. #define AF_NETWARE    64
  33.  
  34. #define IPX_OPEN          0
  35. #define IPX_CLOSE         1
  36. #define IPX_GETROUTE        2
  37. #define IPX_SEND          3
  38. #define IPX_LISTEN          4
  39. #define IPX_SCHEDULEEVENT     5
  40. #define IPX_CANCEL          6
  41. #define IPX_SCHEDULESPECIALEVENT  7
  42. #define IPX_GETINTERVALMARKER   8
  43. #define IPX_GETADDRESS        9
  44. #define IPX_RELINQUISH        10
  45.  
  46. #define PTYPE_UNKNOWN       0
  47. #define PTYPE_RIP         1
  48. #define PTYPE_ECHO          2
  49. #define PTYPE_ERROR         3
  50. #define PTYPE_IPX         4
  51. #define PTYPE_SPX         5
  52.  
  53. #pragma pack(1)
  54.  
  55. typedef struct
  56. {
  57.   byte  network[4];
  58.   byte  node[6];
  59.   short socket;
  60. } IPXaddr;
  61.  
  62. struct sockaddr_ipx
  63. {
  64.     short     sipx_family;
  65.   IPXaddr     sipx_addr;
  66.     char      sipx_zero[2];
  67. };
  68. #define sipx_port sipx_addr.socket
  69.  
  70. typedef struct
  71. {
  72.   short     checkSum;
  73.   short     length;
  74.   byte      transportControl;
  75.   byte      type;
  76.   IPXaddr     destination;
  77.   IPXaddr     source;
  78. } IPXheader;
  79.  
  80. typedef struct ECBStructure
  81. {
  82.   struct ECBStructure *link;
  83.   unsigned short  ESR_off;
  84.   unsigned short  ESR_seg;
  85.   byte  inUse;
  86.   byte  completionCode;
  87.   short socket;
  88.   byte  IPXWorkspace[4];
  89.   byte  driverWorkspace[12];
  90.   byte  immediateAddress[6];
  91.   short fragCount;
  92.   short fragOff;
  93.   short fragSeg;
  94.   short fragSize;
  95. } ECB;
  96.  
  97. #pragma pack()
  98.  
  99. typedef struct
  100. {
  101.   ECB     ecb;
  102.   IPXheader header;
  103.   int     sequence;
  104.   char    data[NET_DATAGRAMSIZE];
  105. } ipx_lowmem_buffer_t;
  106.  
  107. #define LOWMEMSIZE    (100 * 1024)
  108. #define LOWMEMSAVE    256
  109. #define IPXBUFFERS    ((LOWMEMSIZE - LOWMEMSAVE)/ sizeof(ipx_lowmem_buffer_t))
  110. #define IPXSOCKBUFFERS  5
  111. #define IPXSOCKETS    (IPXBUFFERS / IPXSOCKBUFFERS)
  112.  
  113. // each socket's socketbuffer 0 is used for sending, the others for listening
  114.  
  115. typedef struct
  116. {
  117.   char        reserved[LOWMEMSAVE];
  118.   ipx_lowmem_buffer_t socketbuffer[IPXSOCKETS][IPXSOCKBUFFERS];
  119. } ipx_lowmem_area_t;
  120.  
  121.  
  122. static int ipxsocket[IPXSOCKETS];
  123. static ECB *readlist[IPXSOCKETS];
  124. static int sequence[IPXSOCKETS];
  125. static int handlesInUse;
  126. static ipx_lowmem_area_t *lma;
  127. static char *lowmem_buffer;
  128. static int lowmem_bufseg;
  129. static int lowmem_bufoff;
  130. static unsigned short ipx_cs;
  131. static unsigned short ipx_ip;
  132. static int net_acceptsocket = -1;
  133. static int net_controlsocket;
  134.  
  135. static void IPX_PollProcedure(void);
  136. static PollProcedure pollProcedure = {NULL, 0.0, IPX_PollProcedure};
  137.  
  138. //=============================================================================
  139.  
  140. static void IPX_GetLocalAddress(IPXaddr *addr)
  141. {
  142.   regs.x.cs = ipx_cs;
  143.   regs.x.ip = ipx_ip;
  144.   regs.x.bx = IPX_GETADDRESS;
  145.   regs.x.es = lowmem_bufseg;
  146.   regs.x.si = lowmem_bufoff;
  147.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  148.   Q_memcpy(addr, lowmem_buffer, 10);
  149. }
  150.  
  151. //=============================================================================
  152.  
  153. static int IPX_GetLocalTarget(IPXaddr *addr, byte *localTarget)
  154. {
  155.   regs.x.cs = ipx_cs;
  156.   regs.x.ip = ipx_ip;
  157.   regs.x.bx = IPX_GETROUTE;
  158.   regs.x.es = lowmem_bufseg;
  159.   regs.x.si = lowmem_bufoff;
  160.   regs.x.di = lowmem_bufoff + sizeof(IPXaddr);
  161.   Q_memcpy(lowmem_buffer, addr, sizeof(IPXaddr));
  162.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  163.   if (regs.h.al)
  164.     return -1;
  165.   Q_memcpy(localTarget, lowmem_buffer + sizeof(IPXaddr), 6);
  166.   return 0;
  167. }
  168.  
  169. //=============================================================================
  170.  
  171. static void IPX_ListenForPacket(ECB *ecb)
  172. {
  173.   regs.x.cs = ipx_cs;
  174.   regs.x.ip = ipx_ip;
  175.   regs.x.bx = IPX_LISTEN;
  176.   regs.x.es = ptr2real(ecb) >> 4;
  177.   regs.x.si = ptr2real(ecb) & 0xf;
  178.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  179. }
  180.  
  181. //=============================================================================
  182.  
  183. static void IPX_RelinquishControl(void)
  184. {
  185.   regs.x.cs = ipx_cs;
  186.   regs.x.ip = ipx_ip;
  187.   regs.x.bx = IPX_RELINQUISH;
  188.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  189. }
  190.  
  191.  
  192. void IPX_PollProcedure(void)
  193. {
  194.   IPX_RelinquishControl();
  195.   SchedulePollProcedure(&pollProcedure, 0.01);
  196. }
  197.  
  198. //=============================================================================
  199.  
  200. static void ProcessReadyList(int s)
  201. {
  202.   int n;
  203.   ECB *ecb;
  204.   ECB *prev;
  205.  
  206.   for (n = 1; n < IPXSOCKBUFFERS; n++)
  207.   {
  208.     if (lma->socketbuffer[s][n].ecb.inUse == 0)
  209.     {
  210.       for (ecb = readlist[s], prev = NULL; ecb; ecb = ecb->link)
  211.       {
  212.         if (lma->socketbuffer[s][n].sequence < ((ipx_lowmem_buffer_t *) ecb)->sequence)
  213.           break;
  214.         prev = ecb;
  215.       }
  216.       if (ecb)
  217.         lma->socketbuffer[s][n].ecb.link = ecb;
  218.       else
  219.         lma->socketbuffer[s][n].ecb.link = NULL;
  220.       if (prev)
  221.         prev->link = &lma->socketbuffer[s][n].ecb;
  222.       else
  223.         readlist[s] = &lma->socketbuffer[s][n].ecb;
  224.       lma->socketbuffer[s][n].ecb.inUse = 0xff;
  225.     }
  226.   }
  227. }
  228.  
  229. //=============================================================================
  230.  
  231. int IPX_Init(void)
  232. {
  233.   int s;
  234.   int n;
  235.   struct qsockaddr addr;
  236.   char *colon;
  237.  
  238.   if (COM_CheckParm ("-noipx"))
  239.     return -1;
  240.  
  241.   // find the IPX far call entry point
  242.   regs.x.ax = 0x7a00;
  243.   __dpmi_simulate_real_mode_interrupt (0x2f, (__dpmi_regs *)®s);
  244.   if (regs.h.al != 0xff)
  245.   {
  246.     Con_Printf("IPX not detected\n");
  247.     return -1;
  248.   }
  249.   ipx_cs = regs.x.es;
  250.   ipx_ip = regs.x.di;
  251.  
  252.   // grab a chunk of memory down in DOS land
  253.   lowmem_buffer = dos_getmemory(LOWMEMSIZE);
  254.   if (!lowmem_buffer)
  255.   {
  256.     Con_Printf("IPX_Init: Not enough low memory\n");
  257.     return -1;
  258.   }
  259.   lowmem_bufoff = ptr2real(lowmem_buffer) & 0xf;
  260.   lowmem_bufseg = ptr2real(lowmem_buffer) >> 4;
  261.  
  262.   // init socket handles & buffers
  263.   handlesInUse = 0;
  264.   lma = (ipx_lowmem_area_t *)lowmem_buffer;
  265.   for (s = 0; s < IPXSOCKETS; s++)
  266.   {
  267.     ipxsocket[s] = 0;
  268.     for (n = 0; n < IPXSOCKBUFFERS; n++)
  269.     {
  270.       lma->socketbuffer[s][n].ecb.link = NULL;
  271.       lma->socketbuffer[s][n].ecb.ESR_off = 0;
  272.       lma->socketbuffer[s][n].ecb.ESR_seg = 0;
  273.       lma->socketbuffer[s][n].ecb.socket = 0;
  274.       lma->socketbuffer[s][n].ecb.inUse = 0xff;
  275.       lma->socketbuffer[s][n].ecb.completionCode = 0;
  276.       lma->socketbuffer[s][n].ecb.fragCount = 1;
  277.       lma->socketbuffer[s][n].ecb.fragOff = ptr2real(&lma->socketbuffer[s][n].header) & 0xf;
  278.       lma->socketbuffer[s][n].ecb.fragSeg = ptr2real(&lma->socketbuffer[s][n].header) >> 4;
  279.       lma->socketbuffer[s][n].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  280.     }
  281.   }
  282.  
  283.   if ((net_controlsocket = IPX_OpenSocket (0)) == -1)
  284.   {
  285.     dos_freememory(lowmem_buffer);
  286.     Con_DPrintf ("IPX_Init: Unable to open control socket\n");
  287.     return -1;
  288.   }
  289.  
  290.   SchedulePollProcedure(&pollProcedure, 0.01);
  291.  
  292.   IPX_GetSocketAddr (net_controlsocket, &addr);
  293.   Q_strcpy(my_ipx_address,  IPX_AddrToString (&addr));
  294.   colon = Q_strrchr (my_ipx_address, ':');
  295.   if (colon)
  296.     *colon = 0;
  297.  
  298.   Con_Printf("IPX initialized\n");
  299.   ipxAvailable = true;
  300.   return net_controlsocket;
  301. }
  302.  
  303. //=============================================================================
  304.  
  305. void IPX_Shutdown(void)
  306. {
  307.   IPX_Listen (false);
  308.   IPX_CloseSocket (net_controlsocket);
  309.   dos_freememory(lowmem_buffer);
  310. }
  311.  
  312. //=============================================================================
  313.  
  314. void IPX_Listen (qboolean state)
  315. {
  316.   // enable listening
  317.   if (state)
  318.   {
  319.     if (net_acceptsocket != -1)
  320.       return;
  321.     if ((net_acceptsocket = IPX_OpenSocket (net_hostport)) == -1)
  322.       Sys_Error ("IPX_Listen: Unable to open accept socket\n");
  323.     return;
  324.   }
  325.  
  326.   // disable listening
  327.   if (net_acceptsocket == -1)
  328.     return;
  329.   IPX_CloseSocket (net_acceptsocket);
  330.   net_acceptsocket = -1;
  331. }
  332.  
  333. //=============================================================================
  334.  
  335. int IPX_OpenSocket(int port)
  336. {
  337.   int handle;
  338.   int n;
  339.   unsigned short socket;
  340.  
  341.   if (handlesInUse == IPXSOCKETS)
  342.     return -1;
  343.  
  344.   // open the IPX socket
  345.   regs.x.cs = ipx_cs;
  346.   regs.x.ip = ipx_ip;
  347.   regs.x.bx = IPX_OPEN;
  348.   regs.h.al = 0;
  349.   regs.x.dx = htons(port);
  350.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  351.   if (regs.h.al == 0xfe)
  352.   {
  353.     Con_DPrintf("IPX_OpenSocket: all sockets in use\n");
  354.     return -1;
  355.   }
  356.   if (regs.h.al == 0xff)
  357.   {
  358.     Con_DPrintf("IPX_OpenSocket: socket already open\n");
  359.     return -1;
  360.   }
  361.   if (regs.h.al != 0)
  362.   {
  363.     Con_DPrintf("IPX_OpenSocket: error %02x\n", regs.h.al);
  364.     return -1;
  365.   }
  366.   socket = regs.x.dx;
  367.  
  368. // grab a handle; fill in the ECBs, and get them listening
  369.   for (handle = 0; handle < IPXSOCKETS; handle++)
  370.   {
  371.     if (ipxsocket[handle] == 0)
  372.     {
  373.       ipxsocket[handle] = socket;
  374.       readlist[handle] = NULL;
  375.       sequence[handle] = 0;
  376.       for (n = 0; n < IPXSOCKBUFFERS; n ++)
  377.       {
  378.         lma->socketbuffer[handle][n].ecb.socket = socket;
  379.         lma->socketbuffer[handle][n].ecb.inUse = 0;
  380.         if (n)
  381.           IPX_ListenForPacket(&lma->socketbuffer[handle][n].ecb);
  382.       }
  383.       handlesInUse++;
  384.       return handle;
  385.     }
  386.   }
  387.  
  388.   // "this will NEVER happen"
  389.   Sys_Error("IPX_OpenSocket: handle allocation failed\n");
  390.   return -1;
  391. }
  392.  
  393. //=============================================================================
  394.  
  395. int IPX_CloseSocket(int handle)
  396. {
  397.   // if there's a send in progress, give it one last chance
  398.   if (lma->socketbuffer[handle][0].ecb.inUse != 0)
  399.     IPX_RelinquishControl();
  400.  
  401.   // close the socket (all pending sends/received are cancelled)
  402.   regs.x.cs = ipx_cs;
  403.   regs.x.ip = ipx_ip;
  404.   regs.x.bx = IPX_CLOSE;
  405.   regs.x.dx = ipxsocket[handle];
  406.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  407.  
  408.   ipxsocket[handle] = 0;
  409.   handlesInUse--;
  410.  
  411.   return 0;
  412. }
  413.  
  414. //=============================================================================
  415.  
  416. int IPX_Connect (int handle, struct qsockaddr *addr)
  417. {
  418.   IPXaddr ipxaddr;
  419.  
  420.   Q_memcpy(&ipxaddr, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
  421.   if (IPX_GetLocalTarget(&ipxaddr, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
  422.   {
  423.     Con_Printf("Get Local Target failed\n");
  424.     return -1;
  425.   }
  426.  
  427.   return 0;
  428. }
  429.  
  430. //=============================================================================
  431.  
  432. int IPX_CheckNewConnections (void)
  433. {
  434.   int n;
  435.  
  436.   if (net_acceptsocket == -1)
  437.     return -1;
  438.  
  439.   for (n = 1; n < IPXSOCKBUFFERS; n ++)
  440.     if (lma->socketbuffer[net_acceptsocket][n].ecb.inUse == 0)
  441.       return net_acceptsocket;
  442.   return -1;
  443. }
  444.  
  445. //=============================================================================
  446.  
  447. int IPX_Read (int handle, byte *buf, int len, struct qsockaddr *addr)
  448. {
  449.   ECB   *ecb;
  450.   ipx_lowmem_buffer_t *rcvbuf;
  451.   int   copylen;
  452.  
  453.   ProcessReadyList(handle);
  454. tryagain:
  455.   if (readlist[handle] == NULL)
  456.     return 0;
  457.   ecb = readlist[handle];
  458.   readlist[handle] = ecb->link;
  459.  
  460.   if (ecb->completionCode != 0)
  461.   {
  462.     Con_Printf("Warning: IPX_Read error %02x\n", ecb->completionCode);  
  463.     ecb->fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  464.     IPX_ListenForPacket(ecb);
  465.     goto tryagain;
  466.   }
  467.  
  468.   rcvbuf = (ipx_lowmem_buffer_t *)ecb;
  469.  
  470.   // copy the data up to the buffer
  471.   copylen = ntohs(rcvbuf->header.length) - (sizeof(int) + sizeof(IPXheader));
  472.   if (len < copylen)
  473.     Sys_Error("IPX_Read: buffer too small (%d vs %d)\n", len, copylen);
  474.   Q_memcpy(buf, rcvbuf->data, copylen);
  475.  
  476.   // fill in the addr if they want it
  477.   if (addr)
  478.   {
  479.     ((struct sockaddr_ipx *)addr)->sipx_family = AF_NETWARE;
  480.     Q_memcpy(&((struct sockaddr_ipx *)addr)->sipx_addr, rcvbuf->header.source.network, sizeof(IPXaddr));
  481.     ((struct sockaddr_ipx *)addr)->sipx_zero[0] = 0;
  482.     ((struct sockaddr_ipx *)addr)->sipx_zero[1] = 0;
  483.   }
  484.  
  485.   // update the send ecb's immediate address
  486.   Q_memcpy(lma->socketbuffer[handle][0].ecb.immediateAddress, rcvbuf->ecb.immediateAddress, 6);
  487.  
  488.   // get this ecb listening again
  489.   rcvbuf->ecb.fragSize = sizeof(IPXheader) + sizeof(int) + NET_DATAGRAMSIZE;
  490.   IPX_ListenForPacket(&rcvbuf->ecb);
  491.   return copylen;
  492. }
  493.  
  494. //=============================================================================
  495.  
  496. int IPX_Broadcast (int handle, byte *buf, int len)
  497. {
  498.   struct sockaddr_ipx addr;
  499.   int ret;
  500.  
  501.   Q_memset(addr.sipx_addr.network, 0x00, 4);
  502.   Q_memset(addr.sipx_addr.node, 0xff, 6);
  503.   addr.sipx_port = htons(net_hostport);
  504.   Q_memset(lma->socketbuffer[handle][0].ecb.immediateAddress, 0xff, 6);
  505.   ret = IPX_Write (handle, buf, len, (struct qsockaddr *)&addr);
  506.   return ret;
  507. }
  508.  
  509. //=============================================================================
  510.  
  511. int IPX_Write (int handle, byte *buf, int len, struct qsockaddr *addr)
  512. {
  513.   // has the previous send completed?
  514.   while (lma->socketbuffer[handle][0].ecb.inUse != 0)
  515.     IPX_RelinquishControl();
  516.  
  517.   switch (lma->socketbuffer[handle][0].ecb.completionCode)
  518.   {
  519.     case 0x00: // success
  520.     case 0xfc: // request cancelled
  521.       break;
  522.  
  523.     case 0xfd: // malformed packet
  524.     default:
  525.       Con_Printf("IPX driver send failure: %02x\n", lma->socketbuffer[handle][0].ecb.completionCode);
  526.       break;
  527.  
  528.     case 0xfe: // packet undeliverable
  529.     case 0xff: // unable to send packet
  530.       Con_Printf("IPX lost route, trying to re-establish\n");
  531.  
  532.       // look for a new route
  533.       if (IPX_GetLocalTarget (&lma->socketbuffer[handle][0].header.destination, lma->socketbuffer[handle][0].ecb.immediateAddress) != 0)
  534.         return -1;
  535.  
  536.       // re-send the one that failed
  537.       regs.x.cs = ipx_cs;
  538.       regs.x.ip = ipx_ip;
  539.       regs.x.bx = IPX_SEND;
  540.       regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
  541.       regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
  542.       __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  543.  
  544.       // report that we did not send the current one
  545.       return 0;
  546.   }
  547.  
  548.   // ecb : length
  549.   lma->socketbuffer[handle][0].ecb.fragSize = sizeof(IPXheader) + sizeof(int) + len;
  550.  
  551.   // ipx header : type
  552.   lma->socketbuffer[handle][0].header.type = PTYPE_IPX;
  553.  
  554.   // ipx header : destination
  555.   Q_memcpy(&lma->socketbuffer[handle][0].header.destination, &((struct sockaddr_ipx *)addr)->sipx_addr, sizeof(IPXaddr));
  556.  
  557.   // sequence number
  558.   lma->socketbuffer[handle][0].sequence = sequence[handle];
  559.   sequence[handle]++;
  560.  
  561.   // copy down the data
  562.   Q_memcpy(lma->socketbuffer[handle][0].data, buf, len);
  563.  
  564.   regs.x.cs = ipx_cs;
  565.   regs.x.ip = ipx_ip;
  566.   regs.x.bx = IPX_SEND;
  567.   regs.x.es = ptr2real(&lma->socketbuffer[handle][0].ecb) >> 4;
  568.   regs.x.si = ptr2real(&lma->socketbuffer[handle][0].ecb) & 0xf;
  569.   __dpmi_simulate_real_mode_procedure_retf((__dpmi_regs *)®s);
  570.  
  571.   return len;
  572. }
  573.  
  574. //=============================================================================
  575.  
  576. char *IPX_AddrToString (struct qsockaddr *addr)
  577. {
  578.   static char buf[28];
  579.  
  580.   sprintf(buf, "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%u",
  581.     ((struct sockaddr_ipx *)addr)->sipx_addr.network[0],
  582.     ((struct sockaddr_ipx *)addr)->sipx_addr.network[1],
  583.     ((struct sockaddr_ipx *)addr)->sipx_addr.network[2],
  584.     ((struct sockaddr_ipx *)addr)->sipx_addr.network[3],
  585.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[0],
  586.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[1],
  587.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[2],
  588.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[3],
  589.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[4],
  590.     ((struct sockaddr_ipx *)addr)->sipx_addr.node[5],
  591.     ntohs(((struct sockaddr_ipx *)addr)->sipx_port)
  592.     );
  593.   return buf;
  594. }
  595.  
  596. //=============================================================================
  597.  
  598. int IPX_StringToAddr (char *string, struct qsockaddr *addr)
  599. {
  600.   int  val;
  601.   char buf[3];
  602.  
  603.   buf[2] = 0;
  604.   Q_memset(addr, 0, sizeof(struct qsockaddr));
  605.   addr->sa_family = AF_NETWARE;
  606.  
  607. #define DO(src,dest)  \
  608.   buf[0] = string[src]; \
  609.   buf[1] = string[src + 1]; \
  610.   if (sscanf (buf, "%x", &val) != 1)  \
  611.     return -1;  \
  612.   ((struct sockaddr_ipx *)addr)->sipx_addr.dest = val
  613.  
  614.   DO(0, network[0]);
  615.   DO(2, network[1]);
  616.   DO(4, network[2]);
  617.   DO(6, network[3]);
  618.   DO(9, node[0]);
  619.   DO(11, node[1]);
  620.   DO(13, node[2]);
  621.   DO(15, node[3]);
  622.   DO(17, node[4]);
  623.   DO(19, node[5]);
  624. #undef DO
  625.  
  626.   sscanf (&string[22], "%u", &val);
  627.   ((struct sockaddr_ipx *)addr)->sipx_port = htons(val);
  628.  
  629.   return 0;
  630. }
  631.  
  632. //=============================================================================
  633.  
  634. int IPX_GetSocketAddr (int handle, struct qsockaddr *addr)
  635. {
  636.   Q_memset(addr, 0, sizeof(struct qsockaddr));
  637.   addr->sa_family = AF_NETWARE;
  638.   IPX_GetLocalAddress(&((struct sockaddr_ipx *)addr)->sipx_addr);
  639.   ((struct sockaddr_ipx *)addr)->sipx_port = ipxsocket[handle];
  640.   return 0;
  641. }
  642.  
  643. //=============================================================================
  644.  
  645. int IPX_GetNameFromAddr (struct qsockaddr *addr, char *name)
  646. {
  647.   Q_strcpy(name, IPX_AddrToString(addr));
  648.   return 0;
  649. }
  650.  
  651. //=============================================================================
  652.  
  653. int IPX_GetAddrFromName (char *name, struct qsockaddr *addr)
  654. {
  655.   int n;
  656.   char buf[32];
  657.  
  658.   n = Q_strlen(name);
  659.  
  660.   if (n == 12)
  661.   {
  662.     sprintf(buf, "00000000:%s:%u", name, net_hostport);
  663.     return IPX_StringToAddr (buf, addr);
  664.   }
  665.   if (n == 21)
  666.   {
  667.     sprintf(buf, "%s:%u", name, net_hostport);
  668.     return IPX_StringToAddr (buf, addr);
  669.   }
  670.   if (n > 21 && n <= 27)
  671.     return IPX_StringToAddr (name, addr);
  672.  
  673.   return -1;
  674. }
  675.  
  676. //=============================================================================
  677.  
  678. int IPX_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)
  679. {
  680.   if (addr1->sa_family != addr2->sa_family)
  681.     return -1;
  682.  
  683.   if(Q_memcmp(&((struct sockaddr_ipx *)addr1)->sipx_addr, &((struct sockaddr_ipx *)addr2)->sipx_addr, 10))
  684.     return -1;
  685.  
  686.   if (((struct sockaddr_ipx *)addr1)->sipx_port != ((struct sockaddr_ipx *)addr2)->sipx_port)
  687.     return 1;
  688.  
  689.   return 0;
  690. }
  691.  
  692. //=============================================================================
  693.  
  694. int IPX_GetSocketPort (struct qsockaddr *addr)
  695. {
  696.   return ntohs(((struct sockaddr_ipx *)addr)->sipx_port);
  697. }
  698.  
  699.  
  700. int IPX_SetSocketPort (struct qsockaddr *addr, int port)
  701. {
  702.   ((struct sockaddr_ipx *)addr)->sipx_port = htons(port);
  703.   return 0;
  704. }
  705.  
  706. //=============================================================================
  707.