source: abuse/trunk/src/innet.cpp @ 39

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