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

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