source: abuse/tags/pd/abuse/src/net/unix/netdrv.c

Last change on this file was 49, checked in by Sam Hocevar, 11 years ago
  • Imported original public domain release, for future reference.
  • Property svn:keywords set to Id
File size: 14.8 KB
Line 
1#include "fileman.hpp"
2#include "netdrv.hpp"
3#include "gserver.hpp"
4#include "gclient.hpp"
5#include "undrv.hpp"
6#include "tcpip.hpp"
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <fcntl.h>
11#include <unistd.h>
12#include <sys/ioctl.h>
13#include <sys/stat.h>
14#include <sys/types.h>
15#include <sys/time.h>
16#include <string.h>
17#include <signal.h>
18#include <sys/socket.h>
19#include <netinet/in.h>
20#include <sys/types.h>
21#include <sys/ipc.h>
22#include <sys/shm.h>
23#include <bstring.h>
24#include <netdb.h>
25
26#define real2shm(type,ptr) (ptr==NULL ? NULL : ((type *)((char *)(ptr)-(char *)base)))
27#define shm2real(type,ptr) (ptr==NULL ? NULL : ((type *)((long)(ptr)+(long)(base))))
28
29net_driver *driver=NULL;
30
31#ifdef __sgi
32#define next_process() sginap(0)
33#else
34#define next_process() usleep(10)
35#endif
36
37
38#ifdef __sgi
39void die(...)
40#else
41void die(int why)
42#endif
43{
44  fprintf(stderr,"dieing\n");
45  if (driver) { delete driver; driver=NULL; }
46  exit(0);
47}
48
49
50void mdie(char *reason)
51{
52  fprintf(stderr,"net driver : %s\n",reason);
53  if (driver) { driver->cleanup(); }
54  exit(0);
55}
56
57void comm_failed()  // general communication failure with engine
58{
59  fprintf(stderr,"net driver : Error occured while trying to communicate with the engine\n");
60  if (driver) { delete driver; driver=NULL; }
61  exit(0);
62}
63
64int net_driver::add_joiner(int client_id, char *name)
65{
66  join_array[client_id].next=base->join_list;
67  base->join_list=real2shm(join_struct,&join_array[client_id]);
68  join_array[client_id].client_id=client_id;
69  strcpy(join_array[client_id].name,name);
70}
71
72
73void net_driver::cleanup()
74{
75  base->input_state=INPUT_NET_DEAD;
76  fprintf(stderr,"net driver : cleaning up\n");
77  if (shm_seg_id!=-1)
78    shmctl(shm_seg_id,IPC_RMID,NULL);
79  if (shm_addr!=(void *)-1)
80  {
81    shmdt((char *)shm_addr);
82    shm_addr=(void *)-1;
83  }
84
85  undrv_cleanup();
86  unlink(DLOCK_NAME);
87}
88
89net_driver::~net_driver()
90{
91  cleanup();
92}
93
94int net_driver::setup_shm()
95{
96  shm_addr=(void *)-1;  // shmat returns -1 on failure
97  shm_seg_id=-1;
98
99  driver=this;
100  int catch_sigs[]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGABRT,
101                    SIGIOT,SIGFPE,SIGKILL,SIGUSR1,SIGSEGV,
102                    SIGUSR2,SIGPIPE,SIGTERM,SIGCHLD,
103                    SIGCONT,SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU,-1};
104
105  int i;
106  for (i=0;catch_sigs[i]!=-1;i++)     // catch all signals in case we get
107    signal(catch_sigs[i],die);            // interrupted before we remove shmid
108
109
110  int alloc_size=sizeof(join_struct)*MAX_JOINERS+sizeof(base_memory_struct);
111
112  shm_seg_id=shmget(IPC_PRIVATE,alloc_size,IPC_CREAT | 0777);
113
114
115  if (shm_seg_id==-1) mdie("Unable to allocate shared memory");
116
117
118  shm_addr=shmat(shm_seg_id,NULL,0);  // attach as read/write
119  if (shm_addr==(void *)-1)
120    mdie("could not attach shm seg");
121
122  base=(base_memory_struct *)shm_addr;
123
124  base->join_list=real2shm(join_struct,NULL);
125  base->mem_lock=0;
126  base->calc_crcs=0;
127  base->get_lsf=0;
128  base->wait_reload=0;
129  base->need_reload=0;
130  base->input_state=INPUT_COLLECTING;
131  base->current_tick=0;
132  base->packet.packet_reset();
133  join_array=(join_struct *) (base+1);
134
135  // see if we can attach this memory with the abuse engine
136  if (out->write(&shm_seg_id,sizeof(shm_seg_id))!=sizeof(shm_seg_id))
137    comm_failed();
138
139  // wait for engine to ack it has attached
140  uchar ack=0;
141  if (in->read(&ack,1)!=1 || ack!=1)
142    comm_failed();
143
144 
145  if (shmctl(shm_seg_id,IPC_RMID,NULL))  // remove the shm id
146    mdie("could not remove shm id");
147
148  shm_seg_id=-1;                      // mark id as not allocated
149  return 1;
150
151}
152
153int net_driver::connect_to_engine(int argc, char **argv)
154{
155  if (mkfifo(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
156  { perror("Net driver : unable to make fifo in /tmp");
157    return 0;
158  }
159  chmod(DIN_NAME,S_IRWXU | S_IRWXG | S_IRWXO);   // just to be sure umask doesn't screw us
160
161  if (mkfifo(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO))
162  { perror("Net driver : unable to make fifo in /tmp");
163    return 0;
164  }
165  chmod(DOUT_NAME,S_IRWXU | S_IRWXG | S_IRWXO);
166
167  int driver_out_fd=open(DOUT_NAME,O_RDWR);  // open the pipe
168  if (driver_out_fd<0)
169  { perror(DOUT_NAME);
170    exit(1);
171  }
172
173  int driver_in_fd=open(DIN_NAME,O_RDWR);
174  if (driver_in_fd<0)
175  {
176    close(driver_out_fd);
177    perror(DIN_NAME);
178    exit(1);
179  }
180
181  in=new unix_fd(driver_in_fd);
182  in->read_selectable();
183  out=new unix_fd(driver_out_fd);
184 
185  if (in->read(&reg,sizeof(reg))!=sizeof(reg))
186    mdie("unable to registration from engine");
187}
188
189net_driver::net_driver(int argc, char **argv, int comm_port, int game_port, net_protocol *proto) :
190  comm_port(comm_port), game_port(game_port), proto(proto)
191{
192  debug=0;
193  lsf_wait_list=NULL;
194  crc_wait_list=NULL;
195
196  base=NULL;
197  in=out=NULL;
198  game_face=new game_handler();
199
200  connect_to_engine(argc,argv);
201  setup_shm();
202  int i;
203  for (i=1;i<argc;i++) if (!strcmp(argv[i],"-debug")) debug=1;
204}
205
206int net_driver::become_server()
207{
208  delete game_face;
209  game_face=new game_server;
210  return 1;
211}
212
213int net_driver::check_commands()
214{
215  int ret=0;
216  if (in->ready_to_read())       // commands from engine?
217  {
218    uchar cmd;
219    if (in->read(&cmd,1)!=1) return 0;
220
221    if (debug)
222    {
223      if (cmd<=EGCMD_DIE)
224      {
225        char *cmds[]={"open","close","read","write","seek","size","tell","setfs","crc_calced","process_lsf","request_lfs",
226                     "equest_entry","become_server","block","reload_start","reload_end","send_input","input_missing",
227                      "kill_slackers","die"};
228        fprintf(stderr,"engine cmd : %s\n",cmds[cmd]);
229      }
230    }
231
232    switch (cmd)
233    {
234      case EGCMD_DIE :
235      {
236        cmd=game_face->quit();
237        if (!out->write(&cmd,1)) { mdie("could not write block ack1"); }  // send something to unblock engine
238        mdie("received die command");
239      } break;
240
241      case NFCMD_RELOAD_START :
242      {     
243        cmd=game_face->start_reload();
244        if (!out->write(&cmd,1)) { mdie("could not write start reload ack"); }  // send something to unblock engine     
245      } break;
246
247      case NFCMD_RELOAD_END :
248      {     
249        cmd=game_face->end_reload();
250        if (!out->write(&cmd,1)) { mdie("could not write end reload ack"); }  // send something to unblock engine       
251      } break;
252
253      case NFCMD_BLOCK :
254      {     
255        if (!out->write(&cmd,1)) { mdie("could not write block ack1"); }  // send something to unblock engine
256        if (!in->read(&cmd,1)) { mdie("could not read block ack1"); }  // send something to block ourself
257      } break;
258
259      case NFCMD_INPUT_MISSING :    // try to fetch the input via a loss-less net protocol
260      {
261        game_face->input_missing();
262        if (out->write(&cmd,1)!=1) { mdie("could not write block ack1"); }  // send something to unblock engine
263      } break;
264      case NFCMD_KILL_SLACKERS :
265      {
266        if (!game_face->kill_slackers())
267        {
268          delete game_face;
269          game_face=new game_handler();
270        }
271        if (out->write(&cmd,1)!=1) { mdie("could not write block ack1"); }  // send something to unblock engine
272      } break;
273      case NFCMD_SEND_INPUT :
274      {
275        game_face->add_engine_input();
276        if (out->write(&cmd,1)!=1) { mdie("could not write send ack1"); }  // send something to unblock engine
277        if (in->read(&cmd,1)!=1) { mdie("could not read send ack2"); }  // read something to block ourselves for engine
278      } break;
279
280
281      case NFCMD_REQUEST_ENTRY :
282      {
283        uchar len;
284        char name[256];
285        if (in->read(&len,1)!=1) { mdie("could not read server name length"); }
286        if (in->read(name,len)!=len) { mdie("could not read server name"); }
287        ushort success=join_server(name);
288        if (out->write(&success,2)!=2) mdie("cound not send lsf read failure");     
289      } break;
290      case NFCMD_BECOME_SERVER :
291      {
292        cmd=become_server();   
293        if (out->write(&cmd,1)!=1) mdie("cound not send ok");
294      } break;
295      case NFCMD_REQUEST_LSF :
296      {
297        uchar len;
298        char name[256];
299        if (in->read(&len,1)!=1) { mdie("could not read lsf name length"); }
300        if (in->read(name,len)!=len) { mdie("could not read lsf name"); }
301        if (!get_lsf(name))
302        {
303          len=0;
304          if (out->write(&len,1)!=1) mdie("cound not send lsf read failure");
305        } else
306        {
307          len=strlen(name)+1;
308          if (out->write(&len,1)!=1) mdie("cound not send lsf name len");
309          if (out->write(name,len)!=len) mdie("cound not send lsf name");
310        }     
311      } break;
312
313      case NFCMD_PROCESS_LSF :
314      {
315        uchar len,name[256];
316        if (in->read(&len,1)!=1) { mdie("could not read lsf name length"); }
317        if (in->read(name,len)!=len) { mdie("could not read lsf name"); }
318
319        while (lsf_wait_list)
320        {
321          lsf_waiter *c=lsf_wait_list;
322          lsf_wait_list=lsf_wait_list->next;
323          uchar status=1;
324          c->sock->write(&len,1);
325          c->sock->write(name,len);
326          delete c;
327        }
328      } break;
329
330      case NFCMD_CRCS_CALCED :
331      {
332        while (crc_wait_list)
333        {
334          crc_waiter *c=crc_wait_list;
335          crc_wait_list=crc_wait_list->next;
336          uchar status=1;
337          c->sock->write(&status,1);
338          delete c;
339        }
340      } break;
341
342      case NFCMD_SET_FS :
343      {
344        uchar size;
345        char sn[256];
346        if (in->read(&size,1)!=1) mdie("could not read filename length");
347        if (in->read(sn,size)!=size) mdie("could not read server name");
348        fman->set_default_fs_name(sn);
349
350        size=fetch_crcs(sn);  // return success
351        if (out->write(&size,1)!=1) mdie("could not send ok to engine");
352      } break;   
353
354      case NFCMD_OPEN :
355      {
356        uchar size[2];
357        char filename[300],mode[20],*fn;
358        fn=filename;
359        if (in->read(size,2)!=2  ||
360            in->read(filename,size[0])!=size[0] ||
361            in->read(mode,size[1])!=size[1])
362          mdie("incomplete open command from engine");
363       
364        int fd=fman->rf_open_file(fn,mode);
365        if (fd==-2)
366        {
367          uchar st[2];
368          st[0]=NF_OPEN_LOCAL_FILE;
369          st[1]=strlen(fn)+1;
370          if (out->write(st,2)!=2) comm_failed();
371          if (out->write(fn,st[1])!=st[1]) comm_failed();
372        } else if (fd==-1)
373        {
374          uchar st=NF_OPEN_FAILED;
375          if (out->write(&st,1)!=1) comm_failed();
376        } else
377        {
378          uchar st=NF_OPEN_REMOTE_FILE;
379          if (out->write(&st,1)!=1) comm_failed();     
380          if (out->write(&fd,sizeof(fd))!=sizeof(fd)) comm_failed();   
381        }
382      } break;
383      case NFCMD_CLOSE :
384      case NFCMD_SIZE :
385      case NFCMD_TELL :
386      case NFCMD_SEEK :
387      case NFCMD_READ :
388      {
389        int fd;
390        if (in->read(&fd,sizeof(fd))!=sizeof(fd)) comm_failed();
391
392        switch (cmd)
393        {
394          case NFCMD_CLOSE :
395          {
396            fman->rf_close(fd);
397            uchar st=1;
398            if (out->write(&st,1)!=1) comm_failed();   
399          } break;
400          case NFCMD_SIZE  :
401          {
402            long x=fman->rf_file_size(fd);
403            if (out->write(&x,sizeof(x))!=sizeof(x)) comm_failed();               
404          } break;
405          case NFCMD_TELL :
406          {
407            long offset=fman->rf_tell(fd);
408            if (out->write(&offset,sizeof(offset))!=sizeof(offset)) comm_failed(); 
409          } break;
410          case NFCMD_SEEK :
411          {
412            long offset;
413            if (in->read(&offset,sizeof(offset))!=sizeof(offset)) comm_failed();
414            offset=fman->rf_seek(fd,offset);
415            if (out->write(&offset,sizeof(offset))!=sizeof(offset)) comm_failed(); 
416          } break;
417          case NFCMD_READ :
418          {
419            long size;
420            if (in->read(&size,sizeof(size))!=sizeof(size)) comm_failed();
421            fman->rf_read(fd,out,size);
422          } break;
423        }
424      } break;   
425      default :
426      { fprintf(stderr,"net driver : unknown net command %d\n",cmd); die(0); }
427    }   
428    ret=1;
429  }
430
431  ret|=game_face->process_net();
432  return ret;
433}
434
435
436int net_driver::join_server(char *server_name)   // ask remote server for entry into game
437{
438  char sn_start[256];
439  strcpy(sn_start,server_name);
440
441  net_socket *sock=connect_to_server(server_name,DEFAULT_COMM_PORT,0);
442  if (!sock)
443  {
444    fprintf(stderr,"unable to connect\n");
445    return 0;
446  }
447
448  uchar ctype=CLIENT_ABUSE;
449  ushort port=lstl(game_port),cnum;
450
451  uchar reg;
452  if (sock->write(&ctype,1)!=1 ||   // send server out game port
453      sock->read(&reg,1)!=1)        // is remote engine registered?
454  { delete sock; return 0; }
455
456
457  // maker sure the two games are both registered or unregistered or sync problems
458  // will occur.
459
460  if (reg && !registered())
461  {
462    fprintf(stderr,
463            "Sorry, this server is running REGISTERED ABUSE and you are not.\n"
464            "Ask the server operator to run with -share option or better yet,\n"
465            "Buy ABUSE, registered net games are more fun because you can fly,\n"
466            "turn invisible and have more weapons to duke it out with\n");
467    delete sock;
468    return 0;
469  }
470
471  if (!reg && registered())
472  {
473    fprintf(stderr,
474            "This is 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  uchar 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  uchar ctype=CLIENT_LSF_WAITER;
535  uchar 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  uchar 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.