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

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