📄 tftpsrvr.c
字号:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#ifdef BUILD_WITH_VCC
#include <io.h>
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#define sleep(n) Sleep(n*1000)
#define SOCKET_INVALID(s) (s == INVALID_SOCKET)
typedef unsigned short ushort;
#else
#define INT int
#define SOCKET int
#ifndef O_BINARY
#define O_BINARY 0
#endif
#define SOCKET_INVALID(s) (s < 0)
#define SOCKADDR_IN struct sockaddr_in
#define PSOCKADDR struct sockaddr *
#define SetConsoleTitle(n)
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
#include "ttftp.h"
#define TFTP_BUSY 1
#define TFTP_IDLE 2
#define TFTP_GETLASTACK 3
int TftpState, msgCount, RRQfd, WRQfd;
char WRQfile[128], RRQfile[128];
#ifdef BUILD_WITH_VCC
HANDLE hdlTimer;
#else
pthread_t tidTimer;
#endif
void stopTimer(void);
void startTimer(void);
char *ServerTitleBar="TFTP SERVER";
extern int tftpSrvrTimeout, tftpVerbose;
int
tftpsrvr(void)
{
char rcvmsg[1024], sndmsg[1024], title[256];
char *WRQmode, *errmsg;
INT err, msglen, i, len, rcvtot;
SOCKET listener;
SOCKADDR_IN localAddr;
#ifdef BUILD_WITH_VCC
WSADATA WsaData;
#endif
ushort opcode, blockno, errcode;
char RRQmode[32];
#ifdef BUILD_WITH_VCC
err = WSAStartup (0x0101, &WsaData);
if (err == SOCKET_ERROR) {
fprintf (stdout, "WSAStartup Failed\n");
return(-1);
}
#endif
SetConsoleTitle(ServerTitleBar);
// Open a socket to listen for incoming connections.
listener = socket (AF_INET, SOCK_DGRAM, 0);
if (SOCKET_INVALID(listener)) {
fprintf (stdout, "Socket Create Failed\n");
return(-1);
}
// Bind our server to the TFTP port number.
memset ((char *)&localAddr, 0, sizeof (localAddr));
localAddr.sin_port = htons (IPPORT_TFTP);
localAddr.sin_family = AF_INET;
err = bind (listener, (PSOCKADDR) & localAddr, sizeof (localAddr));
if (SOCKET_INVALID(err)) {
fprintf (stderr,"Socket Bind Failed\n");
#ifdef BUILD_WITH_VCC
if (WSAGetLastError () == WSAEADDRINUSE)
fprintf (stderr,"The port number may already be in use.\n");
#endif
return(-1);
}
TftpState = TFTP_IDLE;
RRQfd = WRQfd = msgCount = 0;
while(1) {
msglen = sizeof(struct sockaddr);
i = recvfrom(listener,rcvmsg,sizeof(rcvmsg),0,
(struct sockaddr *)&localAddr,&msglen);
msgCount++;
opcode = ntohs(*(ushort *)rcvmsg);
switch(opcode) {
case TFTP_RRQ:
test_OpcodePassCount = 0;
strcpy(RRQfile,&rcvmsg[2]);
strcpy(RRQmode,&rcvmsg[strlen(RRQfile)+3]);
if (TftpState == TFTP_BUSY) {
printf("TFTP_RRQ rqst: %s (%s) failed, srvr busy\n",
RRQfile,RRQmode);
*(ushort *)sndmsg = htons(TFTP_ERR);
*(ushort *)&sndmsg[2] = htons(2);
strcpy(&sndmsg[4],"Server is busy");
len = 19;
blockno = 0;
goto tag1;
}
RRQfd = open(RRQfile,O_RDONLY | O_BINARY);
if (RRQfd == -1) {
printf("TFTP_RRQ rqst: %s (%s) failed, file not found\n",
RRQfile,RRQmode);
*(ushort *)sndmsg = htons(TFTP_ERR);
*(ushort *)&sndmsg[2] = htons(1);
strcpy(&sndmsg[4],"File not found");
len = 19;
blockno = 0;
}
else {
printf("TFTP transferring: %s (%s)\n",RRQfile,RRQmode);
sprintf(title,"TFTP_RRQ: %s",RRQfile);
SetConsoleTitle(title);
blockno = 1;
*(ushort *)sndmsg = htons(TFTP_DAT);
*(ushort *)&sndmsg[2] = htons(blockno);
len = read(RRQfd,&sndmsg[4],512);
if (len < 512) {
close(RRQfd);
RRQfd = 0;
printf("TFTP %s transfer complete\n",RRQfile);
SetConsoleTitle(ServerTitleBar);
TftpState = TFTP_GETLASTACK;
}
else {
TftpState = TFTP_BUSY;
startTimer();
}
if (len >= 0)
len += 4;
else
len = 4;
}
tag1:
testTftp(TFTP_RRQ,sndmsg,len);
if (sendto(listener,sndmsg,len,0,(struct sockaddr *)&localAddr,
sizeof(struct sockaddr)) < 0) {
perror("sendto failed");
return(EXIT_ERROR);
}
break;
case TFTP_ACK:
if (RRQfd == -1)
break;
if (TftpState == TFTP_GETLASTACK) {
TftpState = TFTP_IDLE;
break;
}
if (tftpVerbose)
printf("Rcvd TFTP_ACK blk#%d\n",htons(*(ushort *)&rcvmsg[2]));
if (*(ushort *)&rcvmsg[2] == htons(blockno)) {
blockno++;
*(ushort *)sndmsg = htons(TFTP_DAT);
*(ushort *)&sndmsg[2] = htons(blockno);
len = read(RRQfd,&sndmsg[4],512);
if (len < 512) {
close(RRQfd);
}
if (len >= 0)
len += 4;
else {
TftpState = TFTP_IDLE;
printf("TFTP %s transfer completed\n",RRQfile);
SetConsoleTitle(ServerTitleBar);
RRQfd = 0;
stopTimer();
continue;
}
}
else {
*(ushort *)sndmsg = htons(TFTP_ERR);
*(ushort *)&sndmsg[2] = htons(2);
strcpy(&sndmsg[4],"Ack confused");
len = 17;
}
testTftp(TFTP_ACK,sndmsg,len);
if (sendto(listener,sndmsg,len,0,(struct sockaddr *)&localAddr,
sizeof(struct sockaddr)) < 0) {
perror("sendto failed");
return(EXIT_ERROR);
}
break;
case TFTP_WRQ:
test_OpcodePassCount = 0;
strcpy(WRQfile,&rcvmsg[2]);
WRQmode = &rcvmsg[2];
while(*WRQmode) WRQmode++;
WRQmode++;
if (TftpState == TFTP_BUSY) {
printf("TFTP_WRQ rqst: %s (%s) failed, srvr busy\n",
WRQfile,WRQmode);
*(ushort *)sndmsg = htons(TFTP_ERR);
*(ushort *)&sndmsg[2] = htons(2);
strcpy(&sndmsg[4],"Server is busy");
len = 19;
blockno = 0;
goto tag2;
}
if (strcmp(WRQmode,"octet")) {
fprintf(stderr,"%s: %s mode not supported\n",WRQfile,WRQmode);
break;
}
printf("TFTP receiving: '%s'\n",WRQfile);
unlink(WRQfile);
if ((WRQfd = open(WRQfile,O_WRONLY|O_BINARY|O_TRUNC|O_CREAT,0777))==-1) {
perror(WRQfile);
break;
}
TftpState = TFTP_BUSY;
sprintf(title,"TFTP_WRQ: %s",WRQfile);
SetConsoleTitle(title);
startTimer();
rcvtot = 0;
*(ushort *)sndmsg = htons(TFTP_ACK);
*(ushort *)&sndmsg[2] = 0;
len = 4;
tag2:
testTftp(TFTP_WRQ,sndmsg,len);
if (sendto(listener,sndmsg,len,0,(struct sockaddr *)&localAddr,
sizeof(struct sockaddr)) < 0) {
perror("sendto (TFTP_ACK) failed");
return(EXIT_ERROR);
}
break;
case TFTP_DAT:
if (tftpVerbose)
printf("Rcvd TFTP_DAT\n");
if ((i-4) > 0) {
if (write(WRQfd,&rcvmsg[4],i-4) != i - 4) {
perror("write (TFTP_DAT) failed");
return(EXIT_ERROR);
}
rcvtot += (i-4);
if ((i-4) != 512) {
TftpState = TFTP_IDLE;
close(WRQfd);
printf("Receive completed (%d bytes).\n",rcvtot);
SetConsoleTitle(ServerTitleBar);
stopTimer();
}
}
*(ushort *)sndmsg = htons(TFTP_ACK);
sndmsg[2] = rcvmsg[2]; /* Copy blockno for ack. */
sndmsg[3] = rcvmsg[3];
len = 4;
testTftp(TFTP_DAT,sndmsg,len);
if (sendto(listener,sndmsg,len,0,(struct sockaddr *)&localAddr,
sizeof(struct sockaddr)) < 0) {
perror("sendto (TFTP_ACK) failed");
return(EXIT_ERROR);
}
break;
case TFTP_ERR:
testTftp(TFTP_ERR,0,0);
errcode = htons(*(ushort *)&rcvmsg[2]);
errmsg = &rcvmsg[4];
close(RRQfd);
RRQfd = 0;
if (errcode != 0)
printf("Incoming ERROR %d: <%s>\n",errcode, errmsg);
}
}
return(EXIT_SUCCESS);
}
// TimerThread:
// This is used to kick off a timer that will keep track of the msgCount
// value and the TftpState variable. It is started when WRQ or RRQ is
// received; then, every 5 seconds TftpState is polled. If the state is
// busy, and tftpSrvrTimeout seconds have elapsed without a change in
// msgCount, then assume that the client went away and clear the busy state.
// If not busy, then assume the transaction has completed and terminate.
//
#ifdef BUILD_WITH_VCC
DWORD WINAPI timerThread(LPVOID notusedhere)
#else
void *timerThread(void *notusedhere)
#endif
{
int lastcount, no_activity_time;
/* Don't use the timer thread if a test is active. */
if (test_Opcode)
return(0);
no_activity_time = 0;
while(1) {
sleep(5);
if (TftpState == TFTP_BUSY) {
if (lastcount == msgCount) {
no_activity_time += 5;
if (no_activity_time == 5)
fprintf(stderr,"TFTP server waiting for response");
else
fprintf(stderr,".");
}
else {
lastcount = msgCount;
no_activity_time = 0;
}
if (no_activity_time >= tftpSrvrTimeout) {
fprintf(stderr,"\nTFTP timeout");
if (RRQfd > 0) {
close(RRQfd);
fprintf(stderr,", RRQ of %s aborted",RRQfile);
}
if (WRQfd > 0) {
close(WRQfd);
fprintf(stderr,
", WRQ of %s aborted (file prematurely truncated)",
WRQfile);
}
fprintf(stderr,".\n");
TftpState = TFTP_IDLE;
SetConsoleTitle(ServerTitleBar);
stopTimer(); /* Doesn't return, it kills this thread. */
}
}
else {
if (no_activity_time > 0)
fprintf(stderr,"\n");
stopTimer(); /* Doesn't return, it kills this thread. */
}
}
return(0); /* Should never get here. */
}
#ifdef BUILD_WITH_VCC
void
startTimer(void)
{
DWORD tid;
/* Don't use the timer thread if a test is active. */
if (test_Opcode)
return;
hdlTimer = CreateThread(NULL,0,timerThread,(LPVOID)0,CREATE_SUSPENDED,&tid);
if (!hdlTimer) {
perror("CreatThread()");
return;
}
ResumeThread(hdlTimer);
}
void
stopTimer(void)
{
/* Don't use the timer thread if a test is active. */
if (test_Opcode)
return;
if (hdlTimer) {
if (TerminateThread(hdlTimer,1) == FALSE) {
fprintf(stderr,"Thread termination failed\n");
return;
}
}
}
#else
void
startTimer(void)
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr,0x8000);
pthread_create(&tidTimer,&attr,timerThread,(void *)0);
}
void
stopTimer(void)
{
if (tidTimer != (pthread_t)NULL) {
pthread_cancel(tidTimer);
tidTimer = (pthread_t)NULL;
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -