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.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: ipx.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
19 #define WIN32_LEAN_AND_MEAN
41 // ---------------------------------------------------------------------------
43 #define NUM_IPX_PACKETS 32
46 #define MAX_SUBNETS 64
47 #define MAX_PACKETS 64
50 typedef struct tIpxNetworkID {
54 typedef struct tIpxAddrGeneric {
58 typedef struct tIpxNetAddr {
60 tIpxAddrGeneric node_addr;
64 typedef struct tIpxUserAddr {
66 tIpxAddrGeneric node_addr;
70 typedef struct tIpxPacket {
76 ubyte data[IPX_MAX_DATA_SIZE];
80 typedef struct tPacket {
84 ubyte data[IPX_MAX_DATA_SIZE];
89 // ---------------------------------------------------------------------------
91 // ---------------------------------------------------------------------------
93 static ubyte ipx_installed = 0;
94 static int neterrors = 0;
96 static int NumIPXUsers = 0;
97 static tIpxUserAddr IPXUsers[MAX_USERS];
99 static int NumIPXSubnet = 0;
100 static tIpxNetworkID IPXSubnetID[MAX_SUBNETS];
102 static tIpxPacket *IPXPackets = NULL;
103 static int IPXPacketNum = 0;
105 static SOCKET WinSocket = 0;
106 static WORD IPXSocket = 0;
107 static tIpxNetworkID ThisIPXSubnet;
108 static tIpxAddrGeneric ThisIPXNode;
110 static int PacketListTail, PacketListCur;
111 static tPacket *PacketList;
115 // ---------------------------------------------------------------------------
116 // Function Prototypes
117 // ---------------------------------------------------------------------------
120 uint wipx_open_socket(int sock_num, SOCKET *sock_id, WORD *ipx_socket);
121 uint wipx_close_socket(SOCKET sock_id);
122 uint wipx_get_socket_addr(SOCKET sock_id, tIpxNetworkID *net_addr, tIpxAddrGeneric *node_addr);
123 uint wipx_set_socket_mode_bool(SOCKET sock_id, int opt, BOOL toggle);
124 uint wipx_socket_listen(SOCKET sock_id, tIpxPacket *packet);
125 uint wipx_socket_send(SOCKET sock_id, tIpxPacket *packet);
127 uint wipx_logerror(uint ipx_result, char *text);
129 void got_new_packet( tIpxPacket *packet );
130 void free_packet( int id );
133 ubyte *ipx_get_my_local_address() {
134 return (ubyte *)&ThisIPXNode;
137 ubyte *ipx_get_my_server_address() {
138 return (ubyte *)&ThisIPXSubnet;
141 void ipx_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
143 memset(local_target, 0, 6);
148 // ---------------------------------------------------------------------------
150 // ---------------------------------------------------------------------------
152 //---------------------------------------------------------------
153 // Initializes all IPX internals.
154 // If socket_number==0, then opens next available socket.
155 // Returns: 0 if successful.
156 // -1 if socket already open.
157 // -2 if socket table full.
158 // -3 if IPX not installed.
159 // -4 if couldn't allocate memory
160 // -5 if error with getting internetwork address
162 int ipx_init(int socket_number, int show_address)
169 // Establish Winsock IPX Link.
170 ipx_result = wipx_init();
171 if (ipx_result) return -3;
173 ipx_result = wipx_open_socket(socket_number, &WinSocket, &IPXSocket);
175 if (ipx_result == WSAEPROTONOSUPPORT) return -3;
176 if (ipx_result == WSAENOBUFS) return -2;
180 // Get this station's IPX address.
181 ipx_result = wipx_get_socket_addr(WinSocket, &ThisIPXSubnet, &ThisIPXNode);
182 if (ipx_result) return -5;
184 memcpy(&IPXSubnetID[NumIPXSubnet++], &ThisIPXSubnet, sizeof(tIpxNetworkID));
186 // Initialize packet buffers
187 PacketList = (tPacket *)GlobalAllocPtr(GPTR, MAX_PACKETS*sizeof(tPacket));
189 return -4; // Memory will be freed in ipx_close
191 for (i = 0; i < MAX_PACKETS; i++)
193 PacketList[i].packetnum = -1;
194 PacketList[i].free = i;
201 // Setup IPX packets for packet retrieval and sending
202 IPXPackets = (tIpxPacket *)GlobalAllocPtr(GPTR, sizeof(tIpxPacket)*NUM_IPX_PACKETS);
204 return -4; // Memory will be freed in ipx_close
206 for (i = 1; i < NUM_IPX_PACKETS; i++)
208 IPXPackets[i].in_use = 1;
209 wipx_socket_listen(WinSocket, &IPXPackets[i]);
212 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
213 memset( &IPXPackets[0].daddr.net_id, 0, sizeof(tIpxNetworkID));
224 wipx_close_socket(WinSocket);
228 GlobalFreePtr(IPXPackets);
232 GlobalFreePtr(PacketList);
238 // ----------------------------------------------------------------------------
239 // Listen/Retrieve Packet Functions
240 // ----------------------------------------------------------------------------
242 int ipx_get_packet_data( ubyte * data )
244 int i, n, best, best_id, size;
246 for (i=1; i < NUM_IPX_PACKETS; i++ )
248 IPXPackets[i].in_use = 1;
249 wipx_socket_listen(WinSocket, &IPXPackets[i]);
250 if (!IPXPackets[i].in_use)
251 got_new_packet(&IPXPackets[i]);
254 // Take oldest packet from list and get data.
259 for (i=0; i <= PacketListTail; i++ )
261 if ( PacketList[i].packetnum > -1 ) {
263 if ((best == -1) || (PacketList[i].packetnum < best) ) {
264 best = PacketList[i].packetnum;
270 if ( best_id < 0 ) return 0;
272 size = PacketList[best_id].size;
273 memcpy( data, PacketList[best_id].data, size );
275 free_packet(best_id);
281 void got_new_packet( tIpxPacket *packet )
284 unsigned short datasize;
288 if (memcmp( &packet->saddr.node_addr, &ThisIPXNode, sizeof(tIpxAddrGeneric))) {
289 // Find slot to put packet in...
290 datasize = packet->datalen;
292 if ( datasize > 0 && datasize <= sizeof(tPacket) ) {
293 if ( PacketListCur >= MAX_PACKETS ) {
297 id = PacketList[PacketListCur++].free;
298 if (id > PacketListTail ) PacketListTail = id;
299 PacketList[id].size = datasize - sizeof(int);
300 PacketList[id].packetnum = packet->packetnum;
301 if (PacketList[id].packetnum < 0) { neterrors++; return; }
302 memcpy( PacketList[id].data, packet->data, PacketList[id].size );
312 void free_packet( int id )
314 PacketList[id].packetnum = -1;
315 PacketList[ --PacketListCur].free = id;
316 if (PacketListTail==id)
317 while ((--PacketListTail>0) && (PacketList[PacketListTail].packetnum == -1 ));
322 // ----------------------------------------------------------------------------
323 // Send IPX Packet Functions
324 // ----------------------------------------------------------------------------
326 void ipx_send_packet_data( ubyte * data,
330 ubyte *immediate_address )
332 Assert(ipx_installed);
334 if ( datasize >= IPX_MAX_DATA_SIZE ) {
335 Error("Illegal sized IPX packet being sent.");
338 // Make sure no one is already sending something
339 IPXPackets[0].packetnum = IPXPacketNum;
341 memcpy( &IPXPackets[0].daddr.net_id, (tIpxNetworkID *)network, 4);
342 memcpy( &IPXPackets[0].daddr.node_addr, (tIpxAddrGeneric *)address, sizeof(tIpxAddrGeneric) );
344 // Fill in data to send
345 Assert(datasize > 1);
346 IPXPackets[0].datalen = sizeof(int) + datasize;
347 memcpy( IPXPackets[0].data, data, datasize );
350 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
351 wipx_socket_send( WinSocket, &IPXPackets[0]);
355 void ipx_send_broadcast_packet_data( ubyte * data, int datasize )
358 ubyte broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
359 tIpxAddrGeneric local_address;
361 wipx_set_socket_mode_bool(WinSocket, SO_BROADCAST, TRUE);
363 // Set to all networks besides mine
364 for (i = 0; i < NumIPXSubnet; i++ )
366 if (memcmp(&IPXSubnetID[i], &ThisIPXSubnet, 4)) {
367 ipx_get_local_target( (ubyte *)&IPXSubnetID[i],
369 (ubyte*)&local_address );
370 ipx_send_packet_data( data, datasize,
371 (ubyte *)&IPXSubnetID[i],
373 (ubyte *)&local_address );
375 ipx_send_packet_data( data, datasize,
376 (ubyte *)&IPXSubnetID[i],
382 // Send directly to all users not on my network or in the network list.
383 for (i = 0; i < NumIPXUsers; i++ )
385 if ( memcmp( &IPXUsers[i].net_id, &ThisIPXSubnet,4 ) ) {
386 for (j=0; j < NumIPXSubnet; j++ ) {
387 if (!memcmp( &IPXUsers[i].net_id, &IPXSubnetID[j], 4 ))
390 ipx_send_packet_data( data, datasize,
391 (ubyte*)&IPXUsers[i].net_id,
392 (ubyte*)&IPXUsers[i].node_addr,
393 (ubyte*)&IPXUsers[i].addr );
401 // Functions Sends a non-localized packet... needs 4 byte server,
404 void ipx_send_internetwork_packet_data( ubyte * data, int datasize,
408 tIpxAddrGeneric local_address;
410 if ( (*(uint *)server) != 0 ) {
411 ipx_get_local_target( server, address, (ubyte *)&local_address );
412 ipx_send_packet_data( data, datasize, server, address, (ubyte *)&local_address );
414 // Old method, no server info.
415 ipx_send_packet_data( data, datasize, server, address, address );
421 // ---------------------------------------------------------------------------
422 // Read IPX User file stuff
423 // ---------------------------------------------------------------------------
425 int ipx_change_default_socket( ushort socket_number )
432 if ( !ipx_installed ) return -3;
435 result = wipx_open_socket(socket_number, &new_socket, &new_ipx_socket);
436 if (result) return -2;
439 // Close existing socket...
440 wipx_close_socket(WinSocket);
442 IPXSocket = new_ipx_socket;
443 WinSocket = new_socket;
445 // Repost all listen requests on the new socket...
446 for (i=1; i<NUM_IPX_PACKETS; i++ )
448 IPXPackets[i].in_use = 0;
449 wipx_socket_listen(WinSocket, &IPXPackets[i]);
452 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
455 // init packet buffers.
456 for (i=0; i<MAX_PACKETS; i++ )
458 PacketList[i].packetnum = -1;
459 PacketList[i].free = i;
461 PacketListCur = PacketListTail = 0;
467 void ipx_read_user_file(char * filename)
471 char temp_line[132], *p1;
474 if (!filename) return;
478 fp = fopen( filename, "rt" );
481 printf( "Broadcast Users:\n" );
483 while (fgets(temp_line, 132, fp)) {
485 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
486 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
487 n = sscanf( temp_line, "%2x%2x%2x%2x/%2x%2x%2x%2x%2x%2x", &tmp.net_id.b[0],
488 &tmp.net_id.b[1], &tmp.net_id.b[2], &tmp.net_id.b[3],
489 &tmp.node_addr.b[0], &tmp.node_addr.b[1], &tmp.node_addr.b[2],
490 &tmp.node_addr.b[3], &tmp.node_addr.b[4], &tmp.node_addr.b[5] );
491 if ( n != 10 ) continue;
492 if ( NumIPXUsers < MAX_USERS ) {
493 ipx_get_local_target( tmp.net_id.b, tmp.node_addr.b, tmp.addr.b );
494 IPXUsers[NumIPXUsers++] = tmp;
496 // printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
497 // 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] );
499 printf( "Too many addresses in %s! (Limit of %d)\n", filename, MAX_USERS );
508 void ipx_read_network_file(char * filename)
512 char temp_line[132], *p1;
515 if (!filename) return;
517 fp = fopen( filename, "rt" );
520 printf( "Using Networks:\n" );
521 for (i=0; i<NumIPXSubnet; i++ ) {
522 ubyte * n1 = (ubyte *)IPXSubnetID[i].b;
523 printf("* %02x%02x%02x%02x\n", n1[0], n1[1], n1[2], n1[3] );
526 while (fgets(temp_line, 132, fp)) {
528 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
529 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
530 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] );
531 if ( n != 4 ) continue;
532 if ( NumIPXSubnet < MAX_SUBNETS ) {
534 for (j=0; j<NumIPXSubnet; j++ )
535 if ( !memcmp( &IPXSubnetID[j], &tmp.net_id, 4 ) )
537 if ( j >= NumIPXSubnet ) {
538 memcpy( &IPXSubnetID[NumIPXSubnet++], &tmp.net_id, 4 );
539 // printf(" %02x%02x%02x%02x\n", &tmp.net_id.b[0], &tmp.net_id.b[1], tmp.network[2], tmp.network[3] );
542 printf( "Too many networks in %s! (Limit of %d)\n", filename, MAX_SUBNETS );
553 // ----------------------------------------------------------------------------
555 // ----------------------------------------------------------------------------
559 WSADATA version_info;
560 WORD version_requested;
563 version_requested = MAKEWORD(2,0);
565 result = WSAStartup(version_requested, &version_info);
567 wipx_logerror(result, "wpx_init");
571 if (LOBYTE(version_requested) < 1 && HIBYTE(version_requested) < 1) {
572 logentry("Bad version of Winsock DLL %d.%d.\n", LOBYTE(version_requested), HIBYTE(version_requested));
580 uint wipx_open_socket(int sock_num, SOCKET *sock_id, WORD *ipx_socket)
584 SOCKADDR_IPX ipx_addr;
585 unsigned long ioctlval;
587 s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
588 if (s == INVALID_SOCKET) {
591 wipx_logerror(s, "wipx_open_socket::socket");
592 return INVALID_SOCKET;
595 // Set hard close for sockets
598 setsockopt(s, SOL_SOCKET, SO_LINGER, (PSTR)&ling, sizeof(ling));
600 memset(&ipx_addr, 0, sizeof(SOCKADDR_IPX));
601 ipx_addr.sa_socket = htons(sock_num);
602 ipx_addr.sa_family = AF_IPX;
603 if (bind(s, (SOCKADDR *)&ipx_addr, sizeof(SOCKADDR_IPX)) == SOCKET_ERROR) {
607 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::bind");
611 ioctlval = 1; // Set socket to non-blocking mode
612 if (ioctlsocket(s, FIONBIO, &ioctlval) == SOCKET_ERROR) {
616 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::ioctlsocket");
621 *ipx_socket = sock_num;
627 uint wipx_close_socket(SOCKET sock_id)
629 if (closesocket(sock_id) == SOCKET_ERROR) {
630 wipx_logerror(SOCKET_ERROR, "wipx_close_socket");
637 uint wipx_get_socket_addr(SOCKET sock_id, tIpxNetworkID *net_addr,
638 tIpxAddrGeneric *node_addr)
640 SOCKADDR_IPX ipx_addr;
643 // Use getsockname to get info
644 len = sizeof(SOCKADDR_IPX);
645 if (getsockname(sock_id, (SOCKADDR *)&ipx_addr, &len) == SOCKET_ERROR) {
646 wipx_logerror(SOCKET_ERROR, "getsockname");
650 memcpy(net_addr, ipx_addr.sa_netnum, 4);
651 memcpy(node_addr, ipx_addr.sa_nodenum, 6);
657 uint wipx_set_socket_mode_bool(SOCKET sock_id, int opt, BOOL toggle)
659 if (setsockopt(sock_id, SOL_SOCKET, opt, (LPSTR)&toggle,
660 sizeof(toggle)) == SOCKET_ERROR) {
661 wipx_logerror(SOCKET_ERROR, "wipx_set_socket_mode_bool");
668 uint wipx_socket_listen(SOCKET sock_id, tIpxPacket *packet)
670 unsigned long ioctlval = 0;
671 int bytes, length = sizeof(SOCKADDR_IPX);
672 SOCKADDR_IPX ipx_addr;
674 if (ioctlsocket(sock_id, FIONREAD, &ioctlval) == SOCKET_ERROR) {
675 wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::ioctlsocket");
679 ipx_addr.sa_socket = htons(IPXSocket);
680 ipx_addr.sa_family = AF_IPX;
681 bytes = recvfrom(sock_id, (char *)(&packet->packetnum),
682 sizeof(int) + IPX_MAX_DATA_SIZE,
686 if (bytes == SOCKET_ERROR) {
687 wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::recvfrom");
691 packet->datalen = bytes;
698 uint wipx_socket_send(SOCKET sock_id, tIpxPacket *packet)
700 SOCKADDR_IPX ipx_addr;
703 ipx_addr.sa_socket = htons(IPXSocket);
704 ipx_addr.sa_family = AF_IPX;
705 memcpy(ipx_addr.sa_nodenum, &packet->daddr.node_addr, 6);
706 memcpy(ipx_addr.sa_netnum, &packet->daddr.net_id, 4);
708 /* logentry("Sending packet to %2X%2X%2X%2X:%2X%2X%2X%2X%2X%2X\n",
709 packet->daddr.net_id.b[0],
710 packet->daddr.net_id.b[1],
711 packet->daddr.net_id.b[2],
712 packet->daddr.net_id.b[3],
713 packet->daddr.node_addr.b[0],
714 packet->daddr.node_addr.b[1],
715 packet->daddr.node_addr.b[2],
716 packet->daddr.node_addr.b[3],
717 packet->daddr.node_addr.b[4],
718 packet->daddr.node_addr.b[5]);
721 bytes = sendto(sock_id, (char *)(&packet->packetnum),
725 sizeof(SOCKADDR_IPX));
727 if (bytes == SOCKET_ERROR) {
728 wipx_logerror(SOCKET_ERROR, "wipx_socket_send::sendto");
741 uint wipx_logerror(uint ipx_result, char *text)
743 logentry("%s:: error %x.\n", text, ipx_result);