source: abuse/trunk/src/net/netfile.cpp @ 524

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

core: Get rid of mostly useless headers, move endianness handling to
common.h (and rewrite functions so that they do not need the SDL headers)
and move a few functions out of sdlport's video.cpp. These functions
were in the original video.cpp (which reappears) and shouldn't be part
of the SDL port.

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