]> icculus.org git repositories - btb/d2x.git/blob - unused/win95/ipx.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / unused / win95 / ipx.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #define WIN32_LEAN_AND_MEAN
16 #include <windows.h>
17 #include <windowsx.h>
18 #include <winsock.h>
19 #include <wsipx.h>
20
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <malloc.h>
25 #include <stdlib.h>
26 #include <conio.h>
27
28
29 #include "pstypes.h"
30 #include "winapp.h"
31 #include "ipx.h"
32 #include "dxxerror.h"
33 #include "mono.h"
34
35
36
37 //      ---------------------------------------------------------------------------
38
39 #define NUM_IPX_PACKETS 32
40
41 #define MAX_USERS               64
42 #define MAX_SUBNETS     64
43 #define MAX_PACKETS     64
44
45
46 typedef struct tIpxNetworkID {
47         BYTE b[4];
48 } tIpxNetworkID;  
49
50 typedef struct tIpxAddrGeneric { 
51         BYTE b[6]; 
52 } tIpxAddrGeneric;
53
54 typedef struct tIpxNetAddr {
55         tIpxNetworkID net_id;
56         tIpxAddrGeneric node_addr;
57         WORD ipx_socket;
58 } tIpxNetAddr;
59
60 typedef struct tIpxUserAddr {
61         tIpxNetworkID net_id;
62         tIpxAddrGeneric node_addr;
63         tIpxAddrGeneric addr;
64 } tIpxUserAddr;
65
66 typedef struct tIpxPacket {
67         tIpxNetAddr saddr;
68         tIpxNetAddr daddr;
69         int in_use;
70         int datalen;
71         int packetnum;
72         ubyte data[IPX_MAX_DATA_SIZE];
73 } tIpxPacket;
74
75
76 typedef struct tPacket {
77         int free;
78         int size;
79         int packetnum;
80         ubyte data[IPX_MAX_DATA_SIZE];
81 } tPacket;
82
83
84
85 //      ---------------------------------------------------------------------------
86 //      Data
87 // ---------------------------------------------------------------------------
88
89 static ubyte                                    ipx_installed = 0;
90 static int                                              neterrors = 0;
91
92 static int                                              NumIPXUsers = 0;
93 static tIpxUserAddr                     IPXUsers[MAX_USERS];
94
95 static int                                              NumIPXSubnet = 0;
96 static tIpxNetworkID            IPXSubnetID[MAX_SUBNETS];
97
98 static tIpxPacket                               *IPXPackets = NULL;
99 static int                                              IPXPacketNum = 0;
100
101 static SOCKET                                   WinSocket = 0;
102 static WORD                                             IPXSocket = 0;
103 static tIpxNetworkID                    ThisIPXSubnet;
104 static tIpxAddrGeneric          ThisIPXNode;
105
106 static int                                              PacketListTail, PacketListCur;
107 static tPacket                                  *PacketList;
108
109
110
111 //      ---------------------------------------------------------------------------
112 //      Function Prototypes
113 //      ---------------------------------------------------------------------------
114
115 uint wipx_init();
116 uint wipx_open_socket(int sock_num, SOCKET *sock_id, WORD *ipx_socket);
117 uint wipx_close_socket(SOCKET sock_id);
118 uint wipx_get_socket_addr(SOCKET sock_id, tIpxNetworkID *net_addr, tIpxAddrGeneric *node_addr);
119 uint wipx_set_socket_mode_bool(SOCKET sock_id, int opt, BOOL toggle);
120 uint wipx_socket_listen(SOCKET sock_id, tIpxPacket *packet);
121 uint wipx_socket_send(SOCKET sock_id, tIpxPacket *packet);
122 uint wipx_close(); 
123 uint wipx_logerror(uint ipx_result, char *text);
124
125 void got_new_packet( tIpxPacket *packet );
126 void free_packet( int id );
127 void ipx_close();
128
129 ubyte *ipx_get_my_local_address() {
130         return (ubyte *)&ThisIPXNode;
131 }
132
133 ubyte *ipx_get_my_server_address() {
134   return (ubyte *)&ThisIPXSubnet;
135 }
136
137 void ipx_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
138 {
139         memset(local_target, 0, 6);
140 }
141
142
143
144 //      ---------------------------------------------------------------------------
145 //      Functions
146 //      ---------------------------------------------------------------------------     
147
148 //---------------------------------------------------------------
149 // Initializes all IPX internals. 
150 // If socket_number==0, then opens next available socket.
151 // Returns:     0  if successful.
152 //                              -1 if socket already open.
153 //                              -2      if socket table full.
154 //                              -3 if IPX not installed.
155 //                              -4 if couldn't allocate memory
156 //                              -5 if error with getting internetwork address
157
158 int ipx_init(int socket_number, int show_address)
159 {
160         int i;
161         uint ipx_result;
162
163         atexit(ipx_close);
164
165 //      Establish Winsock IPX Link.
166         ipx_result = wipx_init();
167         if (ipx_result) return -3;
168
169         ipx_result = wipx_open_socket(socket_number, &WinSocket, &IPXSocket);
170         if (ipx_result) {
171                 if (ipx_result == WSAEPROTONOSUPPORT) return -3;
172                 if (ipx_result == WSAENOBUFS) return -2;
173                 return -1;
174         }
175
176 //      Get this station's IPX address.
177         ipx_result = wipx_get_socket_addr(WinSocket, &ThisIPXSubnet, &ThisIPXNode);
178         if (ipx_result) return -5;
179         NumIPXSubnet = 0;
180         memcpy(&IPXSubnetID[NumIPXSubnet++], &ThisIPXSubnet, sizeof(tIpxNetworkID));    
181
182 //      Initialize packet buffers
183         PacketList = (tPacket *)GlobalAllocPtr(GPTR, MAX_PACKETS*sizeof(tPacket));
184         if (!PacketList) 
185                 return -4;                                                              // Memory will be freed in ipx_close
186
187         for (i = 0; i < MAX_PACKETS; i++) 
188         {
189                 PacketList[i].packetnum = -1;
190                 PacketList[i].free = i;
191         }
192
193         IPXPacketNum = 0;
194         PacketListCur = 0;
195         PacketListTail = 0;
196
197 //      Setup IPX packets for packet retrieval and sending
198         IPXPackets = (tIpxPacket *)GlobalAllocPtr(GPTR, sizeof(tIpxPacket)*NUM_IPX_PACKETS);
199         if (!IPXPackets) 
200                 return -4;                                                              // Memory will be freed in ipx_close
201
202         for (i = 1; i < NUM_IPX_PACKETS; i++)
203         {
204                 IPXPackets[i].in_use = 1;
205                 wipx_socket_listen(WinSocket, &IPXPackets[i]);
206         }
207
208         IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
209         memset( &IPXPackets[0].daddr.net_id, 0, sizeof(tIpxNetworkID));
210
211         ipx_installed = 1;
212
213         return 0;
214 }       
215
216
217 void ipx_close()
218 {
219         if (WinSocket) {
220                 wipx_close_socket(WinSocket);
221                 wipx_close();
222         }
223         if (IPXPackets) {
224                 GlobalFreePtr(IPXPackets);
225                 IPXPackets = NULL;
226         }
227         if (PacketList) {
228                 GlobalFreePtr(PacketList);
229                 PacketList = NULL;
230         }
231 }
232
233
234 //      ----------------------------------------------------------------------------
235 //      Listen/Retrieve Packet Functions
236 //      ----------------------------------------------------------------------------
237
238 int ipx_get_packet_data( ubyte * data )
239 {
240         int i, n, best, best_id, size;
241
242         for (i=1; i < NUM_IPX_PACKETS; i++ )    
243         {
244                 IPXPackets[i].in_use = 1;
245                 wipx_socket_listen(WinSocket, &IPXPackets[i]);
246                 if (!IPXPackets[i].in_use) 
247                         got_new_packet(&IPXPackets[i]);                         
248         }
249
250 //      Take oldest packet from list and get data.
251         best = -1;
252         n = 0;
253         best_id = -1;
254
255         for (i=0; i <= PacketListTail; i++ )    
256         {
257                 if ( PacketList[i].packetnum > -1 ) {
258                         n++;
259                         if ((best == -1) || (PacketList[i].packetnum < best) )  {
260                                 best = PacketList[i].packetnum;
261                                 best_id = i;
262                         }
263                 }                       
264         }
265
266         if ( best_id < 0 ) return 0;
267
268         size = PacketList[best_id].size;
269         memcpy( data, PacketList[best_id].data, size );
270
271         free_packet(best_id);                                                   
272
273         return size;
274 }
275
276
277 void got_new_packet( tIpxPacket *packet )
278 {
279         int id;
280         unsigned short datasize;
281
282         datasize = 0;
283
284         if (memcmp( &packet->saddr.node_addr, &ThisIPXNode, sizeof(tIpxAddrGeneric))) {
285         // Find slot to put packet in...
286                 datasize = packet->datalen;       
287
288                 if ( datasize > 0 && datasize <= sizeof(tPacket) )      {
289                         if ( PacketListCur >= MAX_PACKETS ) {
290                                 neterrors++;
291                                 return;
292                         }               
293                         id = PacketList[PacketListCur++].free;
294                         if (id > PacketListTail ) PacketListTail = id;
295                         PacketList[id].size = datasize - sizeof(int);
296                         PacketList[id].packetnum = packet->packetnum;
297                         if (PacketList[id].packetnum < 0) { neterrors++; return; } 
298                         memcpy( PacketList[id].data, packet->data, PacketList[id].size );
299                 } else {
300                         neterrors++; return;
301                 }
302         } 
303         // Repost the ecb
304         packet->in_use = 0;
305 }
306
307
308 void free_packet( int id )
309 {
310         PacketList[id].packetnum = -1;
311         PacketList[ --PacketListCur].free = id;
312         if (PacketListTail==id) 
313                 while ((--PacketListTail>0) && (PacketList[PacketListTail].packetnum == -1 ));
314 }
315
316
317
318 //      ----------------------------------------------------------------------------
319 //      Send IPX Packet Functions
320 //      ----------------------------------------------------------------------------
321
322 void ipx_send_packet_data( ubyte * data, 
323                                 int datasize, 
324                                 ubyte *network, 
325                                 ubyte *address, 
326                                 ubyte *immediate_address )
327 {
328         Assert(ipx_installed);
329
330         if ( datasize >= IPX_MAX_DATA_SIZE )    {
331                 Error("Illegal sized IPX packet being sent.");          
332         }
333
334 // Make sure no one is already sending something
335         IPXPackets[0].packetnum = IPXPacketNum;
336         IPXPacketNum++; 
337         memcpy( &IPXPackets[0].daddr.net_id, (tIpxNetworkID *)network, 4);
338         memcpy( &IPXPackets[0].daddr.node_addr, (tIpxAddrGeneric *)address, sizeof(tIpxAddrGeneric) );
339
340 // Fill in data to send
341         Assert(datasize > 1);
342         IPXPackets[0].datalen = sizeof(int) + datasize;
343         memcpy( IPXPackets[0].data, data, datasize );
344
345 // Send it
346         IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
347         wipx_socket_send( WinSocket, &IPXPackets[0]);
348 }
349
350
351 void ipx_send_broadcast_packet_data( ubyte * data, int datasize )       
352 {
353         int i, j;
354         ubyte broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
355         tIpxAddrGeneric local_address;
356
357         wipx_set_socket_mode_bool(WinSocket, SO_BROADCAST, TRUE);
358
359 // Set to all networks besides mine
360         for (i = 0; i < NumIPXSubnet; i++ )     
361         {
362                 if (memcmp(&IPXSubnetID[i], &ThisIPXSubnet, 4)) {
363                         ipx_get_local_target( (ubyte *)&IPXSubnetID[i], 
364                                                 broadcast, 
365                                                 (ubyte*)&local_address );
366                         ipx_send_packet_data( data, datasize, 
367                                                 (ubyte *)&IPXSubnetID[i], 
368                                                 broadcast, 
369                                                 (ubyte *)&local_address );
370                 } else {
371                         ipx_send_packet_data( data, datasize, 
372                                                 (ubyte *)&IPXSubnetID[i], 
373                                                 broadcast, 
374                                                 broadcast );
375                 }
376         }
377                                                          
378 // Send directly to all users not on my network or in the network list.
379         for (i = 0; i < NumIPXUsers; i++ )      
380         {
381                 if ( memcmp( &IPXUsers[i].net_id, &ThisIPXSubnet,4 ) )  {
382                         for (j=0; j < NumIPXSubnet; j++ )               {
383                                 if (!memcmp( &IPXUsers[i].net_id, &IPXSubnetID[j], 4 ))
384                                         goto SkipUser;
385                         }
386                         ipx_send_packet_data( data, datasize, 
387                                                 (ubyte*)&IPXUsers[i].net_id, 
388                                                 (ubyte*)&IPXUsers[i].node_addr, 
389                                                 (ubyte*)&IPXUsers[i].addr );
390 SkipUser:
391                         j = 0;
392                 }
393         }
394 }
395
396
397 //      Functions Sends a non-localized packet... needs 4 byte server, 
398 //      6 byte address
399
400 void ipx_send_internetwork_packet_data( ubyte * data, int datasize, 
401                                                 ubyte * server, 
402                                                 ubyte *address )
403 {
404         tIpxAddrGeneric local_address;
405
406         if ( (*(uint *)server) != 0 )   {
407                 ipx_get_local_target( server, address, (ubyte *)&local_address );
408                 ipx_send_packet_data( data, datasize, server, address, (ubyte *)&local_address );
409         } else {
410         // Old method, no server info.
411                 ipx_send_packet_data( data, datasize, server, address, address );
412         }
413 }
414
415
416
417 //      ---------------------------------------------------------------------------
418 // Read IPX User file stuff
419 //      ---------------------------------------------------------------------------
420
421 int ipx_change_default_socket( ushort socket_number )
422 {
423         int i;
424         int result;
425         SOCKET new_socket;
426         WORD new_ipx_socket;
427
428         if ( !ipx_installed ) return -3;
429
430 // Open a new socket    
431         result = wipx_open_socket(socket_number, &new_socket, &new_ipx_socket);
432         if (result) return -2;
433         
434
435 // Close existing socket...
436         wipx_close_socket(WinSocket);
437
438         IPXSocket = new_ipx_socket;
439         WinSocket = new_socket;
440
441 // Repost all listen requests on the new socket...      
442         for (i=1; i<NUM_IPX_PACKETS; i++ )      
443         {
444                 IPXPackets[i].in_use = 0;
445                 wipx_socket_listen(WinSocket, &IPXPackets[i]);
446         }
447
448         IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
449         IPXPacketNum = 0;
450
451 // init packet buffers.
452         for (i=0; i<MAX_PACKETS; i++ )  
453         {
454                 PacketList[i].packetnum = -1;
455                 PacketList[i].free = i;
456         }
457         PacketListCur = PacketListTail = 0;
458
459         return 0;
460 }
461
462
463 void ipx_read_user_file(char * filename)
464 {
465         FILE * fp;
466         tIpxUserAddr tmp;
467         char temp_line[132], *p1;
468         int n, ln=0;
469
470         if (!filename) return;
471
472         NumIPXUsers = 0;
473
474         fp = fopen( filename, "rt" );
475         if ( !fp ) return;
476
477         printf( "Broadcast Users:\n" );
478
479         while (fgets(temp_line, 132, fp)) {
480                 ln++;
481                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
482                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
483                 n = sscanf( temp_line, "%2x%2x%2x%2x/%2x%2x%2x%2x%2x%2x", &tmp.net_id.b[0], 
484                                         &tmp.net_id.b[1], &tmp.net_id.b[2], &tmp.net_id.b[3],
485                                         &tmp.node_addr.b[0], &tmp.node_addr.b[1], &tmp.node_addr.b[2],
486                                         &tmp.node_addr.b[3], &tmp.node_addr.b[4], &tmp.node_addr.b[5] );
487                 if ( n != 10 ) continue;
488                 if ( NumIPXUsers < MAX_USERS )  {
489                         ipx_get_local_target( tmp.net_id.b, tmp.node_addr.b, tmp.addr.b );
490                         IPXUsers[NumIPXUsers++] = tmp;
491
492 //                      printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
493 //                      printf( "%02X%02X%02X%02X%02X%02X\n", ipx_real_buffer[4],ipx_real_buffer[5],ipx_real_buffer[6],ipx_real_buffer[7],ipx_real_buffer[8],ipx_real_buffer[9] );
494                 } else {
495                         printf( "Too many addresses in %s! (Limit of %d)\n", filename, MAX_USERS );
496                         fclose(fp);
497                         return;
498                 }
499         }
500         fclose(fp);
501 }
502
503
504 void ipx_read_network_file(char * filename)
505 {
506         FILE * fp;
507         tIpxUserAddr tmp;
508         char temp_line[132], *p1;
509         int i, n, ln=0;
510
511         if (!filename) return;
512
513         fp = fopen( filename, "rt" );
514         if ( !fp ) return;
515
516         printf( "Using Networks:\n" );
517         for (i=0; i<NumIPXSubnet; i++ )         {
518                 ubyte * n1 = (ubyte *)IPXSubnetID[i].b;
519                 printf("* %02x%02x%02x%02x\n", n1[0], n1[1], n1[2], n1[3] );
520         }
521
522         while (fgets(temp_line, 132, fp)) {
523                 ln++;
524                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
525                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
526                 n = sscanf( temp_line, "%2x%2x%2x%2x", &tmp.net_id.b[0], &tmp.net_id.b[1], &tmp.net_id.b[2], &tmp.net_id.b[3] );
527                 if ( n != 4 ) continue;
528                 if ( NumIPXSubnet < MAX_SUBNETS  )      {
529                         int j;
530                         for (j=0; j<NumIPXSubnet; j++ ) 
531                                 if ( !memcmp( &IPXSubnetID[j], &tmp.net_id, 4 ) )
532                                         break;
533                         if ( j >= NumIPXSubnet )        {
534                                 memcpy( &IPXSubnetID[NumIPXSubnet++], &tmp.net_id, 4 );
535 //                              printf("  %02x%02x%02x%02x\n", &tmp.net_id.b[0], &tmp.net_id.b[1], tmp.network[2], tmp.network[3] );
536                         }
537                 } else {
538                         printf( "Too many networks in %s! (Limit of %d)\n", filename, MAX_SUBNETS );
539                         fclose(fp);
540                         return;
541                 }
542         }
543         fclose(fp);
544
545 }
546
547
548
549 //      ----------------------------------------------------------------------------
550 //      Winsock API layer
551 //      ----------------------------------------------------------------------------
552
553 uint wipx_init()
554 {
555         WSADATA version_info;
556         WORD version_requested;
557         int result;
558         
559         version_requested = MAKEWORD(2,0);
560         
561         result = WSAStartup(version_requested, &version_info);
562         if (result) {
563                 wipx_logerror(result, "wpx_init");      
564                 return result;
565         }
566                 
567         if (LOBYTE(version_requested) < 1 && HIBYTE(version_requested) < 1) {
568                 logentry("Bad version of Winsock DLL %d.%d.\n", LOBYTE(version_requested), HIBYTE(version_requested));
569                 return 0xffffffff;
570         }
571
572         return 0;
573 }
574
575
576 uint wipx_open_socket(int sock_num, SOCKET *sock_id, WORD *ipx_socket)
577 {
578         LINGER ling;
579         SOCKET s;
580         SOCKADDR_IPX ipx_addr;
581         unsigned long ioctlval;
582
583         s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
584         if (s == INVALID_SOCKET) {
585                 *sock_id = 0;
586                 *ipx_socket = 0;
587                 wipx_logerror(s, "wipx_open_socket::socket");
588                 return INVALID_SOCKET;
589         }
590
591 //      Set hard close for sockets
592         ling.l_onoff = 1;
593         ling.l_linger = 0;
594         setsockopt(s, SOL_SOCKET, SO_LINGER, (PSTR)&ling, sizeof(ling));
595         
596         memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
597         ipx_addr.sa_socket = htons(sock_num);
598         ipx_addr.sa_family = AF_IPX;
599         if (bind(s, (SOCKADDR *)&ipx_addr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR) {
600                 closesocket(s);
601                 *ipx_socket = 0;
602                 *sock_id = 0;
603                 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::bind");
604                 return SOCKET_ERROR;
605         }
606         
607         ioctlval = 1;                                                           // Set socket to non-blocking mode
608         if (ioctlsocket(s, FIONBIO, &ioctlval) == SOCKET_ERROR) {
609                 closesocket(s);
610                 *ipx_socket = 0;
611                 *sock_id = 0;
612                 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::ioctlsocket");
613                 return SOCKET_ERROR;
614         }
615         
616         *sock_id = s;
617         *ipx_socket = sock_num;
618
619         return 0;
620 }
621
622
623 uint wipx_close_socket(SOCKET sock_id)
624 {
625         if (closesocket(sock_id) == SOCKET_ERROR) {
626                 wipx_logerror(SOCKET_ERROR, "wipx_close_socket");
627                 return SOCKET_ERROR;
628         }
629         else return 0;
630 }
631
632
633 uint wipx_get_socket_addr(SOCKET sock_id, tIpxNetworkID *net_addr, 
634                                 tIpxAddrGeneric *node_addr)
635 {
636         SOCKADDR_IPX    ipx_addr;
637         int                             len;
638
639 //      Use getsockname to get info
640         len = sizeof(SOCKADDR_IPX);
641         if (getsockname(sock_id, (SOCKADDR *)&ipx_addr, &len) == SOCKET_ERROR) {
642                 wipx_logerror(SOCKET_ERROR, "getsockname");
643                 return SOCKET_ERROR;
644         }
645         else {
646                 memcpy(net_addr, ipx_addr.sa_netnum, 4);
647                 memcpy(node_addr, ipx_addr.sa_nodenum, 6);
648                 return 0;
649         }
650 }
651
652
653 uint wipx_set_socket_mode_bool(SOCKET sock_id, int opt, BOOL toggle)
654 {
655         if (setsockopt(sock_id, SOL_SOCKET, opt, (LPSTR)&toggle,
656                                  sizeof(toggle)) == SOCKET_ERROR) {
657                 wipx_logerror(SOCKET_ERROR, "wipx_set_socket_mode_bool");
658                 return SOCKET_ERROR;
659         }
660         return 0;
661 }
662
663
664 uint wipx_socket_listen(SOCKET sock_id, tIpxPacket *packet)
665 {
666         unsigned long ioctlval = 0;
667         int bytes, length = sizeof(SOCKADDR_IPX);
668         SOCKADDR_IPX ipx_addr;
669         
670         if (ioctlsocket(sock_id, FIONREAD, &ioctlval) == SOCKET_ERROR)  {
671                 wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::ioctlsocket");
672                 return SOCKET_ERROR;
673         }
674         else if (ioctlval) {
675                 ipx_addr.sa_socket = htons(IPXSocket);
676                 ipx_addr.sa_family = AF_IPX;
677                 bytes = recvfrom(sock_id, (char *)(&packet->packetnum),
678                                         sizeof(int) + IPX_MAX_DATA_SIZE,
679                                         0,
680                                         &ipx_addr,
681                                         &length);
682                 if (bytes == SOCKET_ERROR) {
683                         wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::recvfrom");
684                         return SOCKET_ERROR;
685                 }
686                 packet->in_use = 0;
687                 packet->datalen = bytes;
688                 return 0;
689         }
690         else return 0;
691 }
692
693
694 uint wipx_socket_send(SOCKET sock_id, tIpxPacket *packet)
695 {
696         SOCKADDR_IPX ipx_addr;
697         int bytes = 0;
698
699         ipx_addr.sa_socket = htons(IPXSocket);
700         ipx_addr.sa_family = AF_IPX;
701         memcpy(ipx_addr.sa_nodenum, &packet->daddr.node_addr, 6);
702         memcpy(ipx_addr.sa_netnum, &packet->daddr.net_id, 4);
703         
704 /*      logentry("Sending packet to %2X%2X%2X%2X:%2X%2X%2X%2X%2X%2X\n",
705                                 packet->daddr.net_id.b[0],
706                                 packet->daddr.net_id.b[1],
707                                 packet->daddr.net_id.b[2],
708                                 packet->daddr.net_id.b[3],
709                                 packet->daddr.node_addr.b[0],
710                                 packet->daddr.node_addr.b[1],
711                                 packet->daddr.node_addr.b[2],
712                                 packet->daddr.node_addr.b[3],
713                                 packet->daddr.node_addr.b[4],
714                                 packet->daddr.node_addr.b[5]);
715 */
716
717         bytes = sendto(sock_id, (char *)(&packet->packetnum),
718                                 packet->datalen,
719                                 0,
720                                 &ipx_addr,
721                                 sizeof(SOCKADDR_IPX));          
722         packet->in_use = 1;
723         if (bytes == SOCKET_ERROR) {
724                 wipx_logerror(SOCKET_ERROR, "wipx_socket_send::sendto");
725                 return SOCKET_ERROR;
726         }
727         else return 0;
728 }
729
730
731 uint wipx_close()
732 {
733         return WSACleanup();
734 }
735
736  
737 uint wipx_logerror(uint ipx_result, char *text)
738 {
739         logentry("%s:: error %x.\n", text, ipx_result);
740         return ipx_result;
741 }       
742