tftp-server2.c
来自「socket编程, 查看server下相应目录的所有文件, 并且可通过tftp下」· C语言 代码 · 共 314 行
C
314 行
/* TFTP-server1.c
*
* this is a server that recives UDP frames and the sends a talkback
* signal to the clients specific frame changes with an ACK.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/*******************************************
* Structure declarations for the format
* of the TFTP list system
******************************************/
struct tftp_list
{
unsigned short id_Number;
char TFTPlist_type;
char TFTPlist_ack;
unsigned short block_Number;
char TFTPlist_cmd[4];
};
/*******************************************
* This function reports the error and
* exits back to the shell :
******************************************/
static void bail(const char *on_what)
{
fputs(strerror(errno),stderr);
fputs(": ",stderr);
fputs(on_what,stderr);
fputc('\n',stderr);
exit(1);
}
/*******************************************
* Function to form a frame
* arguments include:
* STRUCT frame type
* SHORT ID number
* CHAR U or T UDP or TCP
* CHAR A only used by Server as ACK
* SHORT block number for data frames
* CHAR[4] command string LIST/GET/PUT
******************************************/
int format_frame( struct tftp_list *frame, short *id, char t, char a,
short *bk, char *cmd )
{
frame->id_Number = *id;
frame->TFTPlist_type = t;
frame->TFTPlist_ack = a;
frame->block_Number = *bk;
strncpy (frame->TFTPlist_cmd, cmd, 4);
return (0);
}
/*******************************************
* Function to print a frame
* arguments include:
* STRUCT frame type
******************************************/
int print_frame( struct tftp_list *frame )
{
unsigned short i;
printf("[%d]", frame->id_Number);
printf("[%c]", frame->TFTPlist_type);
printf("[%c]", frame->TFTPlist_ack);
printf("[%d]", frame->block_Number);
printf("[");
for(i=0; i<4;i++) printf("%c", frame->TFTPlist_cmd[i]);
printf("]\n");
}
/*******************************************
* This function reads a directory and
* places the result into a text file
* parameters include:
* char * dirName
* char * sFileOut
******************************************/
void ReadDirectory(char * dirName, char * fileName)
{
FILE *fileOut;
struct dirent **namelist;
int n,c;
if((fileOut=fopen(fileName,"w"))==NULL)
bail("B1 cannot open dierctory listing output file");
n = scandir( dirName, &namelist, 0, alphasort);
if (n < 0) bail("scandir");
else
{
c=2;
while((c)<(n))
{
// printf("%d\t%s\n", c-1, namelist[c]->d_name);
fprintf(fileOut, "%d\t%s\n",c-1, namelist[c]->d_name);
free(namelist[c++]);
}
free(namelist);
}
fclose(fileOut);
}
/*******************************************
* this is the main body of the program with
* a simple state machine
******************************************/
int main(int argc,char **argv)
{
FILE *fileListIn;
int z, x, iLen, iLoop;
char cBuf1[512],cBuf2[512], ptrChar, cChar;
int RxSocket, TxSocket;
struct sockaddr_in server_address, client_address;
char *srvr_addr = "IPADDR_ANY";
char *ListFileName="LIST.OUT", *tftpDIR="/tftpboot";
unsigned int addr_len;
unsigned short srvr_port, iID, *ptr, iBlockNumber, iExit;
struct tftp_list tftp_list_frame, *ptrFrame;
time_t CurrentTime, CheckTime;
long lFlags, lFlagsOld;
printf("-------------------------------------------------\n");
printf("TFTP list server\n");
printf("-------------------------------------------------\n");
printf("usage: TFTP-server <port>\n");
printf("the port can be omitted and the program defaults \n");
printf("to UDP port 6969\n");
printf("-------------------------------------------------\n");
if( argc == 2 ) srvr_port = atoi(argv[1]);
else srvr_port = 6969;
printf("port is %d\n", srvr_port );
memset( &cBuf1, 0, sizeof cBuf1);
ptrFrame = (struct tftp_list *) &cBuf1[0];
//setting RX socket in here - Blocking
memset( &server_address, 0, sizeof server_address);
addr_len = sizeof(server_address);
srvr_addr = "192.168.0.203";
server_address.sin_family = AF_INET;
server_address.sin_port = htons(srvr_port);
server_address.sin_addr.s_addr= inet_addr(srvr_addr);
RxSocket = socket(AF_INET,SOCK_DGRAM,0);
if(z == -1) bail("01 error in creating a socket");
z = bind(RxSocket, (struct sockaddr *)&server_address, addr_len);
if(z == -1) bail("02 could not bind to address and port");
//get flags for socket - blocking work
lFlagsOld = fcntl(RxSocket, F_GETFL);
while (1)
{
//set RX socket to BLOCKing modes
lFlags = lFlagsOld;
if(fcntl(RxSocket, F_SETFL, lFlags)==-1 )
bail("02.5 error setting RX flags");
printf("-------------------------------------------------\n");
printf("Waiting... (blocking)...\n");
printf("-------------------------------------------------\n");
//RX frame from a cleint
memset( &cBuf1, 0, sizeof cBuf1);
z = recvfrom(RxSocket, cBuf1, 22, 0, (struct sockaddr *) &client_address, &addr_len );
if(z == -1) bail("03 receive error");
//Display RX'ed frame
ptrFrame = (struct tftp_list *) &cBuf1;
printf("RX frame\t"); print_frame( ptrFrame );
printf("To make server multi threaded put fork in here..\n");
//clear buffer
memset( &cBuf2, 0, sizeof cBuf2);
//show IP of sender (not rearly needed but just for reference
sprintf(cBuf2, "%s:%d", inet_ntoa(client_address.sin_addr), srvr_port );
printf("return address\t[%s]\n", cBuf2);
// override port talk back on standard port number 6969
client_address.sin_port = htons(srvr_port);
if (z == -1) bail("04 Bad address");
TxSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(z == -1) bail("05 error in creating a socket");
ptrFrame = (struct tftp_list *) cBuf1;
//Set ACK in the frame
ptrFrame->TFTPlist_ack = 'A';
printf("-------------------------------------------------\n");
printf("TX frame\t"); print_frame ( ptrFrame );
//sleep (1L);
//Send frame
z = sendto(TxSocket,cBuf1,22,0,(struct sockaddr *)&client_address, addr_len);
//Reread the contents of the directory
ReadDirectory( tftpDIR, ListFileName);
iBlockNumber = 1;
//create non blocking socket
lFlags = lFlagsOld;
lFlags |= O_NONBLOCK;
if(fcntl(RxSocket, F_SETFL, lFlags)==-1 )
bail("08 error setting RX flags");
//Opne the temp file with LIST information in it
if((fileListIn=fopen(ListFileName, "r")) ==NULL)
bail ("09 cannot read the LIST temp file");
iExit = 0;
//start loop for number of blocks to TX
while(!iExit)
{
// clear the payload portion of the frame
for(iLoop=10; iLoop<512; iLoop++) cBuf1[iLoop]=0;
ptrFrame = (struct tftp_list *) &cBuf1[0];
ptrFrame->block_Number = iBlockNumber;
ptrFrame->TFTPlist_ack = ' ';
client_address.sin_port = htons(srvr_port);
//get 502 bytes from DIR file list
for (iLoop=0; iLoop<502; iLoop++)
{
cChar = fgetc(fileListIn);
if (cChar != EOF)
{
cBuf1[10+iLoop] = cChar;
// printf("%c ", cChar);
}
else
{
cBuf1[10+iLoop] = cChar;
iExit = 1;
break;
}
}
printf("\n");
//transmit the frame
printf("-------------------------------------------------\n");
ptrFrame = (struct tftp_list *) &cBuf1;
printf("TX data frame : "); print_frame( ptrFrame );
printf("client addr\t%s port %d\n", inet_ntoa(client_address.sin_addr),
ntohs(client_address.sin_port) );
z = sendto(TxSocket,cBuf1,512,0,(struct sockaddr *)&client_address, addr_len);
if(z == -1) bail ("10 Error transmitting data block");
//Wait for 2 seconds for an ACK else EXIT
time(&CheckTime);
z=-1; iLoop=0;
memset(&cBuf2,0,sizeof cBuf2);
while ( ((CheckTime+2) > time(&CurrentTime)) && (z==(-1)) )
{
z = recvfrom(RxSocket,cBuf2,22,0,(struct sockaddr *)&client_address, &addr_len);
printf("\r%d %d",iLoop++, z);
}
printf("\n");
ptrFrame = (struct tftp_list *) &cBuf2[0];
//error if timeout then no ACK received
if(z<=0)
{
printf("\tNot received an ACK to TX data frame resetting\n");
iExit = 1;
}
//if not correct block number or an ACK exit
else if((ptrFrame->block_Number!=iBlockNumber) || (ptrFrame->TFTPlist_ack!='A'))
{
printf("RX ACK frame : "); print_frame ( ptrFrame );
printf("\tBlock number on ACK does not match or Not Ack in frame\n");
printf("\tBlock number should be %d and is %d\n", iBlockNumber, ptrFrame->block_Number );
iExit = 1;
}
else
{
printf("RX ACK frame : "); print_frame ( ptrFrame );
printf("\tACK Frame received and is ok\n");
printf("\tBlock number should be %d and is %d\n", iBlockNumber, ptrFrame->block_Number );
iBlockNumber++;
}
} // end while for TX as many blocks as needed
if (cChar == EOF)
{
printf("\tSending MAX block\n");
for(iLoop=10; iLoop<512; iLoop++) cBuf1[iLoop] = 0;
ptrFrame = (struct tftp_list *) &cBuf1[0];
ptrFrame->block_Number = 65535;
ptrFrame->TFTPlist_ack = ' ';
client_address.sin_port = htons(srvr_port);
z = sendto(TxSocket,cBuf1,22,0,(struct sockaddr *)&client_address, addr_len);
if(z == -1) bail ("10 Error transmitting data block");
}
fclose(fileListIn);
printf("Resetting server\n");
}
close (RxSocket);
close (TxSocket);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?