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

Last change on this file since 651 was 651, checked in by Sam Hocevar, 9 years ago

build: add a --disable-network compilation flag and get rid of most of
the CELLOS_LV2 ifdefs.

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