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

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

core: fix a few useless casts.

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