#include "indian.hpp" #include "netfile.hpp" #include "../inc/netface.hpp" #include "engine.hpp" nfs_client *first_nfs_client=NULL; remote_file *remote_file_list=NULL; char default_fs_name[256]; // default file server name (set with parm -fs) nfs_client::nfs_client(net_socket *sock, int file_fd, nfs_client *next) : sock(sock),file_fd(file_fd),next(next),size_to_read(0) { sock->read_selectable(); } nfs_client::~nfs_client() { delete sock; if (file_fd>=0) close(file_fd); } void secure_filename(char *filename, char *mode) { if (!no_security) { if (filename[0]=='/') { filename[0]=0; return ; } int level=0; char *f=filename; while (*f) { if (*f=='/') { f++; level++; } else if (*f=='.' && f[1]=='.') { if (f[3]=='.') while (*f!='.') f++; else { f+=2; level--; } } else f++; } if (level<0) filename[0]=0; } } int local_address(char *server_name) // returns 1 if server name is ourself { struct hostent *hn=gethostbyname(server_name); // first check to see if this address is 127.0.0.1 if (!hn) return 0; // if bad server_name, return false char **ip_address=hn->h_addr_list; while (*ip_address) { char *a=*ip_address; if (a[0]==127 && a[1]==0 && a[2]==0 && a[3]==1) return 1; ip_address++; } char server_ip[4]; memcpy(server_ip,hn->h_addr_list,4); char my_name[100]; // now check to see if this address is 'hostname' gethostname(my_name,100); struct hostent *l_hn=gethostbyname(my_name); char **l_ip_address=l_hn->h_addr_list; while (*l_ip_address) // local ip_address { char *a=*l_ip_address; // scan through all local ip's ip_address=hn->h_addr_list; while (*ip_address) // scan through all ip's for server_name { char *b=server_ip; if (a[0]==b[0] && a[1]==b[1] && a[2]==b[2] && a[3]==b[3]) // check for match return 1; ip_address++; } l_ip_address++; } return 0; // didn't match localhost nor hostname, must be somewhere else } int nfs_client::send_read() // return 0 if failure on socket, not failure to read { if (file_fd>=0 && socket_fd>=0) { // first make sure the socket isn't 'full' struct timeval tv={0,0}; // don't wait fd_set write_check; FD_ZERO(&write_check); FD_SET(socket_fd,&write_check); select(FD_SETSIZE,NULL,&write_check,NULL,&tv); if (FD_ISSET(socket_fd,&write_check)) // ready to write? { char buf[READ_PACKET_SIZE]; short read_total; short actual; do { read_total=size_to_read>(READ_PACKET_SIZE-2) ? (READ_PACKET_SIZE-2) : size_to_read; actual=read(file_fd,buf,read_total); actual=lstl(actual); if (write(socket_fd,&actual,sizeof(actual))!=sizeof(actual)) { fprintf(stderr,"write failed\n"); return 0; } actual=lstl(actual); int write_amount=write(socket_fd,buf,actual); if (write_amount!=actual) { fprintf(stderr,"write failed\n"); return 0; } size_to_read-=actual; FD_ZERO(&write_check); FD_SET(socket_fd,&write_check); select(FD_SETSIZE,NULL,&write_check,NULL,&tv); if (!FD_ISSET(socket_fd,&write_check)) { FD_SET(socket_fd,&master_write_set); // socket is full, wait for it empty FD_CLR(socket_fd,&master_set); // don't check for reading or process commands till read is done return 1; // not ok to write anymore, try again latter } } while (size_to_read && actual==read_total); size_to_read=0; FD_CLR(socket_fd,&master_write_set); // don't check this socket for write ok FD_SET(socket_fd,&master_set); // check it for reading return 1; } else { FD_SET(socket_fd,&master_write_set); // socket is full, wait for it empty FD_CLR(socket_fd,&master_set); // don't check for reading or process commands till read is done return 1; } } return 0; } int process_nfs_command(nfs_client *c) { char cmd; if (read(c->socket_fd,&cmd,1)!=1) return 0; switch (cmd) { case NFCMD_READ : { long size; if (read(c->socket_fd,&size,sizeof(size))!=sizeof(size)) return 0; size=lltl(size); c->size_to_read=size; return c->send_read(); } break; case NFCMD_CLOSE : { return 0; } break; case NFCMD_SEEK : { long offset; if (read(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0; offset=lltl(offset); offset=lseek(c->file_fd,offset,0); offset=lltl(offset); if (write(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0; return 1; } break; case NFCMD_TELL : { long offset=lseek(c->file_fd,0,SEEK_CUR); offset=lltl(offset); if (write(c->socket_fd,&offset,sizeof(offset))!=sizeof(offset)) return 0; return 1; } break; default : { fprintf(stderr,"net driver : bad command from nfs client\n"); return 0; } } } void add_nfs_client(int fd) { uchar size[2]; char filename[300],mode[20],*mp; if (read(fd,size,2)!=2) { close(fd); return ; } if (read(fd,filename,size[0])!=size[0]) { close(fd); return ; } if (read(fd,mode,size[1])!=size[1]) { close(fd); return ; } fprintf(stderr,"remote request for %s ",filename); secure_filename(filename,mode); // make sure this filename isn't a security risk if (filename[0]==0) { fprintf(stderr,"(denied)\n"); close(fd); return ; } mp=mode; int flags=0; while (*mp) { if (*mp=='w') flags|=O_CREAT|O_RDWR; else if (*mp=='r') flags|=O_RDONLY; mp++; } int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO); if (f<0) { fprintf(stderr,"(not found)\n"); f=-1; // make sure this is -1 } long ret=lltl(f); if (write(fd,&ret,sizeof(ret))!=sizeof(ret)) { close(fd); return ; } if (f<0) // no file, sorry close(fd); else { long cur_pos=lseek(f,0,SEEK_CUR); long size=lseek(f,0,SEEK_END); lseek(f,cur_pos,SEEK_SET); size=lltl(size); if (write(fd,&size,sizeof(size))!=sizeof(size)) { close(f); close(fd); return ; } first_nfs_client=new nfs_client(fd,f,first_nfs_client); first_nfs_client->size=size; } } void remote_file::r_close(char *reason) { if (reason) fprintf(stderr,"remote_file : %s\n",reason); if (socket_fd>=0) { uchar cmd=NFCMD_CLOSE; write(socket_fd,&cmd,1); close(socket_fd); } socket_fd=-1; } remote_file::remote_file(char *filename, char *mode, remote_file *Next) { next=Next; open_local=0; socket_fd=connect_to_server(filename); if (socket_fd==-1) { fprintf(stderr,"unable to connect\n"); return ; } uchar sizes[3]={CLIENT_NFS,strlen(filename)+1,strlen(mode)+1}; if (write(socket_fd,sizes,3)!=3) { r_close("could not send open info"); return ; } if (write(socket_fd,filename,sizes[1])!=sizes[1]) { r_close("could not send filename"); return ; } if (write(socket_fd,mode,sizes[2])!=sizes[2]) { r_close("could not send mode"); return ; } long remote_file_fd; if (read(socket_fd,&remote_file_fd,sizeof(remote_file_fd))!=sizeof(remote_file_fd)) { r_close("could not read remote fd"); return ; } remote_file_fd=lltl(remote_file_fd); if (remote_file_fd<0) { r_close("remote fd is bad"); return ; } if (read(socket_fd,&size,sizeof(size))!=sizeof(size)) { r_close("could not read remote filesize"); return ; } // ulong remote_crc; // if (read(socket_fd,&remote_crc,sizeof(remote_crc))!=sizeof(remote_crc)) { r_close("could not read remote checksum"); return ; } // ulong local_crc= size=lltl(size); } int remote_file::unbuffered_read(int out_fd, size_t count) { if (socket_fd>=0 && count) { uchar cmd=NFCMD_READ; if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("read : could not send command"); return 0; } long rsize=lltl(count); if (write(socket_fd,&rsize,sizeof(rsize))!=sizeof(rsize)) { r_close("read : could not send size"); return 0; } long total_read=0,total; char buf[READ_PACKET_SIZE]; ushort size; ushort packet_size; do { if (read(socket_fd,&packet_size,sizeof(packet_size))!=sizeof(packet_size)) { fprintf(stderr,"could not read packet size\n"); return 0; } packet_size=lstl(packet_size); ushort size_read=read(socket_fd,buf+2,packet_size); if (size_read!=packet_size) { if (read(socket_fd,buf+2+size_read,packet_size-size_read)!=packet_size-size_read) { fprintf(stderr,"incomplete packet\n"); return 0; } } *((short *)buf)=packet_size; if (write(out_fd,buf,packet_size+2)!=packet_size+2) comm_failed(); total_read+=packet_size; count-=packet_size; } while (packet_size==READ_PACKET_SIZE-2 && count); return total_read; } return 0; } int remote_file::unbuffered_tell() // ask server where the offset of the file pointer is { if (socket_fd>=0) { uchar cmd=NFCMD_TELL; if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("tell : could not send command"); return 0; } long offset; if (read(socket_fd,&offset,sizeof(offset))!=sizeof(offset)) { r_close("tell : could not read offset"); return 0; } return lltl(offset); } return 0; } int remote_file::unbuffered_seek(long offset) // tell server to seek to a spot in a file { if (socket_fd>=0) { uchar cmd=NFCMD_SEEK; if (write(socket_fd,&cmd,sizeof(cmd))!=sizeof(cmd)) { r_close("seek : could not send command"); return 0; } long off=lltl(offset); if (write(socket_fd,&off,sizeof(off))!=sizeof(off)) { r_close("seek : could not send offset"); return 0; } if (read(socket_fd,&offset,sizeof(offset))!=sizeof(offset)) { r_close("seek : could not read offset"); return 0; } return lltl(offset); } return 0; } int open_file(char *&filename, char *mode) { if (filename[0]!='/' && filename[1]!='/' && default_fs_name[0]) // default file server? { char tmp_fn[500]; sprintf(tmp_fn,"//%s/%s",default_fs_name,filename); strcpy(filename,tmp_fn); } if (filename[0]=='/' && filename[1]=='/') // passive server file reference? { filename+=2; remote_file *rf=new remote_file(filename,mode,remote_file_list); if (rf->open_failure()) { delete rf; return -1; } else { remote_file_list=rf; return rf->socket_fd; } } secure_filename(filename,mode); if (filename[0]==0) return -1; int flags=0; while (*mode) { if (*mode=='w') flags|=O_CREAT|O_RDWR; else if (*mode=='r') flags|=O_RDONLY; mode++; } int f=open(filename,flags,S_IRWXU | S_IRWXG | S_IRWXO); if (f>=0) { close(f); return -2; } return -1; } remote_file *find_rfile(int fd) { remote_file *r=remote_file_list; for (;r && r->socket_fd!=fd;r=r->next) { if (r->socket_fd==-1) { fprintf(stderr,"bad sock\n"); } } return r; } void unlink_remote_file(remote_file *rf) { if (rf==remote_file_list) remote_file_list=rf->next; else { remote_file *last=remote_file_list; while (last->next && last->next!=rf) last=last->next; last->next=rf->next; } } remote_file::~remote_file() { r_close(NULL); } int fetch_crcs(char *server) { int socket_fd=connect_to_server(server); if (socket_fd==-1) { fprintf(stderr,"unable to connect\n"); return 0; } uchar cmd=CLIENT_CRC_WAITER; if (write(socket_fd,&cmd,1)!=1) { close(socket_fd); return 0; } if (read(socket_fd,&cmd,1)!=1) { close(socket_fd); return 0; } close(socket_fd); return cmd; }