source: abuse/branches/lol/src/unixnfc.cpp @ 732

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

build: SDL2 compilation fixes.

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