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

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