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

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

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

File size: 11.7 KB
RevLine 
[56]1/*
2 *  Abuse - dark 2D side-scrolling platform game
3 *  Copyright (c) 1995 Crack dot Com
[494]4 *  Copyright (c) 2005-2011 Sam Hocevar <sam@hocevar.net>
[56]5 *
6 *  This software was released into the Public Domain. As with most public
[555]7 *  domain software, no warranty is made or implied by Crack dot Com, by
8 *  Jonathan Clark, or by Sam Hocevar.
[56]9 */
[2]10
[555]11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
[2]14
[651]15#if HAVE_NETWORK
16
[2]17#include <stdio.h>
18#include <stdlib.h>
19#include <fcntl.h>
20#include <unistd.h>
21#include <string.h>
22#include <signal.h>
[90]23#include <sys/stat.h>
[2]24
[524]25#include "common.h"
[56]26
[481]27#include "fileman.h"
28#include "netface.h"
29#include "ghandler.h"
30#include "specache.h"
[56]31
[2]32extern net_protocol *prot;
33
34
35file_manager *fman=NULL;
36
37file_manager::file_manager(int argc, char **argv, net_protocol *proto) : proto(proto)
[124]38{
[2]39  default_fs=NULL;
40  no_security=0;
41  nfs_list=NULL;
42
43  int i;
[494]44  for (i=1; i<argc; i++)
[2]45    if (!strcmp(argv[i],"-bastard"))   // this bypasses filename security features
46    {
47      fprintf(stderr,"Warning : Security measures bypassed (-bastard)\n");
48      no_security=1;
49    }
50}
51
52
53
54void file_manager::process_net()
55{
56  nfs_client *nc,*last=NULL;
[494]57  for (nc=nfs_list; nc; )      // check for nfs request
[2]58  {
59
60    int ok=1;
61
62    if (nc->sock->error())
63    {
64      ok=0;
65      //fprintf(stderr,"Killing nfs client, socket went bad\n");
[124]66    }
[2]67    else if (nc->size_to_read && nc->sock->ready_to_write())
68      ok=nc->send_read();
69    else if (nc->sock->ready_to_read())
[125]70      ok=process_nfs_command(nc);    // if we couldn't process the packet, delete the connection
[124]71
[2]72    if (ok)
73    {
74      last=nc;
75      nc=nc->next;
76    } else
77    {
78      if (last) last->next=nc->next;
79      else nfs_list=nc->next;
80      nfs_client *c=nc;
81      nc=nc->next;
82      delete c;
83    }
84  }
85}
86
87
88int file_manager::process_nfs_command(nfs_client *c)
89{
90  char cmd;
91  if (c->sock->read(&cmd,1)!=1) return 0;
92  switch (cmd)
93  {
94    case NFCMD_READ :
95    {
[17]96      int32_t size;
[2]97      if (c->sock->read(&size,sizeof(size))!=sizeof(size)) return 0;
98      size=lltl(size);
99
100      c->size_to_read=size;
101      return c->send_read();
102    } break;
103    case NFCMD_CLOSE :
104    {
105      return 0;
106    } break;
107    case NFCMD_SEEK :
108    {
[17]109      int32_t offset;
[2]110      if (c->sock->read(&offset,sizeof(offset))!=sizeof(offset)) return 0;
111      offset=lltl(offset);
112      offset=lseek(c->file_fd,offset,0);
113      offset=lltl(offset);
114      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
115      return 1;
116    } break;
117    case NFCMD_TELL :
118    {
[17]119      int32_t offset=lseek(c->file_fd,0,SEEK_CUR);
[2]120      offset=lltl(offset);
121      if (c->sock->write(&offset,sizeof(offset))!=sizeof(offset)) return 0;
122      return 1;
123    } break;
[124]124
[2]125    default :
126    { fprintf(stderr,"net driver : bad command from nfs client\n");
127      return 0;
128    }
[124]129  }
[2]130}
131
132int file_manager::nfs_client::send_read()   // return 0 if failure on socket, not failure to read
133{
134  if (file_fd>=0 && sock)
135  {
136    // first make sure the socket isn't 'full'
137    if (sock->ready_to_write())
138    {
[124]139      char buf[READ_PACKET_SIZE];
[2]140      short read_total;
141      short actual;
142
143      do
[124]144      {
145    read_total=size_to_read>(READ_PACKET_SIZE-2) ? (READ_PACKET_SIZE-2) : size_to_read;
[2]146
[124]147    actual=read(file_fd,buf+2,read_total);
[476]148    ushort tmp = lstl(actual);
149    memcpy(buf, &tmp, sizeof(tmp));
[2]150
[124]151    int write_amount=sock->write(buf,actual+2);
152    if (write_amount!=actual+2)
153    {
154      fprintf(stderr,"write failed\n");
155      return 0;
156    }
[2]157
[124]158    size_to_read-=actual;
[2]159
[124]160    if (!sock->ready_to_write())
161    {
162      sock->read_unselectable();
163      sock->write_selectable();
164      return 1;    // not ok to write anymore, try again latter
165    }
[2]166
167      } while (size_to_read && actual==read_total);
168
169      sock->read_selectable();
170      sock->write_unselectable();
171
172      size_to_read=0;
173      return 1;
[124]174    } else
[2]175    {
176      sock->read_unselectable();
177      sock->write_selectable();
178      return 1;
179    }
180  }
181  return 0;
182}
183
184
185void file_manager::secure_filename(char *filename, char *mode)
186{
187  if (!no_security)
[124]188  {
[2]189    if (filename[0]=='/') { filename[0]=0; return ; }
190    int level=0;
191    char *f=filename;
192    while (*f)
193    {
194      if (*f=='/') { f++; level++; }
195      else if (*f=='.' && f[1]=='.')
196      {
[124]197    if (f[3]=='.') while (*f!='.') f++;
198    else
199    {
200      f+=2;
201      level--;
[2]202    }
[124]203      } else f++;
204
205    }
[2]206    if (level<0)
207      filename[0]=0;
208  }
209}
210
211
212
213
[124]214file_manager::nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) :
[2]215  sock(sock),file_fd(file_fd),next(next),size_to_read(0)
[124]216{
[2]217  sock->read_selectable();
[124]218}
[2]219
220
[124]221file_manager::nfs_client::~nfs_client()
222{
[2]223  delete sock;
224  if (file_fd>=0)
225    close(file_fd);
226}
227
228
229void file_manager::add_nfs_client(net_socket *sock)
230{
[17]231  uint8_t size[2];
[2]232  char filename[300],mode[20],*mp;
233  if (sock->read(size,2)!=2) { delete sock; return ; }
234  if (sock->read(filename,size[0])!=size[0]) { delete sock; return ; }
235  if (sock->read(mode,size[1])!=size[1]) { delete sock; return ; }
236
[124]237
[2]238  secure_filename(filename,mode);  // make sure this filename isn't a security risk
239  if (filename[0]==0) { fprintf(stderr,"(denied)\n"); delete sock; return ; }
240
241  mp=mode;
242  int flags=0;
243
244  while (*mp)
245  {
246    if (*mp=='w') flags|=O_CREAT|O_RDWR;
247    else if (*mp=='r') flags|=O_RDONLY;
248    mp++;
249  }
[124]250
[2]251  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
252
[124]253  FILE *fp=fopen("open.log","ab");
[2]254  fprintf(fp,"open file %s, fd=%d\n",filename,f);
255  fclose(fp);
[124]256
257  if (f<0)
[2]258    f=-1;  // make sure this is -1
259
260
[17]261  int32_t ret=lltl(f);
[2]262  if (sock->write(&ret,sizeof(ret))!=sizeof(ret)) { delete sock; return ; }
263
264  if (f<0)    // no file, sorry
265    delete sock;
266  else
267  {
[17]268    int32_t cur_pos=lseek(f,0,SEEK_CUR);
269    int32_t size=lseek(f,0,SEEK_END);
[2]270    lseek(f,cur_pos,SEEK_SET);
271    size=lltl(size);
272    if (sock->write(&size,sizeof(size))!=sizeof(size)) {  close(f); delete sock; sock=NULL; return ; }
273
274    nfs_list=new nfs_client(sock,f,nfs_list);
275    nfs_list->size=size;
276  }
277}
278
279
280
[124]281void file_manager::remote_file::r_close(char const *reason)
282{
[2]283//  if (reason) fprintf(stderr,"remote_file : %s\n",reason);
284
285  if (sock)
286  {
287    delete sock;
288    sock=NULL;
289  }
290
291}
292
[39]293file_manager::remote_file::remote_file(net_socket *sock, char const *filename, char const *mode, remote_file *Next) : sock(sock)
[2]294{
295  next=Next;
296  open_local=0;
297
[494]298  uint8_t sizes[3]={ CLIENT_NFS,strlen(filename)+1,strlen(mode)+1};
[2]299  if (sock->write(sizes,3)!=3) { r_close("could not send open info"); return ; }
300  if (sock->write(filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; }
301  if (sock->write(mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; }
302
[17]303  int32_t remote_file_fd;
[124]304  if (sock->read(&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd))
305  { r_close("could not read remote fd"); return ; }
[2]306  remote_file_fd=lltl(remote_file_fd);
307  if (remote_file_fd<0) { r_close("remote fd is bad"); return ; }
308
[124]309  if (sock->read(&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; }
[2]310
311  size=lltl(size);
312}
313
314int file_manager::remote_file::unbuffered_read(void *buffer, size_t count)
315{
316  if (sock && count)
317  {
[17]318    uint8_t cmd=NFCMD_READ;
[2]319    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; }
320
[17]321    int32_t rsize=lltl(count);
[2]322    if (sock->write(&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; }
323
[17]324    int32_t total_read=0;
[2]325    char buf[READ_PACKET_SIZE];
326
327    ushort packet_size;
328    do
329    {
[124]330      if (sock->read(&packet_size,sizeof(packet_size))!=sizeof(packet_size))
[2]331      {
[124]332    fprintf(stderr,"could not read packet size\n");
333    return 0;
[2]334      }
335
336      packet_size=lstl(packet_size);
337
[124]338      ushort size_read=sock->read(buf,packet_size);
[2]339
[124]340      if (size_read!=packet_size)
341      {
342    if (sock->read(buf+2+size_read,packet_size-size_read)!=packet_size-size_read)
343    {
344      fprintf(stderr,"incomplete packet\n");
345      return 0;
346    }
[2]347      }
348
349      memcpy(buffer,buf,packet_size);
350      buffer=(void *)(((char *)buffer)+packet_size);
351
352      total_read+=packet_size;
353      count-=packet_size;
[124]354    } while (packet_size==READ_PACKET_SIZE-2 && count);
[2]355    return total_read;
356  }
357  return 0;
358}
359
[17]360int32_t file_manager::remote_file::unbuffered_tell()   // ask server where the offset of the file pointer is
[2]361{
362  if (sock)
363  {
[17]364    uint8_t cmd=NFCMD_TELL;
[2]365    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; }
366
[17]367    int32_t offset;
[124]368    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; }
[2]369    return lltl(offset);
[124]370  }
[2]371  return 0;
372}
373
[17]374int32_t file_manager::remote_file::unbuffered_seek(int32_t offset)  // tell server to seek to a spot in a file
[2]375{
376  if (sock)
377  {
[17]378    uint8_t cmd=NFCMD_SEEK;
[2]379    if (sock->write(&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; }
380
[17]381    int32_t off=lltl(offset);
[2]382    if (sock->write(&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; }
383
[124]384    if (sock->read(&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; }
[2]385    return lltl(offset);
[124]386  }
[2]387  return 0;
388}
389
390
391file_manager::remote_file::~remote_file()
392{ r_close(NULL); }
393
[39]394int file_manager::rf_open_file(char const *&filename, char const *mode)
[2]395{
396  net_address *fs_server_addr=NULL;
397
398  if (filename[0]=='/' && filename[1]=='/')   // passive server file reference?
399  {
400    filename+=2;
401
402    fs_server_addr=prot->get_node_address(filename,DEFAULT_COMM_PORT,0);
403    if (!fs_server_addr)
404    {
405      printf("couldn not get address for %s\n",filename);
406      return -1;
407    }
408  } else if (default_fs)
409    fs_server_addr=default_fs->copy();
[124]410
[2]411  if (fs_server_addr)
412  {
413    net_socket *sock=proto->connect_to_server(fs_server_addr,net_socket::SOCKET_SECURE);
414    delete fs_server_addr;
415
416    if (!sock)
[124]417    {
[2]418      fprintf(stderr,"unable to connect\n");
419      return -1;
420    }
421
422    remote_file *rf=new remote_file(sock,filename,mode,remote_list);
423    if (rf->open_failure())
424    {
425      delete rf;
426      return -1;
427    }
[124]428    else
[2]429    {
430      remote_list=rf;
431      return rf->sock->get_fd();
[124]432    }
[2]433  }
434
435
436// FIXME: AK - Should we keep this?
437//  secure_filename(filename,mode);
438  if (filename[0]==0) return -1;
439
440  int flags=0;
441  while (*mode)
442  {
443    if (*mode=='w') flags|=O_CREAT|O_RDWR;
444    else if (*mode=='r') flags|=O_RDONLY;
445    mode++;
446  }
447
448  char tmp_name[200];
449  if (get_filename_prefix() && filename[0] != '/')
450    sprintf(tmp_name,"%s%s",get_filename_prefix(),filename);
451  else strcpy(tmp_name,filename);
452
453  int f=open(tmp_name,flags,S_IRWXU | S_IRWXG | S_IRWXO);
454  if (f>=0)
455  { close(f);
456    return -2;
457  }
[124]458
[2]459  return -1;
460}
461
462
463file_manager::remote_file *file_manager::find_rf(int fd)
464{
465  remote_file *r=remote_list;
[494]466  for (; r && r->sock->get_fd()!=fd; r=r->next)
[2]467  {
468    if (r->sock->get_fd()==-1)
469    {
470      fprintf(stderr,"bad sock\n");
471    }
472  }
473  if (!r) { fprintf(stderr,"Bad fd for remote file %d\n",fd); }
474  return r;
475}
476
477
[17]478int32_t file_manager::rf_tell(int fd)
[2]479{
480  remote_file *rf=find_rf(fd);
481  if (rf) return rf->unbuffered_tell();
482  else return 0;
483}
484
[17]485int32_t file_manager::rf_seek(int fd, int32_t offset)
[2]486{
487  remote_file *rf=find_rf(fd);
488  if (rf) return rf->unbuffered_seek(offset);
489  else return 0;
490}
491
492int file_manager::rf_read(int fd, void *buffer, size_t count)
493{
494  remote_file *rf=find_rf(fd);
495  if (rf) return rf->unbuffered_read(buffer,count);
496  else return 0;
497}
498
499int file_manager::rf_close(int fd)
500{
501  remote_file *rf=remote_list,*last=NULL;
502  while (rf && rf->sock->get_fd()!=fd) rf=rf->next;
503  if (rf)
504  {
505    if (last) last->next=rf->next;
506    else remote_list=rf->next;
507    delete rf;
508    return 1;
[124]509  } else
[2]510  {
[124]511    fprintf(stderr,"Bad fd for remote file %d\n",fd);
[2]512    return 0;
[124]513  }
[2]514}
515
[17]516int32_t file_manager::rf_file_size(int fd)
[2]517{
518  remote_file *rf=find_rf(fd);
519  if (rf) return rf->file_size();
520  else return 0;
521}
[651]522
523#endif // HAVE_NETWORK
524
Note: See TracBrowser for help on using the repository browser.