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

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