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

Last change on this file since 524 was 524, checked in by Sam Hocevar, 11 years ago

core: Get rid of mostly useless headers, move endianness handling to
common.h (and rewrite functions so that they do not need the SDL headers)
and move a few functions out of sdlport's video.cpp. These functions
were in the original video.cpp (which reappears) and shouldn't be part
of the SDL port.

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