]> icculus.org git repositories - btb/d2x.git/blob - arch/linux/linuxnet.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / arch / linux / linuxnet.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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Linux lower-level network code.
17  * implements functions declared in include/ipx.h
18  *
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <conf.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <sys/types.h>
33 #if 0//def HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #endif
36
37 #ifdef _WIN32
38 #include <winsock.h>
39 #else
40 #include <netinet/in.h> /* for htons & co. */
41 #endif
42
43 #include "pstypes.h"
44 #include "args.h"
45 #include "dxxerror.h"
46
47 #include "ipx.h"
48 #include "ipx_drv.h"
49 #ifdef NATIVE_IPX
50 # include "ipx_bsd.h"
51 #endif //NATIVE_IPX
52 #ifdef KALINIX
53 #include "ipx_kali.h"
54 #endif
55 #include "ipx_udp.h"
56 #include "ipx_mcast4.h"
57 #include "dxxerror.h"
58 #include "inferno.h"
59 //added 05/17/99 Matt Mueller - needed to redefine FD_* so that no asm is used
60 //#include "checker.h"
61 //end addition -MM
62 #include "byteswap.h"
63
64
65 #ifdef _WIN32
66 extern struct ipx_driver ipx_win;
67 #endif
68
69 #define MAX_IPX_DATA 576
70
71 int ipx_fd;
72 ipx_socket_t ipx_socket_data;
73 ubyte ipx_installed=0;
74 ushort ipx_socket = 0;
75 uint ipx_network = 0;
76 ubyte ipx_MyAddress[10];
77 int ipx_packetnum = 0;                  /* Sequence number */
78 //int     ipx_packettotal=0,ipx_lastspeed=0;
79
80 /* User defined routing stuff */
81 typedef struct user_address {
82         ubyte network[4];
83         ubyte node[6];
84         ubyte address[6];
85 } user_address;
86 #define MAX_USERS 64
87 int Ipx_num_users = 0;
88 user_address Ipx_users[MAX_USERS];
89
90 #define MAX_NETWORKS 64
91 int Ipx_num_networks = 0;
92 uint Ipx_networks[MAX_NETWORKS];
93
94 int ipx_general_PacketReady(ipx_socket_t *s) {
95         fd_set set;
96         struct timeval tv;
97         
98         FD_ZERO(&set);
99         FD_SET(s->fd, &set);
100         tv.tv_sec = tv.tv_usec = 0;
101         if (select(s->fd + 1, &set, NULL, NULL, &tv) > 0)
102                 return 1;
103         else
104                 return 0;
105 }
106
107 struct ipx_driver *driver = &ipx_udp;
108
109 ubyte * ipx_get_my_server_address()
110 {
111         return (ubyte *)&ipx_network;
112 }
113
114 ubyte * ipx_get_my_local_address()
115 {
116         return (ubyte *)(ipx_MyAddress + 4);
117 }
118
119 void arch_ipx_set_driver(int ipx_driver)
120 {
121         switch(ipx_driver) {
122 #ifdef _WIN32
123         case IPX_DRIVER_IPX: driver = &ipx_win; break;
124 #else
125 #ifdef NATIVE_IPX
126         case IPX_DRIVER_IPX: driver = &ipx_bsd; break;
127 #endif //NATIVE_IPX
128 #endif
129 #ifdef KALINIX
130         case IPX_DRIVER_KALI: driver = &ipx_kali; break;
131 #endif
132         case IPX_DRIVER_UDP: driver = &ipx_udp; break;
133         case IPX_DRIVER_MCAST4: driver = &ipx_mcast4; break;
134         default: Int3();
135         }
136 }
137
138 int ipx_init(int socket_number)
139 {
140         int i;
141 #ifdef _WIN32
142         WORD wVersionRequested;
143         WSADATA wsaData;
144         
145         wVersionRequested = MAKEWORD(2, 0);
146         if (WSAStartup( wVersionRequested, &wsaData))
147         {
148                 return IPX_SOCKET_ALREADY_OPEN;
149         }
150         
151 #if 0
152         if ( LOBYTE( wsaData.wVersion ) != 2 ||
153                 HIBYTE( wsaData.wVersion ) != 0 ) {
154                 /* We couldn't find a usable WinSock DLL. */
155                 WSACleanup( );
156                 return IPX_SOCKET_TABLE_FULL;
157         }
158 #endif
159 #endif
160         
161         if ((i = FindArg("-ipxnetwork")) && Args[i + 1]) {
162                 unsigned long n = strtol(Args[i + 1], NULL, 16);
163                 ipx_MyAddress[0] = n >> 24; ipx_MyAddress[1] = (n >> 16) & 255;
164                 ipx_MyAddress[2] = (n >> 8) & 255; ipx_MyAddress[3] = n & 255;
165                 printf("IPX: Using network %08x\n", (unsigned int)n);
166         }
167         if (driver->OpenSocket(&ipx_socket_data, socket_number)) {
168                 return IPX_NOT_INSTALLED;
169         }
170         driver->GetMyAddress();
171         memcpy(&ipx_network, ipx_MyAddress, 4);
172         Ipx_num_networks = 0;
173         memcpy( &Ipx_networks[Ipx_num_networks++], &ipx_network, 4 );
174         ipx_installed = 1;
175         atexit(ipx_close);
176         return IPX_INIT_OK;
177 }
178
179 void ipx_close()
180 {
181         if (ipx_installed)
182         {
183 #ifdef _WIN32
184                 WSACleanup();
185 #endif
186                 driver->CloseSocket(&ipx_socket_data);
187         }
188         ipx_installed = 0;
189 }
190
191 int ipx_get_packet_data( ubyte * data )
192 {
193         struct ipx_recv_data rd;
194         char buf[MAX_IPX_DATA];
195 //killed 6-15-99 to get rid of compile warnings - OE
196 //      uint best_id = 0;
197 //      uint pkt_num;
198 //end kill - OE
199         int size;
200         int best_size = 0;
201 //edited 04/12/99 Matt Mueller - duh, we don't want to throw all that data away!
202         //--killed-- Like the original, only take latest packet, throw away rest
203         //do _NOT_ throw them away!
204         while (driver->PacketReady(&ipx_socket_data)) {
205                 if ((size = 
206                      driver->ReceivePacket(&ipx_socket_data, buf, 
207                       sizeof(buf), &rd)) > 4) {
208                      if (!memcmp(rd.src_network, ipx_MyAddress, 10)) 
209                         continue;       /* don't get own pkts */
210 //--killed--                 pkt_num = INTEL_INT(*(uint *)buf);
211 //--killed--                 if (pkt_num >= best_id) {
212                         memcpy(data, buf + 4, size - 4);
213                                 return size-4;
214 //--killed--                    best_id = pkt_num;
215 //--killed--                    best_size = size - 4;
216 //--killed--                 }
217 //end edit -MM
218                 }
219         }
220         return best_size;
221 }
222
223 void ipx_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address )
224 {
225         u_char buf[MAX_IPX_DATA];
226         IPXPacket_t ipx_header;
227
228         Assert(datasize <= MAX_IPX_DATA+4);
229         
230         memcpy(ipx_header.Destination.Network, network, 4);
231         memcpy(ipx_header.Destination.Node, immediate_address, 6);
232         {
233                 u_short socket = htons(ipx_socket_data.socket);
234                 memcpy(ipx_header.Destination.Socket, &socket, 2);
235         }
236         ipx_header.PacketType = 4; /* Packet Exchange */
237         {
238                 int packetnum = INTEL_INT(ipx_packetnum);
239                 memcpy(buf, &packetnum, 4);
240         }
241         ipx_packetnum++;
242     //ipx_packettotal+=datasize+4;
243     //if (f2i(Players[Player_num].time_level) && (f2i(Players[Player_num].time_level)%10!=ipx_lastspeed))
244         //{
245         //   ipx_lastspeed=f2i(Players[Player_num].time_level)%10;
246         //   printf("tot=%i,t2=%i,time=%i,avg=%i,a2=%i\n",ipx_packetnum,ipx_packettotal,(int)f2i(Players[Player_num].time_level),
247         //          ipx_packetnum/(int)f2i(Players[Player_num].time_level),
248         //          ipx_packettotal/(int)f2i(Players[Player_num].time_level));
249         //}    
250         memcpy(buf + 4, data, datasize);
251         driver->SendPacket(&ipx_socket_data, &ipx_header, buf, datasize + 4);
252 }
253
254 void ipx_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
255 {
256         // let's hope Linux knows how to route it
257         memcpy( local_target, node, 6 );
258 }
259
260 void ipx_send_broadcast_packet_data( ubyte * data, int datasize )       
261 {
262         int i, j;
263         ubyte broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
264         ubyte local_address[6];
265
266         // Set to all networks besides mine
267         for (i=0; i<Ipx_num_networks; i++ )     {
268                 if ( memcmp( &Ipx_networks[i], &ipx_network, 4 ) )      {
269                         ipx_get_local_target( (ubyte *)&Ipx_networks[i], broadcast, local_address );
270                         ipx_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast, local_address );
271                 } else {
272                         ipx_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast, broadcast );
273                 }
274         }
275
276         //OLDipx_send_packet_data( data, datasize, (ubyte *)&ipx_network, broadcast, broadcast );
277
278         // Send directly to all users not on my network or in the network list.
279         for (i=0; i<Ipx_num_users; i++ )        {
280                 if ( memcmp( Ipx_users[i].network, &ipx_network, 4 ) )  {
281                         for (j=0; j<Ipx_num_networks; j++ )             {
282                                 if (!memcmp( Ipx_users[i].network, &Ipx_networks[j], 4 ))
283                                         goto SkipUser;
284                         }
285                         ipx_send_packet_data( data, datasize, Ipx_users[i].network, Ipx_users[i].node, Ipx_users[i].address );
286 SkipUser:
287                         j = 0;
288                 }
289         }
290 }
291
292 // Sends a non-localized packet... needs 4 byte server, 6 byte address
293 void ipx_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address )
294 {
295         ubyte local_address[6];
296
297 #ifdef WORDS_NEED_ALIGNMENT
298         int zero = 0;
299         if (memcmp(server, &zero, 4)) {
300 #else // WORDS_NEED_ALIGNMENT
301         if ((*(uint *)server) != 0) {
302 #endif // WORDS_NEED_ALIGNMENT
303                 ipx_get_local_target( server, address, local_address );
304                 ipx_send_packet_data( data, datasize, server, address, local_address );
305         } else {
306                 // Old method, no server info.
307                 ipx_send_packet_data( data, datasize, server, address, address );
308         }
309 }
310
311 int ipx_change_default_socket( ushort socket_number )
312 {
313         if ( !ipx_installed ) return -3;
314
315         driver->CloseSocket(&ipx_socket_data);
316         if (driver->OpenSocket(&ipx_socket_data, socket_number)) {
317                 return -3;
318         }
319         return 0;
320 }
321
322 void ipx_read_user_file(char * filename)
323 {
324         FILE * fp;
325         user_address tmp;
326         char temp_line[132], *p1;
327         int n, ln=0, x;
328
329         if (!filename) return;
330
331         Ipx_num_users = 0;
332
333         fp = fopen( filename, "rt" );
334         if ( !fp ) return;
335
336         printf( "Broadcast Users:\n" );
337
338         while (fgets(temp_line, 132, fp)) {
339                 ln++;
340                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
341                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
342 #if 1 // adb: replaced sscanf(..., "%2x...", (char *)...) with better, but longer code
343                 if (strlen(temp_line) >= 21 && temp_line[8] == '/') {
344                         for (n = 0; n < 4; n++) {
345                                 if (sscanf(temp_line + n * 2, "%2x", &x) != 1)
346                                         break;
347                                 tmp.network[n] = x;
348                         }
349                         if (n != 4)
350                                 continue;
351                         for (n = 0; n < 6; n++) {
352                                 if (sscanf(temp_line + 9 + n * 2, "%2x", &x) != 1)
353                                         break;
354                                 tmp.node[n] = x;
355                         }
356                         if (n != 6)
357                                 continue;
358                 } else
359                         continue;
360 #else
361                 n = sscanf( temp_line, "%2x%2x%2x%2x/%2x%2x%2x%2x%2x%2x", &tmp.network[0], &tmp.network[1], &tmp.network[2], &tmp.network[3], &tmp.node[0], &tmp.node[1], &tmp.node[2],&tmp.node[3], &tmp.node[4], &tmp.node[5] );
362                 if ( n != 10 ) continue;
363 #endif
364                 if ( Ipx_num_users < MAX_USERS )        {
365                         ubyte * ipx_real_buffer = (ubyte *)&tmp;
366                         ipx_get_local_target( tmp.network, tmp.node, tmp.address );
367                         Ipx_users[Ipx_num_users++] = tmp;
368                         printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
369                         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] );
370                 } else {
371                         printf( "Too many addresses in %s! (Limit of %d)\n", filename, MAX_USERS );
372                         fclose(fp);
373                         return;
374                 }
375         }
376         fclose(fp);
377 }
378
379
380 void ipx_read_network_file(char * filename)
381 {
382         FILE * fp;
383         user_address tmp;
384         char temp_line[132], *p1;
385         int i, n, ln=0, x;
386
387         if (!filename) return;
388
389         fp = fopen( filename, "rt" );
390         if ( !fp ) return;
391
392         printf( "Using Networks:\n" );
393         for (i=0; i<Ipx_num_networks; i++ )             {
394                 ubyte * n1 = (ubyte *)&Ipx_networks[i];
395                 printf("* %02x%02x%02x%02x\n", n1[0], n1[1], n1[2], n1[3] );
396         }
397
398         while (fgets(temp_line, 132, fp)) {
399                 ln++;
400                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
401                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
402 #if 1 // adb: replaced sscanf(..., "%2x...", (char *)...) with better, but longer code
403                 if (strlen(temp_line) >= 8) {
404                         for (n = 0; n < 4; n++) {
405                                 if (sscanf(temp_line + n * 2, "%2x", &x) != 1)
406                                         break;
407                                 tmp.network[n] = x;
408                         }
409                         if (n != 4)
410                                 continue;
411                 } else
412                         continue;
413 #else
414                 n = sscanf( temp_line, "%2x%2x%2x%2x", &tmp.network[0], &tmp.network[1], &tmp.network[2], &tmp.network[3] );
415                 if ( n != 4 ) continue;
416 #endif
417                 if ( Ipx_num_networks < MAX_NETWORKS  ) {
418                         int j;
419                         for (j=0; j<Ipx_num_networks; j++ )     
420                                 if ( !memcmp( &Ipx_networks[j], tmp.network, 4 ) )
421                                         break;
422                         if ( j >= Ipx_num_networks )    {
423                                 memcpy( &Ipx_networks[Ipx_num_networks++], tmp.network, 4 );
424                                 printf("  %02x%02x%02x%02x\n", tmp.network[0], tmp.network[1], tmp.network[2], tmp.network[3] );
425                         }
426                 } else {
427                         printf( "Too many networks in %s! (Limit of %d)\n", filename, MAX_NETWORKS );
428                         fclose(fp);
429                         return;
430                 }
431         }
432         fclose(fp);
433 }
434
435 // Initalizes the protocol-specific member of the netgame packet.
436 void ipx_init_netgame_aux_data(ubyte buf[])
437 {
438         if(driver->InitNetgameAuxData)
439                 driver->InitNetgameAuxData(&ipx_socket_data, buf);
440 }
441
442 // Handles the protocol-specific member of the netgame packet.
443 int ipx_handle_netgame_aux_data(const ubyte buf[])
444 {
445         if(driver->HandleNetgameAuxData)
446                 return driver->HandleNetgameAuxData(&ipx_socket_data, buf);
447         return 0;
448 }
449
450 // Notifies the protocol that we're done with a particular game
451 void ipx_handle_leave_game()
452 {
453         if(driver->HandleLeaveGame)
454                 driver->HandleLeaveGame(&ipx_socket_data);
455 }
456
457 // Send a packet to every member of the game.
458 int ipx_send_game_packet(ubyte *data, int datasize)
459 {
460         if(driver->SendGamePacket) {
461                 u_char buf[MAX_IPX_DATA];
462
463                 memcpy(buf, &ipx_packetnum, 4);
464                 ipx_packetnum++;
465                 memcpy(buf + 4, data, datasize);
466                 *(uint *)data = ipx_packetnum++;
467                 return driver->SendGamePacket(&ipx_socket_data, buf, datasize + 4);
468         } else {
469                 // Loop through all the players unicasting the packet.
470                 int i;
471
472                 //printf("Sending game packet: N_players = %i\n", N_players);
473
474                 for(i=0; i<N_players; i++) {
475                         if(Players[i].connected && (i != Player_num))
476                                 ipx_send_packet_data(data, datasize, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
477                 }
478                 return datasize;
479         }
480
481         return 0;
482 }