/* ftp_server.c
/* This is the server for a very simple file transfer
service. This is a "concurrent server" that can
handle requests from multiple simultaneous clients.
For each client:
- get file name and check if it exists
- send size of file to client
- send file to client, a block at a time
- close connection with client
*/
#include
#include
#include
#include
#include
#include
#include
#define MY_PORT_ID 6081
#define MAXLINE 256
#define MAXSIZE 512
#define ACK 2
#define NACK 3
#define REQUESTFILE 100
#define COMMANDNOTSUPPORTED 150
#define COMMANDSUPPORTED 160
#define BADFILENAME 200
#define FILENAMEOK 400
int writen(int sd,char *ptr,int size);
int readn(int sd,char *ptr,int size);
int main() {
int sockid, newsd, pid, clilen;
struct sockaddr_in my_addr, client_addr;
printf("server: creating socket\n");
if ((sockid = socket(AF_INET,SOCK_STREAM,0)) < 0)
{printf("server: socket error : %d\n", errno); exit(0); }
printf("server: binding my local socket\n");
bzero((char *) &my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MY_PORT_ID);
my_addr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(sockid ,(struct sockaddr *) &my_addr,sizeof(my_addr)) < 0)
{printf("server: bind error :%d\n", errno); exit(0); }
printf("server: starting listen \n");
if (listen(sockid,5) < 0)
{ printf("server: listen error :%d\n",errno);exit(0);}
while(1==1) {
/* ACCEPT A CONNECTION AND THEN CREATE A CHILD TO DO THE WORK */
/* LOOP BACK AND WAIT FOR ANOTHER CONNECTION */
printf("server: starting accept\n");
if ((newsd = accept(sockid ,(struct sockaddr *) &client_addr,
&clilen)) < 0)
{printf("server: accept error :%d\n", errno); exit(0); }
printf("server: return from accept, socket for this ftp: %d\n",
newsd);
if ( (pid=fork()) == 0) {
/* CHILD PROC STARTS HERE. IT WILL DO ACTUAL FILE TRANSFER */
close(sockid); /* child shouldn't do an accept */
doftp(newsd);
close (newsd);
exit(0); /* child all done with work */
}
/* PARENT CONTINUES BELOW HERE */
close(newsd); /* parent all done with client, only child */
} /* will communicate with that client from now on */
}
/* CHILD PROCEDURE, WHICH ACTUALLY DOES THE FILE TRANSFER */
doftp(int newsd)
{
int i,fsize,fd,msg_ok,fail,fail1,req,c,ack;
int no_read ,num_blks , num_blks1,num_last_blk,num_last_blk1,tmp;
char fname[MAXLINE];
char out_buf[MAXSIZE];
FILE *fp;
no_read = 0;
num_blks = 0;
num_last_blk = 0;
/* START SERVICING THE CLIENT */
/* get command code from client.*/
/* only one supported command: 100 - get a file */
req = 0;
if((readn(newsd,(char *)&req,sizeof(req))) < 0)
{printf("server: read error %d\n",errno);exit(0);}
req = ntohs(req);
printf("server: client request code is: %d\n",req);
if (req!=REQUESTFILE) {
printf("server: unsupported operation. goodbye\n");
/* reply to client: command not OK (code: 150) */
msg_ok = COMMANDNOTSUPPORTED;
msg_ok = htons(msg_ok);
if((writen(newsd,(char *)&msg_ok,sizeof(msg_ok))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
exit(0);
}
/* reply to client: command OK (code: 160) */
msg_ok = COMMANDSUPPORTED;
msg_ok = htons(msg_ok);
if((writen(newsd,(char *)&msg_ok,sizeof(msg_ok))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
fail = FILENAMEOK;
if((read(newsd,fname,MAXLINE)) < 0) {
printf("server: filename read error :%d\n",errno);
fail = BADFILENAME ;
}
/* IF SERVER CANT OPEN FILE THEN INFORM CLIENT OF THIS AND TERMINATE */
if((fp = fopen(fname,"r")) == NULL) /*cant open file*/
fail = BADFILENAME;
tmp = htons(fail);
if((writen(newsd,(char *)&tmp,sizeof(tmp))) < 0)
{printf("server: write error :%d\n",errno);exit(0); }
if(fail == BADFILENAME) {printf("server cant open file\n");
close(newsd);exit(0);}
printf("server: filename is %s\n",fname);
req = 0;
if ((readn(newsd,(char *)&req,sizeof(req))) < 0)
{printf("server: read error :%d\n",errno);exit(0);}
printf("server: start transfer command, %d, received\n", ntohs(req));
/*SERVER GETS FILESIZE AND CALCULATES THE NUMBER OF BLOCKS OF
SIZE = MAXSIZE IT WILL TAKE TO TRANSFER THE FILE. ALSO CALCULATE
NUMBER OF BYTES IN THE LAST PARTIALLY FILLED BLOCK IF ANY.
SEND THIS INFO TO CLIENT, RECEIVING ACKS */
printf("server: starting transfer\n");
fsize = 0;ack = 0;
while ((c = getc(fp)) != EOF) {fsize++;}
num_blks = fsize / MAXSIZE;
num_blks1 = htons(num_blks);
num_last_blk = fsize % MAXSIZE;
num_last_blk1 = htons(num_last_blk);
if((writen(newsd,(char *)&num_blks1,sizeof(num_blks1))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
printf("server: told client there are %d blocks\n", num_blks);
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0); }
if (ntohs(ack) != ACK) {
printf("client: ACK not received on file size\n");
exit(0);
}
if((writen(newsd,(char *)&num_last_blk1,sizeof(num_last_blk1))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
printf("server: told client %d bytes in last block\n", num_last_blk);
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0); }
if (ntohs(ack) != ACK) {
printf("server: ACK not received on file size\n");
exit(0);
}
rewind(fp);
/* ACTUAL FILE TRANSFER STARTS BLOCK BY BLOCK*/
for(i= 0; i < num_blks; i ++) {
no_read = fread(out_buf,sizeof(char),MAXSIZE,fp);
if (no_read == 0) {printf("server: file read error\n");exit(0);}
if (no_read != MAXSIZE)
{printf("server: file read error : no_read is less\n");exit(0);}
if((writen(newsd,out_buf,MAXSIZE)) < 0)
{printf("server: error sending block:%d\n",errno);exit(0);}
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0);}
if (ntohs(ack) != ACK) {
printf("server: ACK not received for block %d\n",i);
exit(0);
}
printf(" %d...",i);
}
if (num_last_blk > 0) {
printf("%d\n",num_blks);
no_read = fread(out_buf,sizeof(char),num_last_blk,fp);
if (no_read == 0) {printf("server: file read error\n");exit(0);}
if (no_read != num_last_blk)
{printf("server: file read error : no_read is less 2\n");exit(0);}
if((writen(newsd,out_buf,num_last_blk)) < 0)
{printf("server: file transfer error %d\n",errno);exit(0);}
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error %d\n",errno);exit(0);}
if (ntohs(ack) != ACK) {
printf("server: ACK not received last block\n");
exit(0);
}
}
else printf("\n");
/* FILE TRANSFER ENDS */
printf("server: FILE TRANSFER COMPLETE on socket %d\n",newsd);
fclose(fp);
close(newsd);
}
/*
TO TAKE CARE OF THE POSSIBILITY OF BUFFER LIMMITS IN THE KERNEL FOR THE
SOCKET BEING REACHED (WHICH MAY CAUSE READ OR WRITE TO RETURN FEWER CHARACTERS
THAN REQUESTED), WE USE THE FOLLOWING TWO FUNCTIONS */
int readn(int sd,char *ptr,int size)
{ int no_left,no_read;
no_left = size;
while (no_left > 0)
{ no_read = read(sd,ptr,no_left);
if(no_read <0) return(no_read);
if (no_read == 0) break;
no_left -= no_read;
ptr += no_read;
}
return(size - no_left);
}
int writen(int sd,char *ptr,int size)
{ int no_left,no_written;
no_left = size;
while (no_left > 0)
{ no_written = write(sd,ptr,no_left);
if(no_written <=0) return(no_written);
no_left -= no_written;
ptr += no_written;
}
return(size - no_left);
}
/* This is the server for a very simple file transfer
service. This is a "concurrent server" that can
handle requests from multiple simultaneous clients.
For each client:
- get file name and check if it exists
- send size of file to client
- send file to client, a block at a time
- close connection with client
*/
#include
#include
#include
#include
#include
#include
#include
#define MY_PORT_ID 6081
#define MAXLINE 256
#define MAXSIZE 512
#define ACK 2
#define NACK 3
#define REQUESTFILE 100
#define COMMANDNOTSUPPORTED 150
#define COMMANDSUPPORTED 160
#define BADFILENAME 200
#define FILENAMEOK 400
int writen(int sd,char *ptr,int size);
int readn(int sd,char *ptr,int size);
int main() {
int sockid, newsd, pid, clilen;
struct sockaddr_in my_addr, client_addr;
printf("server: creating socket\n");
if ((sockid = socket(AF_INET,SOCK_STREAM,0)) < 0)
{printf("server: socket error : %d\n", errno); exit(0); }
printf("server: binding my local socket\n");
bzero((char *) &my_addr,sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MY_PORT_ID);
my_addr.sin_addr.s_addr = htons(INADDR_ANY);
if (bind(sockid ,(struct sockaddr *) &my_addr,sizeof(my_addr)) < 0)
{printf("server: bind error :%d\n", errno); exit(0); }
printf("server: starting listen \n");
if (listen(sockid,5) < 0)
{ printf("server: listen error :%d\n",errno);exit(0);}
while(1==1) {
/* ACCEPT A CONNECTION AND THEN CREATE A CHILD TO DO THE WORK */
/* LOOP BACK AND WAIT FOR ANOTHER CONNECTION */
printf("server: starting accept\n");
if ((newsd = accept(sockid ,(struct sockaddr *) &client_addr,
&clilen)) < 0)
{printf("server: accept error :%d\n", errno); exit(0); }
printf("server: return from accept, socket for this ftp: %d\n",
newsd);
if ( (pid=fork()) == 0) {
/* CHILD PROC STARTS HERE. IT WILL DO ACTUAL FILE TRANSFER */
close(sockid); /* child shouldn't do an accept */
doftp(newsd);
close (newsd);
exit(0); /* child all done with work */
}
/* PARENT CONTINUES BELOW HERE */
close(newsd); /* parent all done with client, only child */
} /* will communicate with that client from now on */
}
/* CHILD PROCEDURE, WHICH ACTUALLY DOES THE FILE TRANSFER */
doftp(int newsd)
{
int i,fsize,fd,msg_ok,fail,fail1,req,c,ack;
int no_read ,num_blks , num_blks1,num_last_blk,num_last_blk1,tmp;
char fname[MAXLINE];
char out_buf[MAXSIZE];
FILE *fp;
no_read = 0;
num_blks = 0;
num_last_blk = 0;
/* START SERVICING THE CLIENT */
/* get command code from client.*/
/* only one supported command: 100 - get a file */
req = 0;
if((readn(newsd,(char *)&req,sizeof(req))) < 0)
{printf("server: read error %d\n",errno);exit(0);}
req = ntohs(req);
printf("server: client request code is: %d\n",req);
if (req!=REQUESTFILE) {
printf("server: unsupported operation. goodbye\n");
/* reply to client: command not OK (code: 150) */
msg_ok = COMMANDNOTSUPPORTED;
msg_ok = htons(msg_ok);
if((writen(newsd,(char *)&msg_ok,sizeof(msg_ok))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
exit(0);
}
/* reply to client: command OK (code: 160) */
msg_ok = COMMANDSUPPORTED;
msg_ok = htons(msg_ok);
if((writen(newsd,(char *)&msg_ok,sizeof(msg_ok))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
fail = FILENAMEOK;
if((read(newsd,fname,MAXLINE)) < 0) {
printf("server: filename read error :%d\n",errno);
fail = BADFILENAME ;
}
/* IF SERVER CANT OPEN FILE THEN INFORM CLIENT OF THIS AND TERMINATE */
if((fp = fopen(fname,"r")) == NULL) /*cant open file*/
fail = BADFILENAME;
tmp = htons(fail);
if((writen(newsd,(char *)&tmp,sizeof(tmp))) < 0)
{printf("server: write error :%d\n",errno);exit(0); }
if(fail == BADFILENAME) {printf("server cant open file\n");
close(newsd);exit(0);}
printf("server: filename is %s\n",fname);
req = 0;
if ((readn(newsd,(char *)&req,sizeof(req))) < 0)
{printf("server: read error :%d\n",errno);exit(0);}
printf("server: start transfer command, %d, received\n", ntohs(req));
/*SERVER GETS FILESIZE AND CALCULATES THE NUMBER OF BLOCKS OF
SIZE = MAXSIZE IT WILL TAKE TO TRANSFER THE FILE. ALSO CALCULATE
NUMBER OF BYTES IN THE LAST PARTIALLY FILLED BLOCK IF ANY.
SEND THIS INFO TO CLIENT, RECEIVING ACKS */
printf("server: starting transfer\n");
fsize = 0;ack = 0;
while ((c = getc(fp)) != EOF) {fsize++;}
num_blks = fsize / MAXSIZE;
num_blks1 = htons(num_blks);
num_last_blk = fsize % MAXSIZE;
num_last_blk1 = htons(num_last_blk);
if((writen(newsd,(char *)&num_blks1,sizeof(num_blks1))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
printf("server: told client there are %d blocks\n", num_blks);
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0); }
if (ntohs(ack) != ACK) {
printf("client: ACK not received on file size\n");
exit(0);
}
if((writen(newsd,(char *)&num_last_blk1,sizeof(num_last_blk1))) < 0)
{printf("server: write error :%d\n",errno);exit(0);}
printf("server: told client %d bytes in last block\n", num_last_blk);
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0); }
if (ntohs(ack) != ACK) {
printf("server: ACK not received on file size\n");
exit(0);
}
rewind(fp);
/* ACTUAL FILE TRANSFER STARTS BLOCK BY BLOCK*/
for(i= 0; i < num_blks; i ++) {
no_read = fread(out_buf,sizeof(char),MAXSIZE,fp);
if (no_read == 0) {printf("server: file read error\n");exit(0);}
if (no_read != MAXSIZE)
{printf("server: file read error : no_read is less\n");exit(0);}
if((writen(newsd,out_buf,MAXSIZE)) < 0)
{printf("server: error sending block:%d\n",errno);exit(0);}
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error :%d\n",errno);exit(0);}
if (ntohs(ack) != ACK) {
printf("server: ACK not received for block %d\n",i);
exit(0);
}
printf(" %d...",i);
}
if (num_last_blk > 0) {
printf("%d\n",num_blks);
no_read = fread(out_buf,sizeof(char),num_last_blk,fp);
if (no_read == 0) {printf("server: file read error\n");exit(0);}
if (no_read != num_last_blk)
{printf("server: file read error : no_read is less 2\n");exit(0);}
if((writen(newsd,out_buf,num_last_blk)) < 0)
{printf("server: file transfer error %d\n",errno);exit(0);}
if((readn(newsd,(char *)&ack,sizeof(ack))) < 0)
{printf("server: ack read error %d\n",errno);exit(0);}
if (ntohs(ack) != ACK) {
printf("server: ACK not received last block\n");
exit(0);
}
}
else printf("\n");
/* FILE TRANSFER ENDS */
printf("server: FILE TRANSFER COMPLETE on socket %d\n",newsd);
fclose(fp);
close(newsd);
}
/*
TO TAKE CARE OF THE POSSIBILITY OF BUFFER LIMMITS IN THE KERNEL FOR THE
SOCKET BEING REACHED (WHICH MAY CAUSE READ OR WRITE TO RETURN FEWER CHARACTERS
THAN REQUESTED), WE USE THE FOLLOWING TWO FUNCTIONS */
int readn(int sd,char *ptr,int size)
{ int no_left,no_read;
no_left = size;
while (no_left > 0)
{ no_read = read(sd,ptr,no_left);
if(no_read <0) return(no_read);
if (no_read == 0) break;
no_left -= no_read;
ptr += no_read;
}
return(size - no_left);
}
int writen(int sd,char *ptr,int size)
{ int no_left,no_written;
no_left = size;
while (no_left > 0)
{ no_written = write(sd,ptr,no_left);
if(no_written <=0) return(no_written);
no_left -= no_written;
ptr += no_written;
}
return(size - no_left);
}
No comments:
Post a Comment
Thank you