source: abuse/tags/pd/abuse/src/innet.c @ 49

Last change on this file since 49 was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 16.5 KB
Line 
1/*
2
3  This file is a combination of :
4    src/net/unix/unixnfc.c
5    src/net/unix/netdrv.c
6    src/net/unix/undrv.c
7
8    netdrv & undrv compile to a stand-alone program with talk with unixnfc
9via a FIFO in /tmp, using a RPC-like scheme.  This versions runs inside
10of a abuse and therefore is a bit simpler.
11
12
13*/
14#include "demo.hpp"
15#include "macs.hpp"
16#include "specs.hpp"
17#include "level.hpp"
18#include "game.hpp"
19#include <stdio.h>
20#include "timing.hpp"
21#include "fileman.hpp"
22#include "netface.hpp"
23
24#include "gserver.hpp"
25#include "gclient.hpp"
26#include "dprint.hpp"
27#include "netcfg.hpp"
28
29
30extern char *symbol_str(char *name);
31
32#ifdef __WATCOMC__
33#define getlogin() "DOS user"
34#endif
35
36
37base_memory_struct *base;   // points to shm_addr
38base_memory_struct local_base;
39net_address *net_server=NULL;
40extern int registered;
41net_protocol *prot=NULL;
42net_socket *comm_sock=NULL,*game_sock=NULL;
43extern char lsf[256];
44game_handler *game_face=NULL;
45int local_client_number=0;        // 0 is the server
46join_struct *join_array=NULL;      // points to an array of possible joining clients
47extern char *get_login();
48extern void set_login(char *name);
49
50int net_init(int argc, char **argv)
51{
52  int i,x,db_level=0;
53  base=&local_base;
54
55  local_client_number=0;
56
57  if (!main_net_cfg)
58    main_net_cfg=new net_configuration;
59
60
61  if (!registered) return 0;
62
63  for (i=1;i<argc;i++)
64    if (!strcmp(argv[i],"-nonet"))
65      return 0;
66    else if (!strcmp(argv[i],"-port"))
67    {
68      if (i==argc-1 || !sscanf(argv[i+1],"%d",&x) || x<1 || x>0x7fff)
69      {
70        fprintf(stderr,"bad value following -port, use 1..32000\n");
71        return 0;
72      } else
73        main_net_cfg->port=x;
74    } else if (!strcmp(argv[i],"-net") && i<argc-1)
75    {
76      i++;
77      strcpy(main_net_cfg->server_name,argv[i]);
78      main_net_cfg->state=net_configuration::CLIENT;
79    }
80    else if (!strcmp(argv[i],"-ndb"))
81    {
82      if (i==argc-1 || !sscanf(argv[i+1],"%d",&x) || x<1 || x>3)
83      {
84        fprintf(stderr,"bad value following -ndb, use 1..3\n");
85        return 0;
86      } else { db_level=x; }
87    } else if (!strcmp(argv[i],"-server"))
88       main_net_cfg->state=net_configuration::SERVER;
89     else if (!strcmp(argv[i],"-min_players"))
90     {
91       i++;
92       int x=atoi(argv[i]);
93       if (x>=1 && x<=8)
94         main_net_cfg->min_players=x;
95       else fprintf(stderr,"bad value for min_players use 1..8\n");
96     }
97
98 
99  net_protocol *n=net_protocol::first,*usable=NULL;     // find a usable protocol from installed list
100  int total_usable=0;
101  for (;n;n=n->next)                                    // show a list of usables, just to be cute
102  {
103    fprintf(stderr,"Protocol %s : ",n->installed() ? "Installed" : "Not_installed");
104    fprintf(stderr,"%s\n",n->name());
105    if (n->installed())
106    {
107      total_usable++;
108      usable=n;
109    }     
110  }
111
112  if (!usable) { fprintf(stderr,"No network protocols installed\n");  return 0; }
113  prot=usable;
114  prot->set_debug_printing((net_protocol::debug_type)db_level);
115  if (main_net_cfg->state==net_configuration::SERVER)
116    set_login(main_net_cfg->name);
117
118  comm_sock=game_sock=NULL;
119  if (main_net_cfg->state==net_configuration::CLIENT)
120  {
121    dprintf("Attempting to locate server %s, please wait\n",main_net_cfg->server_name);
122    char *sn=main_net_cfg->server_name;
123    net_server=prot->get_node_address(sn,DEFAULT_COMM_PORT,0);
124    if (!net_server) { dprintf(symbol_str("unable_locate"));  exit(0); }   
125    dprintf("Server located!  Please wait while data loads....\n");
126  }
127
128  fman=new file_manager(argc,argv,prot);                                       // manages remote file access
129  game_face=new game_handler;
130  join_array=(join_struct *)jmalloc(sizeof(join_struct)*MAX_JOINERS,"join array");
131  base->join_list=NULL;
132  base->mem_lock=0;
133  base->calc_crcs=0;
134  base->get_lsf=0;
135  base->wait_reload=0;
136  base->need_reload=0;
137  base->input_state=INPUT_COLLECTING;
138  base->current_tick=0;
139  base->packet.packet_reset();
140
141  return 1;
142}
143
144 
145
146
147int net_start()  // is the game starting up off the net? (i.e. -net hostname)
148{   return (main_net_cfg && main_net_cfg->state==net_configuration::CLIENT);  }
149
150
151
152int kill_net()
153{
154  if (game_face) delete game_face;  game_face=NULL;
155  if (join_array) jfree(join_array);  join_array=NULL;
156  if (game_sock) { delete game_sock; game_sock=NULL; }
157  if (comm_sock) { delete comm_sock; comm_sock=NULL; }
158  delete fman;  fman=NULL;
159  if (net_server) { delete net_server; net_server=NULL; }
160  if (prot)
161  {
162 
163    prot->cleanup();
164    prot=NULL;
165    return 1;
166  } else return 0;
167}
168
169void net_uninit()
170{
171  kill_net();
172}
173
174
175int NF_set_file_server(net_address *addr)
176{
177  if (prot)
178  {
179    fman->set_default_fs(addr);
180    net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
181
182    if (!sock) { printf("set_file_server::connect failed\n"); return 0; }
183    uchar cmd=CLIENT_CRC_WAITER;
184    if ( (sock->write(&cmd,1)!=1 && printf("set_file_server::writefailed\n")) ||
185         (sock->read(&cmd,1)!=1  && printf("set_file_server::read failed\n")))        // wait for confirmation that crc's are written
186    { delete sock; return 0; }
187    delete sock;
188    return cmd;
189  } else return 0;
190}
191
192int NF_set_file_server(char *name)
193{
194  if (prot)
195  {
196    net_address *addr=prot->get_node_address(name,DEFAULT_COMM_PORT,0);
197    if (addr)
198    {
199      int ret=NF_set_file_server(addr);
200      delete addr;
201      return ret;
202    } else return 0;
203  } else return 0;
204}
205
206
207int NF_open_file(char *filename, char *mode)
208{
209  if (prot)
210    return fman->rf_open_file(filename,mode);
211  else return -2;
212}
213
214
215long NF_close(int fd)
216{
217  if (prot)
218    return fman->rf_close(fd);
219  else return 0;
220}
221
222long NF_read(int fd, void *buf, long size)
223{
224  if (prot)
225    return fman->rf_read(fd,buf,size);
226  else return 0;
227}
228
229long NF_filelength(int fd)
230{
231  if (prot)
232    return fman->rf_file_size(fd);
233  else return 0;
234}
235
236long NF_seek(int fd, long offset)
237{
238  if (prot)
239    return fman->rf_seek(fd,offset);
240  else return 0;
241}
242
243long NF_tell(int fd)
244{
245  if (prot)
246    return fman->rf_tell(fd);
247  else return 0;
248}
249
250
251void service_net_request()
252{
253  if (prot)
254  {
255    if (prot->select(0))  // anything happening net-wise?
256    {
257      if (comm_sock && comm_sock->ready_to_read())  // new connection?
258      {
259                                net_address *addr;
260                       
261                                net_socket *new_sock=comm_sock->accept(addr);   
262                                if (new_sock)
263                                {
264                                  uchar client_type;
265                                  if (new_sock->read(&client_type,1)!=1)
266                                  {
267                                    delete addr;       
268                                    delete new_sock;
269                                  }
270                                  else
271                                  {
272                                    switch (client_type)
273                                    {
274                                      case CLIENT_NFS :
275                                      {
276                                                                delete addr;   
277                                                                fman->add_nfs_client(new_sock);
278                                      } break;
279                                      case CLIENT_CRC_WAITER :
280                                      {         
281                                                                crc_man.write_crc_file(NET_CRC_FILENAME);       // return 0 on failure
282                                                                client_type=1;                                  // confirmation byte
283                                                                new_sock->write(&client_type,1);
284                                                                delete new_sock;                                // done with this socket now
285                                                                delete addr;   
286                                      } break;
287                                      case CLIENT_LSF_WAITER :          // wants to know which .lsp file to start with
288                                      {
289                                                                uchar len=strlen(lsf);
290                                                                new_sock->write(&len,1);
291                                                                new_sock->write(lsf,len);
292                                                                delete new_sock;
293                                                                delete addr;
294                                      } break;
295                                      default :
296                                      {
297                                                                if (game_face->add_client(client_type,new_sock,addr)==0)  // ask server or client to add new client
298                                                                {
299                                                                  delete addr;
300                                                                  delete new_sock;
301                                                                }
302                                      } break;
303                                    }
304                                  }                 
305                                }
306      }
307      if (!game_face->process_net())
308      {
309                                delete game_face;
310                                game_face=new game_handler;
311      }
312      fman->process_net();     
313    }
314  }
315}
316
317
318int get_remote_lsf(net_address *addr, char *filename)  // filename should be 256 bytes
319{
320  if (prot)
321  {
322    net_socket *sock=prot->connect_to_server(addr,net_socket::SOCKET_SECURE);
323    if (!sock) return 0;
324
325    uchar ctype=CLIENT_LSF_WAITER;
326    uchar len;
327
328    if (sock->write(&ctype,1)!=1 ||
329                                sock->read(&len,1)!=1 || len==0 ||
330                                sock->read(filename,len)!=len)
331    {
332      delete sock;
333      return 0;
334    }
335
336    delete sock;
337    return 1; 
338
339  } else return 0;
340}
341
342void server_check() { ; }
343
344int request_server_entry()
345{
346  if (prot && main_net_cfg)
347  {
348    if (!net_server) return 0;
349
350    if (game_sock) delete game_sock;
351    dprintf("Joining game in progress, hang on....\n");
352
353    game_sock=prot->create_listen_socket(main_net_cfg->port+1,net_socket::SOCKET_FAST);     // this is used for fast game packet transmission
354    if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
355    game_sock->read_selectable();
356
357    net_socket *sock=prot->connect_to_server(net_server,net_socket::SOCKET_SECURE);
358    if (!sock)
359    {
360      fprintf(stderr,"unable to connect to server\n");
361      return 0;
362    }
363
364    uchar ctype=CLIENT_ABUSE;
365    ushort port=lstl(main_net_cfg->port+1),cnum;
366
367    uchar reg;
368    if (sock->write(&ctype,1)!=1 ||   // send server out game port
369                                sock->read(&reg,1)!=1)        // is remote engine registered?
370    { delete sock; return 0; }
371
372    if (reg==2)   // too many players
373    {
374      fprintf(stderr,symbol_str("max_players"));
375      delete sock;
376      return 0;
377    }
378
379    // maker sure the two games are both registered or unregistered or sync problems
380    // will occur.
381
382    if (reg && !registered)
383    {
384      fprintf(stderr,symbol_str("net_not_reg"));
385      delete sock;
386      return 0;
387    }
388
389    if (!reg && registered)
390    {
391      fprintf(stderr,symbol_str("server_not_reg"));
392      delete sock;
393      return 0;
394    }
395
396    char uname[256];
397    if (get_login())
398      strcpy(uname,get_login());
399    else strcpy(uname,"unknown");
400    uchar len=strlen(uname)+1;
401    short nkills;
402
403    if (sock->write(&len,1)!=1 ||
404                                sock->write(uname,len)!=len ||
405                                sock->write(&port,2)!=2  ||            // send server out game port
406                                sock->read(&port,2)!=2   ||            // read server's game port
407                                sock->read(&nkills,2)!=2 ||
408                                sock->read(&cnum,2)!=2   || cnum==0    // read player number (cannot be 0 because 0 is server)
409                                )
410    { delete sock; return 0; }
411
412    nkills=lstl(nkills);
413    port=lstl(port);
414    cnum=lstl(cnum);
415   
416    main_net_cfg->kills=nkills;
417    net_address *addr=net_server->copy();
418    addr->set_port(port);
419
420    delete game_face;
421    game_face=new game_client(sock,addr);
422    delete addr;
423
424    local_client_number=cnum;
425    return cnum;
426  } else return 0;
427}
428
429int reload_start()
430{
431  if (prot)
432    return game_face->start_reload();
433  else return 0;
434}
435
436int reload_end()
437{
438  if (prot)
439    return game_face->end_reload();
440  else return 0;
441}
442
443
444void net_reload()
445{
446  if (prot)
447  {
448    if (net_server)
449    {
450      if (current_level)
451        delete current_level;
452      bFILE *fp;
453
454      if (!reload_start()) return ;
455
456      do {            // make sure server saves the file
457                                fp=open_file(NET_STARTFILE,"rb");
458                                if (fp->open_failure()) { delete fp; fp=NULL; }
459      } while (!fp);
460
461      spec_directory sd(fp); 
462
463      spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
464      if (!e)
465      {
466                                the_game->show_help("This level is missing copyright information, cannot load\n");
467                                current_level=new level(100,100,"untitled");
468                                the_game->need_refresh();
469      }
470      else
471        current_level=new level(&sd,fp,NET_STARTFILE);
472
473      delete fp;     
474      base->current_tick=(current_level->tick_counter()&0xff);
475
476      reload_end();
477    } else if (current_level)
478    {
479     
480      join_struct *join_list=base->join_list;
481
482
483      while (join_list)
484      {
485       
486                                view *f=player_list;
487                                for (;f && f->next;f=f->next);      // find last player, add one for pn
488                                int i,st=0;
489                                for (i=0;i<total_objects;i++)
490                                if (!strcmp(object_names[i],"START"))
491                                st=i;
492                       
493                                game_object *o=create(current_start_type,0,0);
494                                game_object *start=current_level->get_random_start(320,NULL);
495                                if (start) { o->x=start->x; o->y=start->y; }
496                                else { o->x=100; o->y=100; }
497                       
498                                f->next=new view(o,NULL,join_list->client_id);
499                                strcpy(f->next->name,join_list->name);
500                                o->set_controller(f->next);
501                       
502                                if (start)
503                                current_level->add_object_after(o,start);
504                                else
505                                current_level->add_object(o);
506                       
507                                view *v=f->next;     
508                       
509                                v->cx1=5;
510                                v->cy1=5;
511                                v->cx2=319-5;
512                                v->cy2=199-5;
513                                join_list=join_list->next;
514      }     
515      base->join_list=NULL;
516      current_level->save(NET_STARTFILE,1);
517      base->mem_lock=0;
518
519
520      jwindow *j=eh->new_window(0,yres/2,-1,-1,new info_field(WINDOW_FRAME_LEFT,
521                                                                   WINDOW_FRAME_TOP,
522                                                                   0,symbol_str("resync"),
523                                              new button(WINDOW_FRAME_LEFT,
524                                                         WINDOW_FRAME_TOP+eh->font()->height()+5,ID_NET_DISCONNECT,
525                                                         symbol_str("slack"),NULL)),symbol_str("hold!"))
526;
527
528 
529
530      eh->flush_screen();
531      if (!reload_start()) return ;
532
533      base->input_state=INPUT_RELOAD;    // if someone missed the game tick with the RELOAD data in it, make sure the get it
534 
535      // wait for all client to reload the level with the new players
536      do 
537      {
538                                service_net_request();
539                                if (eh->event_waiting())
540                                {
541                                  event ev;
542                                  do
543                                  {
544                                    eh->get_event(ev);
545                                    if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
546                                    {
547                                      game_face->end_reload(1);
548                                      base->input_state=INPUT_PROCESSING;
549                                    }
550                       
551                                  } while (eh->event_waiting());
552                       
553                                  eh->flush_screen();
554                                }
555
556      } while (!reload_end());
557      eh->close_window(j);
558      unlink(NET_STARTFILE);
559
560      the_game->reset_keymap();
561
562      base->input_state=INPUT_COLLECTING;
563
564    }     
565  }
566}
567
568
569int client_number() { return local_client_number; }
570
571
572void send_local_request()
573{
574
575  if (prot)
576  {   
577    if (current_level)
578      base->current_tick=(current_level->tick_counter()&0xff);
579    game_face->add_engine_input();
580  } else base->input_state=INPUT_PROCESSING;
581
582}
583
584
585void kill_slackers()
586{
587  if (prot)
588  {
589    if (!game_face->kill_slackers())
590    {
591      delete game_face;
592      game_face=new game_handler();
593    }
594  }
595}
596
597int get_inputs_from_server(unsigned char *buf)
598{
599  if (prot && base->input_state!=INPUT_PROCESSING)      // if input is not here, wait on it
600  {
601    time_marker start;
602
603    int total_retry=0;
604    jwindow *abort=NULL;
605
606    while (base->input_state!=INPUT_PROCESSING)
607    {
608      if (!prot)
609      {
610        base->input_state=INPUT_PROCESSING;
611        return 1;
612      }
613      service_net_request();
614
615      time_marker now;                   // if this is taking to long, the packet was probably lost, ask for it to be resent
616
617      if (now.diff_time(&start)>0.05)
618      {
619        if (prot->debug_level(net_protocol::DB_IMPORTANT_EVENT))
620          fprintf(stderr,"(missed packet)");
621
622       
623        game_face->input_missing();
624        start.get_time();
625
626        total_retry++;
627        if (total_retry==12000)    // 2 minutes and nothing
628        {
629          abort=eh->new_window(0,yres/2,-1,eh->font()->height()*4,
630                               new info_field(WINDOW_FRAME_LEFT,
631                                              WINDOW_FRAME_TOP,
632                                              0,symbol_str("waiting"),
633                                              new button(WINDOW_FRAME_LEFT,
634                                                         WINDOW_FRAME_TOP+eh->font()->height()+5,ID_NET_DISCONNECT,
635                                                         symbol_str("slack"),NULL)),symbol_str("Error"));         
636          eh->flush_screen();
637        }
638      }
639      if (abort)
640      {
641        if (eh->event_waiting())
642        {
643          event ev;
644          do
645          {
646            eh->get_event(ev);
647            if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
648            {
649              kill_slackers();
650              base->input_state=INPUT_PROCESSING;
651            }
652          } while (eh->event_waiting());
653
654          eh->flush_screen();
655        }
656      }
657    }
658
659    if (abort)
660    {
661      eh->close_window(abort);
662      the_game->reset_keymap();
663
664    }
665  }
666
667
668  memcpy(base->last_packet.data,base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size());
669 
670  int size=base->packet.packet_size(); 
671  memcpy(buf,base->packet.packet_data(),size);
672
673  base->packet.packet_reset();
674  base->mem_lock=0;
675
676  return size;
677}
678
679int become_server(char *name)
680{
681  if (prot && main_net_cfg)
682  {
683    delete game_face;
684
685    if (comm_sock) delete comm_sock;   
686    comm_sock=prot->create_listen_socket(main_net_cfg->port,net_socket::SOCKET_SECURE);   // this is used for incomming connections
687    if (!comm_sock) { prot=NULL; return 0; }
688    comm_sock->read_selectable();
689                prot->start_notify(0x9090, name, strlen(name));  // should we define a new socket for notifiers?
690
691    if (game_sock) delete game_sock;
692    game_sock=prot->create_listen_socket(main_net_cfg->port+1,net_socket::SOCKET_FAST);     // this is used for fast game packet transmission
693    if (!game_sock) { if (comm_sock) delete comm_sock; comm_sock=NULL; prot=NULL; return 0; }
694    game_sock->read_selectable();
695
696    game_face=new game_server;
697    local_client_number=0;
698    return 1;
699  }
700  return 0;
701}
702
703void read_new_views() { ; }
704
705
706void wait_min_players()
707{
708  if (game_face) game_face->game_start_wait();
709}
Note: See TracBrowser for help on using the repository browser.