source: abuse/tags/pd/abuse/src/unixnfc.c @ 49

Last change on this file since 49 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: 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      spec_entry *e=sd.find("Copyright 1995 Crack dot Com, All Rights reserved");
419      if (!e)
420      {
421        the_game->show_help("This level is missing copyright information, cannot load\n");
422        current_level=new level(100,100,"untitled");
423        the_game->need_refresh();
424      }
425      else
426        current_level=new level(&sd,fp,NET_STARTFILE);
427
428      delete fp;     
429      base->current_tick=(current_level->tick_counter()&0xff);
430
431      reload_end();
432    } else if (current_level)
433    {
434     
435      join_struct *join_list=shm2real(join_struct,base->join_list);
436
437      while (!aquire_mem_lock())
438      {
439        next_process();
440        service_net_request();
441      }
442
443      while (join_list)
444      {
445       
446        view *f=player_list;
447        for (;f && f->next;f=f->next);      // find last player, add one for pn
448        int i,st=0;
449        for (i=0;i<total_objects;i++)
450        if (!strcmp(object_names[i],"START"))
451        st=i;
452
453        game_object *o=create(current_start_type,0,0);
454        game_object *start=current_level->get_random_start(320,NULL);
455        if (start) { o->x=start->x; o->y=start->y; }
456        else { o->x=100; o->y=100; }
457
458        f->next=new view(o,NULL,shm2real(join_struct,base->join_list)->client_id);
459        strcpy(f->next->name,shm2real(join_struct,base->join_list)->name);
460        o->set_controller(f->next);
461
462        if (start)
463        current_level->add_object_after(o,start);
464        else
465        current_level->add_object(o);
466
467        view *v=f->next;     
468
469        v->cx1=5;
470        v->cy1=5;
471        v->cx2=319-5;
472        v->cy2=199-5;
473        join_list=shm2real(join_struct,join_list->next);
474      }     
475      base->join_list=NULL;
476      current_level->save(NET_STARTFILE,1);
477      base->mem_lock=0;
478
479
480      jwindow *j=eh->new_window(0,yres/2,-1,-1,new info_field(WINDOW_FRAME_LEFT,
481                                                                   WINDOW_FRAME_TOP,
482                                                                   0,"Clients are re-syncing, please wait...",NULL));
483      eh->flush_screen();
484      if (!reload_start()) return ;
485
486      // wait for all client to reload the level with the new players
487      do 
488      {
489        next_process();
490      } while (!reload_end());
491      eh->close_window(j);
492
493    }     
494  }
495}
496
497int client_number() { return local_client_number; }
498
499
500void send_local_request()
501{
502  if (net_installed)
503  {
504    if (base->join_list)
505      base->packet.write_byte(SCMD_RELOAD);
506
507    uchar cmd=NFCMD_SEND_INPUT;
508
509    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
510    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; }   
511    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
512  } else base->input_state=INPUT_PROCESSING;
513}
514
515void kill_slackers()
516{
517  if (net_installed)
518  {
519    uchar cmd=NFCMD_KILL_SLACKERS;
520    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
521    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; }       
522  }
523}
524
525int get_inputs_from_server(unsigned char *buf)
526{
527  if (net_installed && base->input_state!=INPUT_PROCESSING)      // if input is not here, wait on it
528  {
529    timeval start;
530    gettimeofday(&start,NULL);
531
532    int total_retry=0;
533    jwindow *abort=NULL;
534    linked_list input;
535    while (base->input_state!=INPUT_PROCESSING)
536    {
537      if (!net_installed) 
538      {
539        base->input_state=INPUT_PROCESSING;
540        return 1;
541      }
542      server_check();
543      service_net_request();
544
545      timeval now;                   // if this is taking to long, the packet was probably lost, ask for it to be resent
546      gettimeofday(&now,NULL);
547      if ((((now.tv_sec-start.tv_sec)*100)+(now.tv_usec-start.tv_usec)/10000)>20)
548      {
549//      fprintf(stderr,"receive timeout %d\n",(((now.tv_sec-start.tv_sec)*100)+(now.tv_usec-start.tv_usec)/10000));
550        uchar cmd=NFCMD_INPUT_MISSING;
551        if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return  0; }   
552        if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }     // block, so net driver can request input
553        gettimeofday(&start,NULL);
554        total_retry++;
555        if (total_retry==10)    // 2 seconds and nothing
556        {
557          abort=eh->new_window(0,yres/2,-1,eh->font()->height()*4,
558                               new info_field(WINDOW_FRAME_LEFT,
559                                              WINDOW_FRAME_TOP,
560                                              0,"Waiting for data...",
561                                              new button(WINDOW_FRAME_LEFT,
562                                                         WINDOW_FRAME_TOP+eh->font()->height()+5,ID_NET_DISCONNECT,
563                                                         "Disconnect slackers",NULL)),"Error");   
564          eh->flush_screen();
565        }
566      }
567      if (abort)
568      {
569        if (eh->event_waiting())
570        {
571          event ev;
572          do
573          {
574            eh->get_event(ev);
575            if (ev.type==EV_MESSAGE && ev.message.id==ID_NET_DISCONNECT)
576            kill_slackers();
577            else if (ev.type!=EV_MOUSE_MOVE)  // no need to save mouse move events (likely to be a lot)
578            {
579              event *e=new event;
580              *e=ev;
581              input.add_front(e);
582            }
583          } while (eh->event_waiting());
584
585          eh->flush_screen();
586        }
587      }
588    }
589
590    if (abort)
591    {
592      eh->close_window(abort);
593      while (input.first())               // push all the key events
594      {
595        event *ev=(event *)input.first();
596        input.unlink((linked_node *)ev);
597        eh->push_event(ev);
598      }
599    }
600  }
601
602//  while (!aquire_mem_lock()) service_net_request();
603
604  memcpy(base->last_packet.data,base->packet.data,base->packet.packet_size()+base->packet.packet_prefix_size());
605 
606  int size=base->packet.packet_size();
607  memcpy(buf,base->packet.packet_data(),size);
608
609  base->packet.packet_reset();
610  base->mem_lock=0;
611
612  return size;
613}
614
615
616void server_check()       // read a byte from the net driver, causing the OS to give up the rest of our time-slice
617{
618  if (net_installed)
619  {
620    if (base->input_state==INPUT_NET_DEAD)
621    { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
622    else
623    {
624      uchar cmd=NFCMD_BLOCK;
625      if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }   
626      if (base->input_state==INPUT_NET_DEAD)
627      { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
628      else
629      {
630        if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return ; } 
631        if (base->input_state==INPUT_NET_DEAD)
632        { close(net_out_fd); close(net_in_fd); net_installed=0; kill_net(); }
633        else
634          if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return ; }
635      }
636    }
637  }
638}
639
640int become_server()
641{
642  if (net_installed)
643  {
644    uchar cmd=NFCMD_BECOME_SERVER;
645    if (write(net_out_fd,&cmd,1)!=1) { kill_net(); return 0; }
646    if (read(net_in_fd,&cmd,1)!=1) { kill_net(); return 0; }     
647   
648    return 1;
649  }
650  return 0;
651}
652
653void read_new_views() { ; }
654
655
Note: See TracBrowser for help on using the repository browser.