source: abuse/trunk/src/net/netdrv.cpp @ 555

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

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

File size: 15.2 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 <stdio.h>
16#include <stdlib.h>
17#include <fcntl.h>
18#include <unistd.h>
19#include <sys/ioctl.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <sys/time.h>
23#include <string.h>
24#include <signal.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <sys/types.h>
28#include <sys/ipc.h>
29#include <sys/shm.h>
30#include <bstring.h>
31#include <netdb.h>
32
33#include "fileman.h"
34#include "netdrv.h"
35#include "gserver.h"
36#include "gclient.h"
37#include "undrv.h"
38#include "tcpip.h"
39
40#define real2shm(type,ptr) (ptr==NULL ? NULL : ((type *)((uint8_t *)(ptr)-(uint8_t *)base)))
41#define shm2real(type,ptr) (ptr==NULL ? NULL : ((type *)((intptr_t)(ptr)+(intptr_t)(base))))
42
43net_driver *driver=NULL;
44
45#ifdef __sgi
46#define next_process() sginap(0)
47#else
48#define next_process() usleep(10)
49#endif
50
51
52#ifdef __sgi
53void die(...)
54#else
55void die(int why)
56#endif
57{
58  fprintf(stderr,"dieing\n");
59  if (driver) { delete driver; driver=NULL; }
60  exit(0);
61}
62
63
64void mdie(char *reason)
65{
66  fprintf(stderr,"net driver : %s\n",reason);
67  if (driver) { driver->cleanup(); }
68  exit(0);
69}
70
71void comm_failed()  // general communication failure with engine
72{
73  fprintf(stderr,"net driver : Error occurred while trying to communicate with the engine\n");
74  if (driver) { delete driver; driver=NULL; }
75  exit(0);
76}
77
78int net_driver::add_joiner(int client_id, char *name)
79{
80  join_array[client_id].next=base->join_list;
81  base->join_list=real2shm(join_struct,&join_array[client_id]);
82  join_array[client_id].client_id=client_id;
83  strcpy(join_array[client_id].name,name);
84}
85
86
87void net_driver::cleanup()
88{
89  base->input_state=INPUT_NET_DEAD;
90  fprintf(stderr,"net driver : cleaning up\n");
91  if (shm_seg_id!=-1)
92    shmctl(shm_seg_id,IPC_RMID,NULL);
93  if (shm_addr!=(void *)-1)
94  {
95    shmdt((char *)shm_addr);
96    shm_addr=(void *)-1;
97  }
98
99  undrv_cleanup();
100  unlink(DLOCK_NAME);
101}
102
103net_driver::~net_driver()
104{
105  cleanup();
106}
107
108int net_driver::setup_shm()
109{
110  shm_addr=(void *)-1;  // shmat returns -1 on failure
111  shm_seg_id=-1;
112
113  driver=this;
114  int catch_sigs[]={ SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGABRT,
115            SIGIOT,SIGFPE,SIGKILL,SIGUSR1,SIGSEGV,
116            SIGUSR2,SIGPIPE,SIGTERM,SIGCHLD,
117            SIGCONT,SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU,-1};
118
119  int i;
120  for (i=0; catch_sigs[i]!=-1; i++)     // catch all signals in case we get
121    signal(catch_sigs[i],die);            // interrupted before we remove shmid
122
123
124  int alloc_size=sizeof(join_struct)*MAX_JOINERS+sizeof(base_memory_struct);
125
126  shm_seg_id=shmget(IPC_PRIVATE,alloc_size,IPC_CREAT | 0777);
127
128
129  if (shm_seg_id==-1) mdie("Unable to allocate shared memory");
130
131
132  shm_addr=shmat(shm_seg_id,NULL,0);  // attach as read/write
133  if (shm_addr==(void *)-1)
134    mdie("could not attach shm seg");
135
136  base=(base_memory_struct *)shm_addr;
137
138  base->join_list=real2shm(join_struct,NULL);
139  base->mem_lock=0;
140  base->calc_crcs=0;
141  base->get_lsf=0;
142  base->wait_reload=0;
143  base->need_reload=0;
144  base->input_state=INPUT_COLLECTING;
145  base->current_tick=0;
146  base->packet.packet_reset();
147  join_array=(join_struct *) (base+1);
148
149  // see if we can attach this memory with the abuse engine
150  if (out->write(&shm_seg_id,sizeof(shm_seg_id))!=sizeof(shm_seg_id))
151    comm_failed();
152
153  // wait for engine to ack it has attached
154  uint8_t ack=0;
155  if (in->read(&ack,1)!=1 || ack!=1)
156    comm_failed();
157
158
159  if (shmctl(shm_seg_id,IPC_RMID,NULL))  // remove the shm id
160    mdie("could not remove shm id");
161
162  shm_seg_id=-1;                      // mark id as not allocated
163  return 1;
164
165}
166
167int net_driver::connect_to_engine(int argc, char **argv)
168{
169  if (mkfifo(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
170  { perror("Net driver : unable to make fifo in /tmp");
171    return 0;
172  }
173  chmod(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO);   // just to be sure umask doesn't screw us
174
175  if (mkfifo(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
176  { perror("Net driver : unable to make fifo in /tmp");
177    return 0;
178  }
179  chmod(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
180
181  int driver_out_fd=open(DOUT_NAME,O_RDWR);  // open the pipe
182  if (driver_out_fd<0)
183  { perror(DOUT_NAME);
184    exit(1);
185  }
186
187  int driver_in_fd=open(DIN_NAME,O_RDWR);
188  if (driver_in_fd<0)
189  {
190    close(driver_out_fd);
191    perror(DIN_NAME);
192    exit(1);
193  }
194
195  in=new unix_fd(driver_in_fd);
196  in->read_selectable();
197  out=new unix_fd(driver_out_fd);
198
199  if (in->read(&reg,sizeof(reg))!=sizeof(reg))
200    mdie("unable to registration from engine");
201}
202
203net_driver::net_driver(int argc, char **argv, int comm_port, int game_port, net_protocol *proto) :
204  comm_port(comm_port), game_port(game_port), proto(proto)
205{
206  debug=0;
207  lsf_wait_list=NULL;
208  crc_wait_list=NULL;
209
210  base=NULL;
211  in=out=NULL;
212  game_face=new game_handler();
213
214  connect_to_engine(argc,argv);
215  setup_shm();
216  int i;
217  for (i=1; i<argc; i++) if (!strcmp(argv[i],"-debug")) debug=1;
218}
219
220int net_driver::become_server()
221{
222  delete game_face;
223  game_face=new game_server;
224  return 1;
225}
226
227int net_driver::check_commands()
228{
229  int ret=0;
230  if (in->ready_to_read())       // commands from engine?
231  {
232    uint8_t cmd;
233    if (in->read(&cmd,1)!=1) return 0;
234
235    if (debug)
236    {
237      if (cmd<=EGCMD_DIE)
238      {
239    char *cmds[]={ "open","close","read","write","seek","size","tell","setfs","crc_calced","process_lsf","request_lfs",
240             "equest_entry","become_server","block","reload_start","reload_end","send_input","input_missing",
241              "kill_slackers","die"};
242    fprintf(stderr,"engine cmd : %s\n",cmds[cmd]);
243      }
244    }
245
246    switch (cmd)
247    {
248      case EGCMD_DIE :
249      {
250    cmd=game_face->quit();
251    if (!out->write(&cmd,1)) { mdie("could not write block ack1"); }  // send something to unblock engine
252    mdie("received die command");
253      } break;
254
255      case NFCMD_RELOAD_START :
256      {
257    cmd=game_face->start_reload();
258    if (!out->write(&cmd,1)) { mdie("could not write start reload ack"); }  // send something to unblock engine
259      } break;
260
261      case NFCMD_RELOAD_END :
262      {
263    cmd=game_face->end_reload();
264    if (!out->write(&cmd,1)) { mdie("could not write end reload ack"); }  // send something to unblock engine
265      } break;
266
267      case NFCMD_BLOCK :
268      {
269    if (!out->write(&cmd,1)) { mdie("could not write block ack1"); }  // send something to unblock engine
270    if (!in->read(&cmd,1)) { mdie("could not read block ack1"); }  // send something to block ourself
271      } break;
272
273      case NFCMD_INPUT_MISSING :    // try to fetch the input via a loss-less net protocol
274      {
275    game_face->input_missing();
276    if (out->write(&cmd,1)!=1) { mdie("could not write block ack1"); }  // send something to unblock engine
277      } break;
278
279      case NFCMD_KILL_SLACKERS :
280      {
281    if (!game_face->kill_slackers())
282    {
283      delete game_face;
284      game_face=new game_handler();
285    }
286    if (out->write(&cmd,1)!=1) { mdie("could not write block ack1"); }  // send something to unblock engine
287      } break;
288      case NFCMD_SEND_INPUT :
289      {
290    game_face->add_engine_input();
291    if (out->write(&cmd,1)!=1) { mdie("could not write send ack1"); }  // send something to unblock engine
292    if (in->read(&cmd,1)!=1) { mdie("could not read send ack2"); }    // read something to block ourselves for engine
293      } break;
294
295      case NFCMD_REQUEST_ENTRY :
296      {
297    uint8_t len;
298    char name[256];
299    if (in->read(&len,1)!=1) { mdie("could not read server name length"); }
300    if (in->read(name,len)!=len) { mdie("could not read server name"); }
301    uint16_t success=join_server(name);
302    if (out->write(&success,2)!=2) mdie("cound not send lsf read failure");
303      } break;
304
305      case NFCMD_BECOME_SERVER :
306      {
307    cmd=become_server();
308    if (out->write(&cmd,1)!=1) mdie("cound not send ok");
309      } break;
310
311      case NFCMD_REQUEST_LSF :
312      {
313    uint8_t len;
314    char name[256];
315    if (in->read(&len,1)!=1) { mdie("could not read lsf name length"); }
316    if (in->read(name,len)!=len) { mdie("could not read lsf name"); }
317    if (!get_lsf(name))
318    {
319      len=0;
320      if (out->write(&len,1)!=1) mdie("cound not send lsf read failure");
321    } else
322    {
323      len=strlen(name)+1;
324      if (out->write(&len,1)!=1) mdie("cound not send lsf name len");
325      if (out->write(name,len)!=len) mdie("cound not send lsf name");
326    }
327      } break;
328
329      case NFCMD_PROCESS_LSF :
330      {
331    uint8_t len,name[256];
332    if (in->read(&len,1)!=1) { mdie("could not read lsf name length"); }
333    if (in->read(name,len)!=len) { mdie("could not read lsf name"); }
334
335    while (lsf_wait_list)
336    {
337      lsf_waiter *c=lsf_wait_list;
338      lsf_wait_list=lsf_wait_list->next;
339      uint8_t status=1;
340      c->sock->write(&len,1);
341      c->sock->write(name,len);
342      delete c;
343    }
344      } break;
345
346      case NFCMD_CRCS_CALCED :
347      {
348    while (crc_wait_list)
349    {
350      crc_waiter *c=crc_wait_list;
351      crc_wait_list=crc_wait_list->next;
352      uint8_t status=1;
353      c->sock->write(&status,1);
354      delete c;
355    }
356      } break;
357
358      case NFCMD_SET_FS :
359      {
360    uint8_t size;
361    char sn[256];
362    if (in->read(&size,1)!=1) mdie("could not read filename length");
363    if (in->read(sn,size)!=size) mdie("could not read server name");
364    fman->set_default_fs_name(sn);
365
366    size=fetch_crcs(sn);  // return success
367    if (out->write(&size,1)!=1) mdie("could not send ok to engine");
368      } break;
369
370      case NFCMD_OPEN :
371      {
372    uint8_t size[2];
373    char filename[300],mode[20],*fn;
374    fn=filename;
375    if (in->read(size,2)!=2  ||
376        in->read(filename,size[0])!=size[0] ||
377        in->read(mode,size[1])!=size[1])
378      mdie("incomplete open command from engine");
379
380    int fd=fman->rf_open_file(fn,mode);
381    if (fd==-2)
382    {
383      uint8_t st[2];
384      st[0]=NF_OPEN_LOCAL_FILE;
385      st[1]=strlen(fn)+1;
386      if (out->write(st,2)!=2) comm_failed();
387      if (out->write(fn,st[1])!=st[1]) comm_failed();
388    } else if (fd==-1)
389    {
390      uint8_t st=NF_OPEN_FAILED;
391      if (out->write(&st,1)!=1) comm_failed();
392    } else
393    {
394      uint8_t st=NF_OPEN_REMOTE_FILE;
395      if (out->write(&st,1)!=1) comm_failed();
396      if (out->write(&fd,sizeof(fd))!=sizeof(fd)) comm_failed();
397    }
398      } break;
399      case NFCMD_CLOSE :
400      case NFCMD_SIZE :
401      case NFCMD_TELL :
402      case NFCMD_SEEK :
403      case NFCMD_READ :
404      {
405    int fd;
406    if (in->read(&fd,sizeof(fd))!=sizeof(fd)) comm_failed();
407
408    switch (cmd)
409    {
410      case NFCMD_CLOSE :
411      {
412        fman->rf_close(fd);
413        uint8_t st=1;
414        if (out->write(&st,1)!=1) comm_failed();
415      } break;
416      case NFCMD_SIZE  :
417      {
418        int32_t x=fman->rf_file_size(fd);
419        if (out->write(&x,sizeof(x))!=sizeof(x)) comm_failed();
420      } break;
421      case NFCMD_TELL :
422      {
423        int32_t offset=fman->rf_tell(fd);
424        if (out->write(&offset,sizeof(offset))!=sizeof(offset)) comm_failed();
425      } break;
426      case NFCMD_SEEK :
427      {
428        int32_t offset;
429        if (in->read(&offset,sizeof(offset))!=sizeof(offset)) comm_failed();
430        offset=fman->rf_seek(fd,offset);
431        if (out->write(&offset,sizeof(offset))!=sizeof(offset)) comm_failed();
432      } break;
433      case NFCMD_READ :
434      {
435        int32_t size;
436        if (in->read(&size,sizeof(size))!=sizeof(size)) comm_failed();
437        fman->rf_read(fd,out,size);
438      } break;
439    }
440      } break;
441      default :
442      { fprintf(stderr,"net driver : unknown net command %d\n",cmd); die(0); }
443    }
444    ret=1;
445  }
446
447  ret|=game_face->process_net();
448  return ret;
449}
450
451
452int net_driver::join_server(char *server_name)   // ask remote server for entry into game
453{
454  char sn_start[256];
455  strcpy(sn_start,server_name);
456
457  net_socket *sock=connect_to_server(server_name, DEFAULT_COMM_PORT, 0);
458  if (!sock)
459  {
460    fprintf(stderr,"unable to connect\n");
461    return 0;
462  }
463
464  uint8_t ctype=CLIENT_ABUSE;
465  uint16_t port=lstl(game_port),cnum;
466
467  uint8_t reg;
468  if (sock->write(&ctype,1)!=1 ||   // send server out game port
469      sock->read(&reg,1)!=1)        // is remote engine registered?
470  { delete sock; return 0; }
471
472
473  // maker sure the two games are both registered or unregistered or sync problems
474  // will occur.
475
476  if (!reg)
477  {
478    fprintf(stderr,
479        "This server is not running the registered version of abuse, and\n"
480        "you are (thanks!).  So that there are no conflict between the two games\n"
481        "please start with the -share option when connecting to this server\n"
482        "example : abuse -net somewhere.someplace.net -share\n");
483    delete sock;
484    return 0;
485  }
486
487  char uname[256];
488  if (getlogin())
489    strcpy(uname,getlogin());
490  else strcpy(uname,"unknown");
491  uint8_t len=strlen(uname)+1;
492
493  if (sock->write(&len,1)!=1 ||
494      sock->write(uname,len)!=len ||
495      sock->write(&port,2)!=2  ||            // send server out game port
496      sock->read(&port,2)!=2   ||            // read server's game port
497      sock->read(&cnum,2)!=2   || cnum==0    // read player number (cannot be 0 because 0 is server)
498      )
499  { delete sock; return 0; }
500
501  port=lstl(port);
502  cnum=lstl(cnum);
503
504  server_name=sn_start;
505  net_socket *data_sock=connect_to_server(server_name,port,1,net_socket::SOCKET_FAST);
506  if (!data_sock)  { delete sock; return 0; }
507
508  delete game_face;
509  game_face=new game_client(sn_start,sock,data_sock);
510  return cnum;
511}
512
513
514net_socket *net_driver::connect_to_server(char *&name, int port, int force_port,
515                      net_socket::socket_type sock_type)
516{
517  char *oname=name;
518  net_address *addr=proto->get_node_address(name, port, force_port);
519  if (!addr)
520  {
521    if (debug) fprintf(stderr,"No IP address for name %s\n",oname);
522    return NULL;
523  }
524
525  if (debug)
526    fprintf(stderr,"connecting to server %s\n",oname);
527  net_socket *sock=proto->connect_to_server(addr,sock_type);
528  delete addr;
529  return sock;
530}
531
532
533int net_driver::get_lsf(char *name)  // contact remot host and ask for lisp startup file filename
534{
535  char *name_start=name;
536  net_socket *sock=connect_to_server(name);
537  if (!sock) return 0;
538
539  uint8_t ctype=CLIENT_LSF_WAITER;
540  uint8_t len;
541
542  if (sock->write(&ctype,1)!=1 ||
543      sock->read(&len,1)!=1 || len==0 ||
544      sock->read(name_start,len)!=len)
545  {
546    delete sock;
547    return 0;
548  }
549
550  delete sock;
551  return 1;
552}
553
554
555
556int net_driver::fetch_crcs(char *server)
557{
558  net_socket *sock=connect_to_server(server);
559  if (!sock) return 0;
560  uint8_t cmd=CLIENT_CRC_WAITER;
561  if (sock->write(&cmd,1)!=1 ||
562      sock->read(&cmd,1)!=1)
563  { delete sock; return 0; }
564  delete sock;
565  return cmd;
566}
567
568
569int net_driver::add_client(int type, net_socket *sock, net_address *from)
570{
571  switch (type)
572  {
573    case CLIENT_CRC_WAITER :
574    {
575      if (debug)
576        fprintf(stderr,"add crc waiter\n");
577
578      crc_wait_list=new crc_waiter(sock,crc_wait_list);
579      base->calc_crcs=1;
580      return 1;
581    } break;
582    case CLIENT_LSF_WAITER :
583    {
584      if (debug)
585        fprintf(stderr,"add lsf waiter\n");
586      lsf_wait_list=new lsf_waiter(sock,lsf_wait_list);
587      base->get_lsf=1;
588      return 1;
589    } break;
590    default :
591    {
592      int ret=game_face->add_client(type,sock,from);
593      if (!ret && debug)
594        fprintf(stderr,"unknown client type %d\n",type);
595      return ret;
596    }
597
598  }
599  return 0;
600}
Note: See TracBrowser for help on using the repository browser.