/* pscope (periscope) allows a macintosh connected to the network to "see" into a unix directory and retrieve files from it */ #include #include #include #include #include #include #include #include #include #define TRUE 1 #define SEND 0 #define RECEIVE 1 #define MORE 0 #define DONE 1 #define kTCPBlockSize 256 #define HANDSHAKE 2 #define PROTOCOL_ERR 2 #define TERMINATING 3 #define BAD_NAME 4 int inDescriptor; struct stat inStat; int inSize; FILE *in = stdin,*out = stdout; unsigned char *outbuf = NULL; /* file buffer -> mac */ void handshake(buf,bytes,sock) char *buf; int bytes; int sock; { char *username; struct passwd *userinfo; unsigned char controlByte = buf[0]; outbuf = (unsigned char *)malloc(1); if(controlByte != HANDSHAKE){ /* protocol error */ outbuf[0] = PROTOCOL_ERR; #ifdef DEBUG fprintf(stderr,"Bad Handshake\n"); #endif if(write(sock,outbuf,1) < 0) perror("ERROR writing to socket"); outbuf[0] = TERMINATING; if(write(sock,outbuf,1) < 0) perror("ERROR writing to socket"); close(sock); exit(0); } /* rest of message is userid */ username = (char *)malloc(bytes); memcpy(username,&buf[1],bytes-1); username[bytes-1] = '\0'; userinfo = getpwuid(getuid()); if(strcmp(username,userinfo->pw_name)){ /* account names don't match */ outbuf[0] = BAD_NAME; #ifdef DEBUG fprintf(stderr,"Bad Account\n"); #endif if(write(sock,outbuf,1) < 0) perror("ERROR writing to socket"); outbuf[0] = TERMINATING; if(write(sock,outbuf,1) < 0) perror("ERROR writing to socket"); close(sock); free(userinfo); exit(0); } /* Don't worry, be happy! */ free(userinfo); outbuf[0] = 0; if(write(sock,outbuf,1) < 0) perror("ERROR writing to socket"); return; } void handleMessage(buf,size,msgsock) char *buf; int size; int msgsock; { unsigned char controlByte; int nBytes; char *data; char *filename; int bytesSent = 0; int bytesToGo; int sendBytes; controlByte = buf[0]; switch(controlByte){ case SEND: /* client wants server to send data, resulting from last request */ /* allocate enough buffer space to transmit at least an error */ outbuf = (unsigned char *)malloc(1); memcpy(&nBytes,&(buf[1]),sizeof(int)); /* no of bytes in file name */ filename = (char *)malloc(nBytes+1); memcpy(filename,&(buf[5]),nBytes); /* got the filename assigned */ filename[nBytes] = '\0'; /* termninate fname string */ /* set error flag */ outbuf[0] = 1; if((inDescriptor = open(filename,0)) == -1){ #ifdef DEBUG fprintf(stderr,"failed to open %s\n",filename); #endif if(write(msgsock,outbuf,1) < 0) perror("ERROR writing to socket"); break; } free(filename); /* get input file info */ fstat(inDescriptor,&inStat); inSize = inStat.st_size; /* dynamically allocate enough buffer space here */ outbuf = (unsigned char *)realloc(outbuf,inSize+4+1); /* write number of bytes in data to buffer */ memcpy(&outbuf[1],&inSize,sizeof(inSize)); nBytes = read(inDescriptor,&(outbuf[5]),inSize); #ifdef DEBUG fprintf(stderr,"read %d bytes\n",nBytes); #endif if(nBytes < 0){ #ifdef DEBUG fprintf(stderr,"read error: %d\n",errno); #endif if(write(msgsock,outbuf,1) < 0) perror("ERROR writing to socket"); break; } else if (nBytes == 0){ #ifdef DEBUG fprintf(stderr,"No data read\n"); #endif if(write(msgsock,outbuf,1) < 0) perror("ERROR writing to socket"); break; } outbuf[0] = 0; /* data is good */ /* send control byte + size int */ if(write(msgsock,outbuf,5) < 0) perror("ERROR writing to socket"); if(write(msgsock,&(outbuf[5]),inSize) < 0) perror("ERROR writing to socket"); break; case RECEIVE: /* client wants to send data to the server */ memcpy(&nBytes,&(buf[1]),sizeof(int)); fprintf(stderr,"RECEIVE\n"); fflush(stderr); ntohs(nBytes); fprintf(stderr,"nBytes = %d\n",nBytes); fprintf(stderr,"%d\n%d\n%d\n%d\n",buf[1],buf[2],buf[3],buf[4]); data = (char *)malloc((nBytes + 1) * sizeof(char)); memcpy(data,&(buf[1+sizeof(int)]),nBytes); data[nBytes] = '\0'; fprintf(out,"-->%s\n",data); free(data); break; default: break; } } main(argc,argv) int argc; char **argv; { int port = 32200; int sock , range = 10, length; struct sockaddr_in server; int msgsock; char buf[1024]; int rval; fd_set ready; struct timeval to; char *filename; extern char *optarg; int nonOptArgs; char c; int p_flag = 0; int r_flag = 0; int done = 0; int result; /* process command line args */ while((c = getopt(argc,argv,"p:r:")) != -1) switch(c){ case 'p': p_flag = 1; port = atoi(optarg); break; case 'r': r_flag = 1; range = atoi(optarg); break; default: #ifdef DEBUG fprintf("improper option ignored\n"); #endif ; } nonOptArgs = argc - 1 - p_flag - r_flag; /* Create Socket */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("ERROR opening stream socket"); exit(1); } /* Name socket using wilddcards */ server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = port; /* search until unused port# is found or range exhausted */ while(!done && server.sin_port < (port + range)){ result = bind(sock, (struct sockaddr *)&server, sizeof server); if(result < 0) server.sin_port++; else done = 1; } if(!done){ fprintf(stderr,"Unable to bind socket to port, exitting...\n"); exit(1); } #ifdef DEBUG fprintf(stderr,"Socket prot #%d\n", ntohs(server.sin_port)); #endif /* Start accepting connections */ listen(sock, 5); do { FD_ZERO(&ready); FD_SET(sock, &ready); to.tv_sec = 5; if (select(sock + 1, &ready, (fd_set *)0, (fd_set *)0, &to) < 0) { perror("ERROR select"); continue; } if (FD_ISSET(sock, &ready)) { msgsock = accept(sock, (struct sockaddr *)0, (int *)0); if (msgsock == -1) perror("ERROR accept"); else { if(fork() == 0){ /* child */ close(sock); /* do the handshake */ bzero(buf,sizeof buf); if ((rval = read(msgsock, buf, 1024)) < 0) { perror("ERROR reading stream message"); close(msgsock); exit(0); /* child dies */ } if(rval == 0){ close(msgsock); exit(0); } handshake(buf,rval,msgsock); do { bzero(buf, sizeof buf); /* block until data is available */ if ((rval = read(msgsock, buf, 1024)) < 0) { perror("ERROR reading stream message"); close(msgsock); exit(0); /* child dies */ } else if (rval == 0) printf("No more data\n"); else handleMessage(buf,1024,msgsock); } while(rval > 0); } close(msgsock); /* parent */ } } } while(TRUE); exit(0); }