source: abuse/trunk/src/net/netfile.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: 12.0 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 */
10
[555]11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
[56]14
[651]15#if HAVE_NETWORK
16
[524]17#include "common.h"
18
[481]19#include "netfile.h"
20#include "../inc/netface.h"
21#include "engine.h"
[2]22
23nfs_client *first_nfs_client=NULL;
24remote_file *remote_file_list=NULL;
25char default_fs_name[256];    // default file server name (set with parm -fs)
26
[124]27nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) :
[2]28  sock(sock),file_fd(file_fd),next(next),size_to_read(0)
[124]29{
[2]30  sock->read_selectable();
[124]31}
[2]32
33
[124]34nfs_client::~nfs_client()
35{
[2]36  delete sock;
37  if (file_fd>=0)
38    close(file_fd);
39}
40
41void secure_filename(char *filename, char *mode)
42{
43  if (!no_security)
[124]44  {
[2]45    if (filename[0]=='/') { filename[0]=0; return ; }
46    int level=0;
47    char *f=filename;
48    while (*f)
49    {
50      if (*f=='/') { f++; level++; }
51      else if (*f=='.' && f[1]=='.')
52      {
[124]53    if (f[3]=='.') while (*f!='.') f++;
54    else
55    {
56      f+=2;
57      level--;
[2]58    }
[124]59      } else f++;
60
61    }
[2]62    if (level<0)
63      filename[0]=0;
64  }
65}
66
67
68int local_address(char *server_name)    // returns 1 if server name is ourself
69{
70  struct hostent *hn=gethostbyname(server_name);    // first check to see if this address is 127.0.0.1
71  if (!hn) return 0;                                // if bad server_name, return false
72  char **ip_address=hn->h_addr_list;
[124]73  while (*ip_address)
[2]74  {
75    char *a=*ip_address;
76    if (a[0]==127 && a[1]==0 && a[2]==0 && a[3]==1)
77      return 1;
78    ip_address++;
79  }
80  char server_ip[4];
81  memcpy(server_ip,hn->h_addr_list,4);
82
83  char my_name[100];                              // now check to see if this address is 'hostname'
84  gethostname(my_name,100);
[124]85  struct hostent *l_hn=gethostbyname(my_name);
[2]86  char **l_ip_address=l_hn->h_addr_list;
87
88  while (*l_ip_address)  // local ip_address
89  {
90    char *a=*l_ip_address;         // scan through all local ip's
91    ip_address=hn->h_addr_list;
92    while (*ip_address)            // scan through all ip's for server_name
93    {
94      char *b=server_ip;
95      if (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3])    // check for match
96        return 1;
97      ip_address++;
98    }
99    l_ip_address++;
100  }
101  return 0;       // didn't match localhost nor hostname, must be somewhere else
102}
103
104int nfs_client::send_read()   // return 0 if failure on socket, not failure to read
105{
106  if (file_fd>=0 && socket_fd>=0)
107  {
108    // first make sure the socket isn't 'full'
109
[494]110    struct timeval tv={ 0,0};     // don't wait
[124]111    fd_set write_check;
112    FD_ZERO(&write_check);
113    FD_SET(socket_fd,&write_check);
[2]114    select(FD_SETSIZE,NULL,&write_check,NULL,&tv);
115
116    if (FD_ISSET(socket_fd,&write_check))            // ready to write?
117    {
[124]118      char buf[READ_PACKET_SIZE];
[17]119      int16_t read_total;
120      int16_t actual;
[2]121
122      do
[124]123      {
124    read_total=size_to_read>(READ_PACKET_SIZE-2) ? (READ_PACKET_SIZE-2) : size_to_read;
125    actual=read(file_fd,buf,read_total);
126    actual=lstl(actual);
127    if (write(socket_fd,&actual,sizeof(actual))!=sizeof(actual))
128    {
129      fprintf(stderr,"write failed\n");
130      return 0;
131    }
132    actual=lstl(actual);
[2]133
[124]134    int write_amount=write(socket_fd,buf,actual);
135    if (write_amount!=actual)
136    {
137      fprintf(stderr,"write failed\n");
138      return 0;
139    }
[2]140
[124]141    size_to_read-=actual;
[2]142
[124]143    FD_ZERO(&write_check);
144    FD_SET(socket_fd,&write_check);
145    select(FD_SETSIZE,NULL,&write_check,NULL,&tv);
[2]146
[124]147    if (!FD_ISSET(socket_fd,&write_check))
148    {
149      FD_SET(socket_fd,&master_write_set);      // socket is full, wait for it empty
150      FD_CLR(socket_fd,&master_set);            // don't check for reading or process commands till read is done
151      return 1;    // not ok to write anymore, try again latter
152    }
[2]153
154      } while (size_to_read && actual==read_total);
155      size_to_read=0;
156      FD_CLR(socket_fd,&master_write_set);       // don't check this socket for write ok
157      FD_SET(socket_fd,&master_set);             // check it for reading
158      return 1;
[124]159    } else
[2]160    {
161      FD_SET(socket_fd,&master_write_set);      // socket is full, wait for it empty
162      FD_CLR(socket_fd,&master_set);            // don't check for reading or process commands till read is done
163      return 1;
164    }
165  }
166  return 0;
167}
168
169
170int process_nfs_command(nfs_client *c)
171{
172  char cmd;
173  if (read(c->socket_fd,&cmd,1)!=1) return 0;
174  switch (cmd)
175  {
176    case NFCMD_READ :
177    {
[17]178      int32_t size;
[2]179      if (read(c->socket_fd,&size,sizeof(size))!=sizeof(size)) return 0;
180      size=lltl(size);
181
182      c->size_to_read=size;
183      return c->send_read();
184    } break;
185    case NFCMD_CLOSE :
186    {
187      return 0;
188    } break;
189    case NFCMD_SEEK :
190    {
[17]191      int32_t offset;
[2]192      if (read(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0;
193      offset=lltl(offset);
194      offset=lseek(c->file_fd,offset,0);
195      offset=lltl(offset);
196      if (write(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0;
197      return 1;
198    } break;
199    case NFCMD_TELL :
200    {
[17]201      int32_t offset=lseek(c->file_fd,0,SEEK_CUR);
[2]202      offset=lltl(offset);
203      if (write(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0;
204      return 1;
205    } break;
[124]206
[2]207    default :
208    { fprintf(stderr,"net driver : bad command from nfs client\n");
209      return 0;
210    }
[124]211  }
[2]212}
213
214
215
216void add_nfs_client(int fd)
217{
[17]218  uint8_t size[2];
[2]219  char filename[300],mode[20],*mp;
220  if (read(fd,size,2)!=2) { close(fd); return ; }
221  if (read(fd,filename,size[0])!=size[0]) { close(fd); return ; }
222  if (read(fd,mode,size[1])!=size[1]) { close(fd); return ; }
[124]223
[2]224  fprintf(stderr,"remote request for %s ",filename);
225
226  secure_filename(filename,mode);  // make sure this filename isn't a security risk
227  if (filename[0]==0) { fprintf(stderr,"(denied)\n"); close(fd); return ; }
228
229  mp=mode;
230  int flags=0;
231
232  while (*mp)
233  {
234    if (*mp=='w') flags|=O_CREAT|O_RDWR;
235    else if (*mp=='r') flags|=O_RDONLY;
236    mp++;
237  }
[124]238
[2]239  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
[124]240
241  if (f<0)
[2]242  {
243    fprintf(stderr,"(not found)\n");
244    f=-1;  // make sure this is -1
245  }
246
[17]247  int32_t ret=lltl(f);
[2]248  if (write(fd,&ret,sizeof(ret))!=sizeof(ret)) { close(fd); return ; }
249
250  if (f<0)    // no file, sorry
251    close(fd);
252  else
253  {
[17]254    int32_t cur_pos=lseek(f,0,SEEK_CUR);
255    int32_t size=lseek(f,0,SEEK_END);
[2]256    lseek(f,cur_pos,SEEK_SET);
257    size=lltl(size);
258    if (write(fd,&size,sizeof(size))!=sizeof(size)) {  close(f); close(fd); return ; }
259
260    first_nfs_client=new nfs_client(fd,f,first_nfs_client);
261    first_nfs_client->size=size;
262  }
263}
264
[124]265void remote_file::r_close(char *reason)
266{
[2]267  if (reason)
268    fprintf(stderr,"remote_file : %s\n",reason);
[124]269  if (socket_fd>=0)
[2]270  {
[17]271    uint8_t cmd=NFCMD_CLOSE;
[2]272    write(socket_fd,&cmd,1);
[124]273    close(socket_fd);
[2]274  }
[124]275  socket_fd=-1;
[2]276}
277
278remote_file::remote_file(char *filename, char *mode, remote_file *Next)
279{
280  next=Next;
281  open_local=0;
282
283  socket_fd=connect_to_server(filename);
284  if (socket_fd==-1)
[124]285  {
[2]286    fprintf(stderr,"unable to connect\n");
287    return ;
288  }
289
[494]290  uint8_t sizes[3]={ CLIENT_NFS,strlen(filename)+1,strlen(mode)+1};
[2]291  if (write(socket_fd,sizes,3)!=3) { r_close("could not send open info"); return ; }
292  if (write(socket_fd,filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; }
293  if (write(socket_fd,mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; }
294
[17]295  int32_t remote_file_fd;
[124]296  if (read(socket_fd,&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd))
297  { r_close("could not read remote fd"); return ; }
[2]298  remote_file_fd=lltl(remote_file_fd);
299  if (remote_file_fd<0) { r_close("remote fd is bad"); return ; }
300
[124]301  if (read(socket_fd,&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; }
[17]302//  uint32_t remote_crc;
[2]303//  if (read(socket_fd,&remote_crc,sizeof(remote_crc))!=sizeof(remote_crc)) { r_close("could not read remote checksum"); return ; }
[17]304//  uint32_t local_crc=
[2]305
306  size=lltl(size);
307}
308
309int remote_file::unbuffered_read(int out_fd, size_t count)
310{
311  if (socket_fd>=0 && count)
312  {
[17]313    uint8_t cmd=NFCMD_READ;
[2]314    if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; }
315
[17]316    int32_t rsize=lltl(count);
[2]317    if (write(socket_fd,&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; }
318
[17]319    int32_t total_read=0,total;
[2]320    char buf[READ_PACKET_SIZE];
[17]321    uint16_t size;
[2]322
[124]323    uint16_t packet_size;
[2]324    do
325    {
[124]326      if (read(socket_fd,&packet_size,sizeof(packet_size))!=sizeof(packet_size))
[2]327      {
[124]328    fprintf(stderr,"could not read packet size\n");
329    return 0;
[2]330      }
331      packet_size=lstl(packet_size);
332
[124]333      uint16_t size_read=read(socket_fd,buf+2,packet_size);
[2]334
[124]335      if (size_read!=packet_size)
336      {
337    if (read(socket_fd,buf+2+size_read,packet_size-size_read)!=packet_size-size_read)
338    {
339      fprintf(stderr,"incomplete packet\n");
340      return 0;
341    }
[2]342      }
343
[17]344      *((int16_t *)buf)=packet_size;
[2]345      if (write(out_fd,buf,packet_size+2)!=packet_size+2) comm_failed();
346
347      total_read+=packet_size;
348      count-=packet_size;
[124]349    } while (packet_size==READ_PACKET_SIZE-2 && count);
[2]350    return total_read;
351  }
352  return 0;
353}
354
355int remote_file::unbuffered_tell()   // ask server where the offset of the file pointer is
356{
357  if (socket_fd>=0)
358  {
[17]359    uint8_t cmd=NFCMD_TELL;
[2]360    if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; }
361
[17]362    int32_t offset;
[124]363    if (read(socket_fd,&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; }
[2]364    return lltl(offset);
[124]365  }
[2]366  return 0;
367}
368
[17]369int remote_file::unbuffered_seek(int32_t offset)  // tell server to seek to a spot in a file
[2]370{
371  if (socket_fd>=0)
372  {
[17]373    uint8_t cmd=NFCMD_SEEK;
[2]374    if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; }
375
[17]376    int32_t off=lltl(offset);
[2]377    if (write(socket_fd,&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; }
378
[124]379    if (read(socket_fd,&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; }
[2]380    return lltl(offset);
[124]381  }
[2]382  return 0;
383}
384
385int open_file(char *&filename, char *mode)
386{
387  if (filename[0]!='/' && filename[1]!='/' && default_fs_name[0])   // default file server?
388  {
[124]389    char tmp_fn[500];
[2]390    sprintf(tmp_fn,"//%s/%s",default_fs_name,filename);
391    strcpy(filename,tmp_fn);
392  }
393
394  if (filename[0]=='/' && filename[1]=='/')   // passive server file reference?
395  {
396    filename+=2;
397    remote_file *rf=new remote_file(filename,mode,remote_file_list);
398    if (rf->open_failure())
399    {
400      delete rf;
401      return -1;
402    }
[124]403    else
[2]404    {
405      remote_file_list=rf;
406      return rf->socket_fd;
[124]407    }
[2]408  }
409
410  secure_filename(filename,mode);
411  if (filename[0]==0) return -1;
412
413  int flags=0;
414  while (*mode)
415  {
416    if (*mode=='w') flags|=O_CREAT|O_RDWR;
417    else if (*mode=='r') flags|=O_RDONLY;
418    mode++;
419  }
420
421  int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO);
422  if (f>=0)
423  { close(f);
424    return -2;
425  }
[124]426
[2]427  return -1;
428}
429
430remote_file *find_rfile(int fd)
431{
432  remote_file *r=remote_file_list;
[494]433  for (; r && r->socket_fd!=fd; r=r->next)
[2]434  {
435    if (r->socket_fd==-1)
436    {
437      fprintf(stderr,"bad sock\n");
438    }
439  }
440  return r;
441}
442
443void unlink_remote_file(remote_file *rf)
444{
445  if (rf==remote_file_list)
446    remote_file_list=rf->next;
447  else
448  {
449    remote_file *last=remote_file_list;
450    while (last->next && last->next!=rf) last=last->next;
451    last->next=rf->next;
452  }
453}
454
455remote_file::~remote_file()
456{ r_close(NULL); }
457
458
459int fetch_crcs(char *server)
460{
461  int socket_fd=connect_to_server(server);
462  if (socket_fd==-1)
[124]463  {
[2]464    fprintf(stderr,"unable to connect\n");
465    return 0;
466  }
467
[17]468  uint8_t cmd=CLIENT_CRC_WAITER;
[2]469  if (write(socket_fd,&cmd,1)!=1)  { close(socket_fd); return 0; }
470  if (read(socket_fd,&cmd,1)!=1)  { close(socket_fd); return 0; }
471  close(socket_fd);
472  return cmd;
[124]473
[2]474}
475
[651]476#endif // HAVE_NETWORK
[2]477
Note: See TracBrowser for help on using the repository browser.