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

Last change on this file since 682 was 555, checked in by Sam Hocevar, 8 years ago

ps3: make everything compile on the PS3. Of course, nothing links yet
because so much support is missing.

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