Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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 *)&regs);
  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.