source: abuse/tags/pd/macabuse/src/innet.c

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