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

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

style: remove trailing spaces, fix copyright statements.

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