source: abuse/trunk/src/unixnfc.cpp @ 112

Last change on this file since 112 was 106, checked in by Sam Hocevar, 12 years ago
  • Rename the "eh" variable to "wm" because it's a window manager, not an event handler.
  • No longer pass the window manager to functions, there's only one.

Inspired by Win32 Abuse changelog for January 28, 2001:

  • Starting work on singleton code; will get rid of all

references to an arbitrary window_manager* because
there's only going to be one, and it's not ever
going to change.

File size: 16.0 KB
Line 
1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
4 *
5 *  This software was released into the Public Domain. As with most public
6 *  domain software, no warranty is made or implied by Crack dot Com or
7 *  Jonathan Clark.
8 */
9
10#include "config.h"
11
12#include <sys/types.h>
13#include <sys/ipc.h>
14#include <sys/shm.h>
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <signal.h>
19#include <unistd.h>
20#include <sys/fcntl.h>
21#include <fcntl.h>
22
23#include "system.h"
24#include "indian.hpp"
25
26#include "netface.hpp"
27#include "nfserver.hpp"
28#include "view.hpp"
29#include "objects.hpp"
30#include "level.hpp"
31#include "timing.hpp"
32#include "server2.hpp"
33#include "game.hpp"
34#include "jwindow.hpp"
35
36extern char lsf[256];
37
38#define DIN_NAME "/tmp/.abuse_ndrv_out"   // opposite of driver's in/out
39#define DOUT_NAME "/tmp/.abuse_ndrv_in"
40
41#define real2shm(type,ptr) (ptr==NULL ? NULL : ((type *)((uint8_t *)(ptr)-(uint8_t *)base)))
42#define shm2real(type,ptr) (ptr==NULL ? NULL : ((type *)((intptr_t)(ptr)+(intptr_t)(base))))
43
44#ifdef __sgi
45#define next_process() sginap(0)
46#else
47#define next_process() usleep(1)
48#endif
49
50extern int crc_man_write_crc_file(char const *filename);
51int net_installed=0,net_out_fd,net_in_fd;
52int net_child=-1;
53int local_client_number=0;
54
55void *shm_addr=(void *)-1;  // shmat returns -1 on failure
56base_memory_struct *base;   // points to shm_addr
57base_memory_struct local_base;
58
59net_address *net_server=NULL;
60
61int net_start()
62{
63  return net_server!=NULL;
64}
65
66
67int kill_net()
68{
69
70  if (net_installed)
71  {
72    char cmd=EGCMD_DIE;
73    write(net_out_fd,&cmd,1);
74    read(net_in_fd,&cmd,1);
75    close(net_out_fd);
76    close(net_in_fd);
77  }
78
79  if (net_child!=-1)
80  {
81    kill(net_child,SIGINT);
82    net_child=-1;   
83  }
84
85  net_installed=0;
86  if (shm_addr!=(void *)-1)
87  {
88    shmdt((char *)shm_addr);
89    shm_addr=(void *)-1;
90    base=&local_base;
91  }
92}
93
94void net_uninit()
95{
96  kill_net();
97}
98
99int net_init(int argc, char **argv)
100{
101  int i,p1=-1,no_fork=0;
102  base=&local_base;
103  char *server_name=NULL;
104
105  for (i=1;i<argc;i++)
106    if (!strcmp(argv[i],"-nonet"))
107      return 0;
108    else if (!strcmp(argv[i],"-no_net_fork"))      // make it easy to run the driver under a debugger
109      no_fork=1;
110    else if (!strcmp(argv[i],"-port"))
111    {
112      if (i==argc-1 || !sscanf(argv[i+1],"%d",&p1))
113      {
114        fprintf(stderr,"bad value folloing -port");
115        return 0;
116      }
117    } else if (!strcmp(argv[i],"-net") && i<argc-1)
118    {
119      i++;
120      server_name=argv[i];     
121    }
122
123     
124   
125  char cmd[50];
126  if (p1!=-1)
127    sprintf(cmd,"undrv runme -port %d",p1);
128  else sprintf(cmd,"undrv runme");
129
130  if (!no_fork)
131  {
132    FILE *fp=popen(cmd,"rb");
133    if (!fp || !fscanf(fp,"%d",&net_child) || net_child==-1)
134    { fprintf(stderr,"could not run undrv, please make sure it's in your path\n");
135      return 0;
136    }
137
138    if (fp) pclose(fp);
139  }
140
141  do
142  { sleep(0);
143  } while (access(DIN_NAME,R_OK));
144  net_in_fd=open(DIN_NAME,O_RDWR);
145
146  do
147  { sleep(0);
148  } while (access(DOUT_NAME,W_OK));
149  net_out_fd=open(DOUT_NAME,O_RDWR);
150
151
152  uint8_t reg = 1;
153  if (write(net_out_fd,&reg,sizeof(reg))!=sizeof(reg))
154    return 0;
155
156  int shm_seg_id;
157  if (read(net_in_fd,&shm_seg_id,sizeof(shm_seg_id))!=sizeof(shm_seg_id))
158    return 0;
159
160  shm_addr=shmat(shm_seg_id,NULL,0);  // attach as read/write
161  if (shm_addr==(void *)-1)
162    return 0;
163
164  char ack=1;   // acknodge we read and attached
165  if (write(net_out_fd,&ack,1)!=1)
166    return 0; 
167
168
169  base=(base_memory_struct *)shm_addr;
170
171  net_installed=1;
172     
173  return 1;
174}
175
176#include <unistd.h>
177#include <sys/time.h>
178
179int NF_set_file_server(char *name)
180{
181  if (net_installed)
182  {
183    char cm[2]={NFCMD_SET_FS,strlen(name)+1};
184    if (write(net_out_fd,cm,2)!=2) { kill_net(); return 0; }
185    if (write(net_out_fd,name,cm[1])!=cm[1]) { kill_net(); return 0; }
186    if (read(net_in_fd,cm,1)!=1)  { kill_net(); return 0; }   // read the status of this command
187    next_process();
188    return cm[0];
189  } else return 0;
190}
191
192int NF_open_file(char const *filename, char const *mode)
193{
194  if (net_installed)
195  {
196    char cm[3]={NFCMD_OPEN,strlen(filename)+1,strlen(mode)+1};
197    if (write(net_out_fd,cm,3)!=3) { kill_net(); return -1; }
198    if (write(net_out_fd,filename,cm[1])!=cm[1])  { kill_net(); return -1; }
199    if (write(net_out_fd,mode,cm[2])!=cm[2])  { kill_net(); return -1; }
200
201    uint8_t file_type;
202    if (read(net_in_fd,&file_type,1)!=1)  { kill_net(); return -1; }   
203    if (file_type==NF_OPEN_LOCAL_FILE)
204    {
205      uint8_t name_size;
206      if (read(net_in_fd,&name_size,1)!=1)  { kill_net(); return -1; }         
207      int size=read(net_in_fd,filename,name_size);
208      if (size!=name_size)  { kill_net(); return -1; }   
209      return -2;
210    }
211    else if (file_type==NF_OPEN_FAILED) return -1;
212
213    int fd;
214    if (read(net_in_fd,&fd,sizeof(fd))!=sizeof(fd))  { kill_net(); return -1; }
215
216    return fd;
217  } else return -2;          // return open local
218}
219
220int32_t NF_close(int fd)
221{
222  if (net_installed)
223  {
224    char cm=NFCMD_CLOSE;
225    if (write(net_out_fd,&cm,1)!=1) { kill_net(); return 0; }
226    if (write(net_out_fd,&fd,sizeof(fd))!=sizeof(fd)) { kill_net(); return 0; }
227    char stat;
228    if (read(net_in_fd,&stat,sizeof(stat))!=sizeof(stat))  { kill_net(); return 0; }
229    return stat;
230  } else return 0; 
231}
232
233
234int32_t NF_read(int fd, void *buf, int32_t size)
235{
236  if (net_installed && size)
237  {
238    char cm=NFCMD_READ;
239
240    if (write(net_out_fd,&cm,1)!=1) { kill_net(); return 0; }
241    if (write(net_out_fd,&fd,sizeof(fd))!=sizeof(fd)) { kill_net(); return 0; }
242    if (write(net_out_fd,&size,sizeof(size))!=sizeof(size)) { kill_net(); return 0; }
243
244    int32_t total_read=0;
245    uint16_t t=0xffff;
246    while (size && t>=READ_PACKET_SIZE-2)
247    {
248      if (read(net_in_fd,&t,sizeof(t))!=sizeof(t))  { kill_net(); return 0; }     
249      if (read(net_in_fd,buf,t)!=t)  { kill_net(); return total_read; }
250
251      total_read+=t;
252      size-=t;
253      buf=(void *)((char *)buf+t);
254
255
256    }
257    return total_read;
258  } else return 0; 
259}
260
261
262int32_t NF_filelength(int fd)
263{
264  if (net_installed)
265  {
266    char cm=NFCMD_SIZE;
267    if (write(net_out_fd,&cm,1)!=1) { kill_net(); return 0; }
268    if (write(net_out_fd,&fd,sizeof(fd))!=sizeof(fd)) { kill_net(); return 0; }
269    int32_t size;
270    if (read(net_in_fd,&size,sizeof(size))!=sizeof(size))  { kill_net(); return 0; }
271    return size;
272  } else return 0; 
273}
274
275int32_t NF_tell(int fd)
276{
277  if (net_installed)
278  {
279    char cm=NFCMD_TELL;
280    if (write(net_out_fd,&cm,1)!=1) { kill_net(); return 0; }
281    if (write(net_out_fd,&fd,sizeof(fd))!=sizeof(fd)) { kill_net(); return 0; }
282    int32_t offset;
283    if (read(net_in_fd,&offset,sizeof(offset))!=sizeof(offset))  { kill_net(); return 0; }
284    return offset;
285  } else return 0; 
286}
287
288int32_t NF_seek(int fd, int32_t offset)
289{
290  if (net_installed)
291  {
292    char cm=NFCMD_SEEK;
293    if (write(net_out_fd,&cm,1)!=1) { kill_net(); return 0; }
294    if (write(net_out_fd,&fd,sizeof(fd))!=sizeof(fd)) { kill_net(); return 0; }
295    if (write(net_out_fd,&offset,sizeof(offset))!=sizeof(offset)) { kill_net(); return 0; }
296
297    int32_t offset;
298    if (read(net_in_fd,&offset,sizeof(offset))!=sizeof(offset))  { kill_net(); return 0; }
299    return offset;
300  } else return 0; 
301}
302
303static int aquire_mem_lock()
304{
305  if (base->mem_lock==0 || base->mem_lock==2)
306  {
307    base->mem_lock=2;
308    if (base->mem_lock==2)
309      return 1;
310  }
311//  next_process();   // probably just gonna loop until we get the lock so halt for next preocess
312  return 0;
313}
314
315void service_net_request()
316{
317  if (net_installed)
318  {
319    if (base->input_state==INPUT_NET_DEAD)
320      kill_net();
321    else
322    {
323      if (aquire_mem_lock())
324      {
325        if (base->calc_crcs)
326        {     
327          crc_man_write_crc_file(NET_CRC_FILENAME);       // return 0 on failure
328          base->calc_crcs=0;
329          base->mem_lock=0;
330
331          uint8_t cmd=NFCMD_CRCS_CALCED;
332          if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }
333        } else base->mem_lock=0;
334      }
335      if (aquire_mem_lock())
336      {
337        if (base->get_lsf)
338        {
339          base->get_lsf=0;
340          base->mem_lock=0;
341          uint8_t c[2]={NFCMD_PROCESS_LSF,strlen(lsf)+1};
342          if (write(net_out_fd,&c,2)!=2) { kill_net(); return ; }
343          if (write(net_out_fd,lsf,c[1])!=c[1]) { kill_net(); return ; }
344        } else base->mem_lock=0;
345      }
346    }
347  }
348}
349
350
351int get_remote_lsf(char *name, char *filename)  // filename should be 256 bytes
352{
353  if (net_installed)
354  {
355    uint8_t cm[2]={NFCMD_REQUEST_LSF,strlen(name)+1};
356    if (write(net_out_fd,cm,2)!=2) { kill_net(); return 0; }
357    if (write(net_out_fd,name,cm[1])!=cm[1]) { kill_net(); return 0; }
358    uint8_t size;
359    if (read(net_in_fd,&size,1)!=1) { kill_net(); return 0; }
360    if (size==0) return 0;
361    if (read(net_in_fd,filename,size)!=size) { kill_net(); return 0; }
362    return 1; 
363  } else return 0;
364}
365
366int request_server_entry()
367{
368  if (net_installed)
369  {
370    if (!net_server) return 0;
371    uint8_t cm[2]={NFCMD_REQUEST_ENTRY,strlen(net_server)+1};
372    if (write(net_out_fd,cm,2)!=2) { kill_net(); return 0; }
373    if (write(net_out_fd,net_server,cm[1])!=cm[1]) { kill_net(); return 0; }
374    uint16_t cnum;  // client number
375    if (read(net_in_fd,&cnum,2)!=2) { kill_net(); return 0; }
376    if (cnum==0) return 0;
377    local_client_number=cnum;
378    return 1;
379  } else return 0;
380}
381
382
383int reload_start()
384{
385  if (net_installed)
386  {
387    uint8_t cmd=NFCMD_RELOAD_START;
388    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return 0; }
389    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }
390    return cmd;
391  } else return 1;
392}
393
394
395int reload_end()
396{
397  if (net_installed)
398  {
399    uint8_t cmd=NFCMD_RELOAD_END;
400    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return 0; }
401    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }
402    return cmd;
403  } else return 1;
404}
405
406void net_reload()
407{
408  if (net_installed)
409  {
410    if (net_server)
411    {
412      if (current_level)
413        delete current_level;
414      bFILE *fp;
415
416      if (!reload_start()) return ;
417
418      do {            // make sure server saves the file
419        fp=open_file(NET_STARTFILE,"rb");
420        if (fp->open_failure()) { delete fp; fp=NULL; }
421      } while (!fp);
422
423      spec_directory sd(fp); 
424
425#if 0
426      spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
427      if (!e)
428      {
429        the_game->show_help("This level is missing copyright information, cannot load\n");
430        current_level=new level(100,100,"untitled");
431        the_game->need_refresh();
432      }
433      else
434#endif
435        current_level=new level(&sd,fp,NET_STARTFILE);
436
437      delete fp;     
438      base->current_tick=(current_level->tick_counter()&0xff);
439
440      reload_end();
441    } else if (current_level)
442    {
443     
444      join_struct *join_list=shm2real(join_struct,base->join_list);
445
446      while (!aquire_mem_lock())
447      {
448        next_process();
449        service_net_request();
450      }
451
452      while (join_list)
453      {
454       
455        view *f=player_list;
456        for (;f && f->next;f=f->next);      // find last player, add one for pn
457        int i,st=0;
458        for (i=0;i<total_objects;i++)
459        if (!strcmp(object_names[i],"START"))
460        st=i;
461
462        game_object *o=create(current_start_type,0,0);
463        game_object *start=current_level->get_random_start(320,NULL);
464        if (start) { o->x=start->x; o->y=start->y; }
465        else { o->x=100; o->y=100; }
466
467        f->next=new view(o,NULL,shm2real(join_struct,base->join_list)->client_id);
468        strcpy(f->next->name,shm2real(join_struct,base->join_list)->name);
469        o->set_controller(f->next);
470
471        if (start)
472        current_level->add_object_after(o,start);
473        else
474        current_level->add_object(o);
475
476        view *v=f->next;     
477
478        v->cx1=5;
479        v->cy1=5;
480        v->cx2=319-5;
481        v->cy2=199-5;
482        join_list=shm2real(join_struct,join_list->next);
483      }     
484      base->join_list=NULL;
485      current_level->save(NET_STARTFILE,1);
486      base->mem_lock=0;
487
488
489      jwindow *j=wm->new_window(0,yres/2,-1,-1,new info_field(WINDOW_FRAME_LEFT,
490                                                                   WINDOW_FRAME_TOP,
491                                                                   0,"Clients are re-syncing, please wait...",NULL));
492      wm->flush_screen();
493      if (!reload_start()) return ;
494
495      // wait for all client to reload the level with the new players
496      do 
497      {
498        next_process();
499      } while (!reload_end());
500      wm->close_window(j);
501
502    }     
503  }
504}
505
506int client_number() { return local_client_number; }
507
508
509void send_local_request()
510{
511  if (net_installed)
512  {
513    if (base->join_list)
514      base->packet.write_uint8(SCMD_RELOAD);
515
516    uint8_t cmd=NFCMD_SEND_INPUT;
517
518    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
519    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; }   
520    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
521  } else base->input_state=INPUT_PROCESSING;
522}
523
524void kill_slackers()
525{
526  if (net_installed)
527  {
528    uint8_t cmd=NFCMD_KILL_SLACKERS;
529    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
530    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; }       
531  }
532}
533
534int get_inputs_from_server(unsigned char *buf)
535{
536  if (net_installed && base->input_state!=INPUT_PROCESSING)      // if input is not here, wait on it
537  {
538    timeval start;
539    gettimeofday(&start,NULL);
540
541    int total_retry=0;
542    jwindow *abort=NULL;
543    linked_list input;
544    while (base->input_state!=INPUT_PROCESSING)
545    {
546      if (!net_installed) 
547      {
548        base->input_state=INPUT_PROCESSING;
549        return 1;
550      }
551      server_check();
552      service_net_request();
553
554      timeval now;                   // if this is taking to long, the packet was probably lost, ask for it to be resent
555      gettimeofday(&now,NULL);
556      if ((((now.tv_sec-start.tv_sec)*100)+(now.tv_usec-start.tv_usec)/10000)>20)
557      {
558//      fprintf(stderr,"receive timeout %d\n",(((now.tv_sec-start.tv_sec)*100)+(now.tv_usec-start.tv_usec)/10000));
559        uint8_t cmd=NFCMD_INPUT_MISSING;
560        if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return  0; }   
561        if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }     // block, so net driver can request input
562        gettimeofday(&start,NULL);
563        total_retry++;
564        if (total_retry==10)    // 2 seconds and nothing
565        {
566          abort=wm->new_window(0,yres/2,-1,wm->font()->height()*4,
567                               new info_field(WINDOW_FRAME_LEFT,
568                                              WINDOW_FRAME_TOP,
569                                              0,"Waiting for data...",
570                                              new button(WINDOW_FRAME_LEFT,
571                                                         WINDOW_FRAME_TOP+wm->font()->height()+5,ID_NET_DISCONNECT,
572                                                         "Disconnect slackers",NULL)),"Error");   
573          wm->flush_screen();
574        }
575      }
576      if (abort)
577      {
578        if (wm->event_waiting())
579        {
580          event ev;
581          do
582          {
583            wm->get_event(ev);
584            if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
585            kill_slackers();
586            else if (ev.type!=EV_MOUSE_MOVE)  // no need to save mouse move events (likely to be a lot)
587            {
588              event *e=new event;
589              *e=ev;
590              input.add_front(e);
591            }
592          } while (wm->event_waiting());
593
594          wm->flush_screen();
595        }
596      }
597    }
598
599    if (abort)
600    {
601      wm->close_window(abort);
602      while (input.first())               // push all the key events
603      {
604        event *ev=(event *)input.first();
605        input.unlink((linked_node *)ev);
606        wm->push_event(ev);
607      }
608    }
609  }
610
611//  while (!aquire_mem_lock()) service_net_request();
612
613  memcpy(base->last_packet.data,base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size());
614 
615  int size=base->packet.packet_size();
616  memcpy(buf,base->packet.packet_data(),size);
617
618  base->packet.packet_reset();
619  base->mem_lock=0;
620
621  return size;
622}
623
624
625void server_check()       // read a byte from the net driver, causing the OS to give up the rest of our time-slice
626{
627  if (net_installed)
628  {
629    if (base->input_state==INPUT_NET_DEAD)
630    { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
631    else
632    {
633      uint8_t cmd=NFCMD_BLOCK;
634      if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
635      if (base->input_state==INPUT_NET_DEAD)
636      { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
637      else
638      {
639        if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; } 
640        if (base->input_state==INPUT_NET_DEAD)
641        { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
642        else
643          if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }
644      }
645    }
646  }
647}
648
649int become_server()
650{
651  if (net_installed)
652  {
653    uint8_t cmd=NFCMD_BECOME_SERVER;
654    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return 0; }
655    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }     
656   
657    return 1;
658  }
659  return 0;
660}
661
662void read_new_views() { ; }
663
664
Note: See TracBrowser for help on using the repository browser.