📄 tftpsrv.c
字号:
/* tftpsrv.c
Copyright 1998 by InterNiche Technologies Inc. All rights reserved.
Copyright 1995 by NetPort Software.
Copyright 1986 by Carnegie Mellon
Copyright 1984 by the Massachusetts Institute of Technology
TFTP server code - uses common code in tftputil.c and udp
interface in tftpudp.c
*/
#include "tftpport.h"
#ifdef TFTP_SERVER
#include "tftp.h"
void * tftpsconn = NULL; /* server UDPCONN or socket */
static int (*tfs_alert)(ip_addr,char*,unshort); /* security callback */
static int (*tfs_done)(int status, struct tfconn *, char*); /* transfer complete callback */
extern int ntftps;
int tftp_server_on = FALSE;
u_long refusedt = 0; /* time of most recent transfer refusal */
/* tfsinit(alert, done) - initialize the tftp server. This opens a UDP
connection but does not turn on the server. That needs to done by
an explicit call to tfs_on().
alert() is a function which the server will call whenever it receives
request for a transfer. This function will be called int he following
way:
alert(ip_addr, file_name, direction)
alert() should return TRUE if it wishes to allow the transfer and
FALSE otherwise.
done() is a function that the server will
call to inform the invoker that this file transfer is complete or
aborted.
*/
int
tfsinit(
int (*alert)(ip_addr, char*, unshort), /* notification callback */
int (*done)(int, struct tfconn *, char*)) /* transfer complete callback */
{
unshort lport = TFTPPORT; /* for pass to tftp_udplisten() */
/* open server tftp connection to receive incoming requests
with wildcard foriegn host & wildcard foriegn port */
tftpsconn = tftp_udplisten(0L, 0, &lport, TFTPSERVER);
if(!tftpsconn)
return ENP_RESOURCE;
tfs_done = done;
tfs_alert = alert;
return 0;
}
/* turn the tftp server on
*/
void
tfs_on()
{
tftp_server_on = TRUE;
}
/* turn the tftp server off
*/
void
tfs_off()
{
tftp_server_on = FALSE;
}
/* tfshnd() - handle an initial incoming tftp packet.
This involves opening a udp connection (immediately so that we can
report errors). If the server is OFF then the tftp will be refused;
otherwise more checking will be done. Call the alert function and
verify that the "user" wishes to allow the tftp. Report an error if
not. Finally, spawn a session to oversee the tftp and cleanup when
it's done.
Returns 0 if OK, else ENP error code.
*/
int
tfshnd(ip_addr host, unshort fport, char * udata)
{
struct tfreq *ptreq;
char *file, *smode, *tmp;
struct tfconn *cn = NULL;
unsigned mode;
int e = 0; /* error value to return */
/* Do we have room to do this transfer? */
if(ntftps >= MAXTFTPS)
{
dprintf("TFTP Serve: Ignoring req, too many connections\n");
return ENP_RESOURCE;
}
ptreq = (struct tfreq *)udata;
ptreq->tf_op = htons(ptreq->tf_op);
if(ptreq->tf_op > TF_WRQ)
{
dprintf("TFTP Server: bad init opcode %u\n", ptreq->tf_op);
return ENP_LOGIC;
}
file = (char*)&ptreq->tf_name[0];
smode = file + strlen(file)+1;
for(tmp = smode; *tmp; tmp++)
if(*tmp >= 'A' && *tmp <= 'Z') *tmp += 32;
cn = tfmkcn(); /* make conn now in case we send errors */
if(cn == 0)
{
dprintf("TFTP Server: session Alloc failed\n");
return ENP_RESOURCE;
}
cn->tf_start = cticks;
cn->tf_fhost = host;
cn->tf_fport = fport;
cn->tf_lport = TFTPPORT; /* errors come from std port for now */
if(strcmp(smode, "image") == 0) mode = OCTET;
else if(strcmp(smode, "octet") == 0) mode = OCTET;
else if(strcmp(smode, "netascii") == 0) mode = ASCII;
else
{
dprintf("TFTP Server: Bad mode %s in req\n", smode);
tfsnderr(cn, ERRTXT, "Bad mode");
tfcleanup(cn);
return ENP_LOGIC;
}
if(tftp_server_on != TRUE)
{
dprintf("TFTP Server: got req while off\n");
tfsnderr(cn, ERRTXT, "Transfers currently disabled.");
tfcleanup(cn);
return 0; /* this is not an error */
}
if(tfs_alert)
{
int code;
code = (*tfs_alert)(host, file,
(unshort)(ptreq->tf_op == TF_RRQ ? PUT : GET) );
if(code == 0)
{
tfsnderr(cn, ERRTXT, "Transfer refused.");
refusedt = cticks;
tfcleanup(cn);
return 0;
}
}
cn->tf_lport = 0; /* let UDP select local port */
/* open a UDP connection for data transfer with this host */
cn->tf_conn = tftp_udplisten(host, fport, &cn->tf_lport, (void*)cn);
if(cn->tf_conn == NULL)
{
dprintf("TFTP Server: UDP listen error\n");
tfcleanup(cn);
return ENP_RESOURCE;
}
cn->tf_mode = mode;
if(ptreq->tf_op == TF_RRQ)
{
cn->tf_dir = PUT;
if(cn->tf_mode == ASCII) /* let file sys handle netascii */
cn->tf_fd = vfopen(file, "r");
else
cn->tf_fd = vfopen(file, "rb");
if(cn->tf_fd == NULL)
{
dprintf("TFTP server: couldn't open file\n");
tfsnderr(cn, FNOTFOUND, " ");
(*tfs_done)(TFC_FILEOPEN, cn, file);
tfcleanup(cn);
return ENP_FILEIO;
}
cn->tf_state = RCVACK; /* consider request to first ack */
cn->tf_expected = 1; /* start with block number 1 */
cn->callback = tfs_done;
cn->tf_flen = NORMLEN;
}
else /* get request */
{
cn->tf_dir = GET;
if(cn->tf_mode == ASCII) /* let file sys handle netascii */
cn->tf_fd = vfopen(file, "w");
else
cn->tf_fd = vfopen(file, "wb");
if(cn->tf_fd == NULL)
{
dprintf("TFTP Server: couldn't open file\n");
tfsnderr(cn, ACCESS, " ");
(*tfs_done)(TFC_FILEOPEN, cn, file);
tfcleanup(cn);
return ENP_FILEIO;
}
cn->tf_expected = 0; /* ack block number 0 */
e = tfsndack(cn);
cn->tf_expected = 1; /* start with block number 1 */
cn->tf_state = DATAWAIT;
cn->callback = tfs_done;
}
return e; /* OK return */
}
#endif /* TFTP_SERVER */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -