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 #define WIN32_LEAN_AND_MEAN
37 // ---------------------------------------------------------------------------
39 #define NUM_IPX_PACKETS 32
42 #define MAX_SUBNETS 64
43 #define MAX_PACKETS 64
46 typedef struct tIpxNetworkID {
50 typedef struct tIpxAddrGeneric {
54 typedef struct tIpxNetAddr {
56 tIpxAddrGeneric node_addr;
60 typedef struct tIpxUserAddr {
62 tIpxAddrGeneric node_addr;
66 typedef struct tIpxPacket {
72 ubyte data[IPX_MAX_DATA_SIZE];
76 typedef struct tPacket {
80 ubyte data[IPX_MAX_DATA_SIZE];
85 // ---------------------------------------------------------------------------
87 // ---------------------------------------------------------------------------
89 static ubyte ipx_installed = 0;
90 static int neterrors = 0;
92 static int NumIPXUsers = 0;
93 static tIpxUserAddr IPXUsers[MAX_USERS];
95 static int NumIPXSubnet = 0;
96 static tIpxNetworkID IPXSubnetID[MAX_SUBNETS];
98 static tIpxPacket *IPXPackets = NULL;
99 static int IPXPacketNum = 0;
101 static SOCKET WinSocket = 0;
102 static WORD IPXSocket = 0;
103 static tIpxNetworkID ThisIPXSubnet;
104 static tIpxAddrGeneric ThisIPXNode;
106 static int PacketListTail, PacketListCur;
107 static tPacket *PacketList;
111 // ---------------------------------------------------------------------------
112 // Function Prototypes
113 // ---------------------------------------------------------------------------
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);
123 uint wipx_logerror(uint ipx_result, char *text);
125 void got_new_packet( tIpxPacket *packet );
126 void free_packet( int id );
129 ubyte *ipx_get_my_local_address() {
130 return (ubyte *)&ThisIPXNode;
133 ubyte *ipx_get_my_server_address() {
134 return (ubyte *)&ThisIPXSubnet;
137 void ipx_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
139 memset(local_target, 0, 6);
144 // ---------------------------------------------------------------------------
146 // ---------------------------------------------------------------------------
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
158 int ipx_init(int socket_number, int show_address)
165 // Establish Winsock IPX Link.
166 ipx_result = wipx_init();
167 if (ipx_result) return -3;
169 ipx_result = wipx_open_socket(socket_number, &WinSocket, &IPXSocket);
171 if (ipx_result == WSAEPROTONOSUPPORT) return -3;
172 if (ipx_result == WSAENOBUFS) return -2;
176 // Get this station's IPX address.
177 ipx_result = wipx_get_socket_addr(WinSocket, &ThisIPXSubnet, &ThisIPXNode);
178 if (ipx_result) return -5;
180 memcpy(&IPXSubnetID[NumIPXSubnet++], &ThisIPXSubnet, sizeof(tIpxNetworkID));
182 // Initialize packet buffers
183 PacketList = (tPacket *)GlobalAllocPtr(GPTR, MAX_PACKETS*sizeof(tPacket));
185 return -4; // Memory will be freed in ipx_close
187 for (i = 0; i < MAX_PACKETS; i++)
189 PacketList[i].packetnum = -1;
190 PacketList[i].free = i;
197 // Setup IPX packets for packet retrieval and sending
198 IPXPackets = (tIpxPacket *)GlobalAllocPtr(GPTR, sizeof(tIpxPacket)*NUM_IPX_PACKETS);
200 return -4; // Memory will be freed in ipx_close
202 for (i = 1; i < NUM_IPX_PACKETS; i++)
204 IPXPackets[i].in_use = 1;
205 wipx_socket_listen(WinSocket, &IPXPackets[i]);
208 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
209 memset( &IPXPackets[0].daddr.net_id, 0, sizeof(tIpxNetworkID));
220 wipx_close_socket(WinSocket);
224 GlobalFreePtr(IPXPackets);
228 GlobalFreePtr(PacketList);
234 // ----------------------------------------------------------------------------
235 // Listen/Retrieve Packet Functions
236 // ----------------------------------------------------------------------------
238 int ipx_get_packet_data( ubyte * data )
240 int i, n, best, best_id, size;
242 for (i=1; i < NUM_IPX_PACKETS; i++ )
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]);
250 // Take oldest packet from list and get data.
255 for (i=0; i <= PacketListTail; i++ )
257 if ( PacketList[i].packetnum > -1 ) {
259 if ((best == -1) || (PacketList[i].packetnum < best) ) {
260 best = PacketList[i].packetnum;
266 if ( best_id < 0 ) return 0;
268 size = PacketList[best_id].size;
269 memcpy( data, PacketList[best_id].data, size );
271 free_packet(best_id);
277 void got_new_packet( tIpxPacket *packet )
280 unsigned short datasize;
284 if (memcmp( &packet->saddr.node_addr, &ThisIPXNode, sizeof(tIpxAddrGeneric))) {
285 // Find slot to put packet in...
286 datasize = packet->datalen;
288 if ( datasize > 0 && datasize <= sizeof(tPacket) ) {
289 if ( PacketListCur >= MAX_PACKETS ) {
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 );
308 void free_packet( int id )
310 PacketList[id].packetnum = -1;
311 PacketList[ --PacketListCur].free = id;
312 if (PacketListTail==id)
313 while ((--PacketListTail>0) && (PacketList[PacketListTail].packetnum == -1 ));
318 // ----------------------------------------------------------------------------
319 // Send IPX Packet Functions
320 // ----------------------------------------------------------------------------
322 void ipx_send_packet_data( ubyte * data,
326 ubyte *immediate_address )
328 Assert(ipx_installed);
330 if ( datasize >= IPX_MAX_DATA_SIZE ) {
331 Error("Illegal sized IPX packet being sent.");
334 // Make sure no one is already sending something
335 IPXPackets[0].packetnum = IPXPacketNum;
337 memcpy( &IPXPackets[0].daddr.net_id, (tIpxNetworkID *)network, 4);
338 memcpy( &IPXPackets[0].daddr.node_addr, (tIpxAddrGeneric *)address, sizeof(tIpxAddrGeneric) );
340 // Fill in data to send
341 Assert(datasize > 1);
342 IPXPackets[0].datalen = sizeof(int) + datasize;
343 memcpy( IPXPackets[0].data, data, datasize );
346 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
347 wipx_socket_send( WinSocket, &IPXPackets[0]);
351 void ipx_send_broadcast_packet_data( ubyte * data, int datasize )
354 ubyte broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
355 tIpxAddrGeneric local_address;
357 wipx_set_socket_mode_bool(WinSocket, SO_BROADCAST, TRUE);
359 // Set to all networks besides mine
360 for (i = 0; i < NumIPXSubnet; i++ )
362 if (memcmp(&IPXSubnetID[i], &ThisIPXSubnet, 4)) {
363 ipx_get_local_target( (ubyte *)&IPXSubnetID[i],
365 (ubyte*)&local_address );
366 ipx_send_packet_data( data, datasize,
367 (ubyte *)&IPXSubnetID[i],
369 (ubyte *)&local_address );
371 ipx_send_packet_data( data, datasize,
372 (ubyte *)&IPXSubnetID[i],
378 // Send directly to all users not on my network or in the network list.
379 for (i = 0; i < NumIPXUsers; i++ )
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 ))
386 ipx_send_packet_data( data, datasize,
387 (ubyte*)&IPXUsers[i].net_id,
388 (ubyte*)&IPXUsers[i].node_addr,
389 (ubyte*)&IPXUsers[i].addr );
397 // Functions Sends a non-localized packet... needs 4 byte server,
400 void ipx_send_internetwork_packet_data( ubyte * data, int datasize,
404 tIpxAddrGeneric local_address;
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 );
410 // Old method, no server info.
411 ipx_send_packet_data( data, datasize, server, address, address );
417 // ---------------------------------------------------------------------------
418 // Read IPX User file stuff
419 // ---------------------------------------------------------------------------
421 int ipx_change_default_socket( ushort socket_number )
428 if ( !ipx_installed ) return -3;
431 result = wipx_open_socket(socket_number, &new_socket, &new_ipx_socket);
432 if (result) return -2;
435 // Close existing socket...
436 wipx_close_socket(WinSocket);
438 IPXSocket = new_ipx_socket;
439 WinSocket = new_socket;
441 // Repost all listen requests on the new socket...
442 for (i=1; i<NUM_IPX_PACKETS; i++ )
444 IPXPackets[i].in_use = 0;
445 wipx_socket_listen(WinSocket, &IPXPackets[i]);
448 IPXPackets[0].daddr.ipx_socket = htons(IPXSocket);
451 // init packet buffers.
452 for (i=0; i<MAX_PACKETS; i++ )
454 PacketList[i].packetnum = -1;
455 PacketList[i].free = i;
457 PacketListCur = PacketListTail = 0;
463 void ipx_read_user_file(char * filename)
467 char temp_line[132], *p1;
470 if (!filename) return;
474 fp = fopen( filename, "rt" );
477 printf( "Broadcast Users:\n" );
479 while (fgets(temp_line, 132, fp)) {
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;
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] );
495 printf( "Too many addresses in %s! (Limit of %d)\n", filename, MAX_USERS );
504 void ipx_read_network_file(char * filename)
508 char temp_line[132], *p1;
511 if (!filename) return;
513 fp = fopen( filename, "rt" );
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] );
522 while (fgets(temp_line, 132, fp)) {
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 ) {
530 for (j=0; j<NumIPXSubnet; j++ )
531 if ( !memcmp( &IPXSubnetID[j], &tmp.net_id, 4 ) )
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] );
538 printf( "Too many networks in %s! (Limit of %d)\n", filename, MAX_SUBNETS );
549 // ----------------------------------------------------------------------------
551 // ----------------------------------------------------------------------------
555 WSADATA version_info;
556 WORD version_requested;
559 version_requested = MAKEWORD(2,0);
561 result = WSAStartup(version_requested, &version_info);
563 wipx_logerror(result, "wpx_init");
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));
576 uint wipx_open_socket(int sock_num, SOCKET *sock_id, WORD *ipx_socket)
580 SOCKADDR_IPX ipx_addr;
581 unsigned long ioctlval;
583 s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
584 if (s == INVALID_SOCKET) {
587 wipx_logerror(s, "wipx_open_socket::socket");
588 return INVALID_SOCKET;
591 // Set hard close for sockets
594 setsockopt(s, SOL_SOCKET, SO_LINGER, (PSTR)&ling, sizeof(ling));
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) {
603 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::bind");
607 ioctlval = 1; // Set socket to non-blocking mode
608 if (ioctlsocket(s, FIONBIO, &ioctlval) == SOCKET_ERROR) {
612 wipx_logerror(SOCKET_ERROR, "wipx_open_socket::ioctlsocket");
617 *ipx_socket = sock_num;
623 uint wipx_close_socket(SOCKET sock_id)
625 if (closesocket(sock_id) == SOCKET_ERROR) {
626 wipx_logerror(SOCKET_ERROR, "wipx_close_socket");
633 uint wipx_get_socket_addr(SOCKET sock_id, tIpxNetworkID *net_addr,
634 tIpxAddrGeneric *node_addr)
636 SOCKADDR_IPX ipx_addr;
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");
646 memcpy(net_addr, ipx_addr.sa_netnum, 4);
647 memcpy(node_addr, ipx_addr.sa_nodenum, 6);
653 uint wipx_set_socket_mode_bool(SOCKET sock_id, int opt, BOOL toggle)
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");
664 uint wipx_socket_listen(SOCKET sock_id, tIpxPacket *packet)
666 unsigned long ioctlval = 0;
667 int bytes, length = sizeof(SOCKADDR_IPX);
668 SOCKADDR_IPX ipx_addr;
670 if (ioctlsocket(sock_id, FIONREAD, &ioctlval) == SOCKET_ERROR) {
671 wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::ioctlsocket");
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,
682 if (bytes == SOCKET_ERROR) {
683 wipx_logerror(SOCKET_ERROR, "wipx_socket_listen::recvfrom");
687 packet->datalen = bytes;
694 uint wipx_socket_send(SOCKET sock_id, tIpxPacket *packet)
696 SOCKADDR_IPX ipx_addr;
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);
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]);
717 bytes = sendto(sock_id, (char *)(&packet->packetnum),
721 sizeof(SOCKADDR_IPX));
723 if (bytes == SOCKET_ERROR) {
724 wipx_logerror(SOCKET_ERROR, "wipx_socket_send::sendto");
737 uint wipx_logerror(uint ipx_result, char *text)
739 logentry("%s:: error %x.\n", text, ipx_result);