net_ipx.c 18 KB

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