📄 tftp.erl
字号:
%%%-------------------------------------------------------------------%%% File : tftp.erl%%% Author : Hakan Mattsson <hakan@erix.ericsson.se>%%% Description : Trivial FTP%%% Created : 18 May 2004 by Hakan Mattsson <hakan@erix.ericsson.se>%%%-------------------------------------------------------------------%%% %%% This is a complete implementation of the following IETF standards:%%%%%% RFC 1350, The TFTP Protocol (revision 2).%%% RFC 2347, TFTP Option Extension.%%% RFC 2348, TFTP Blocksize Option.%%% RFC 2349, TFTP Timeout Interval and Transfer Size Options.%%%%%% The only feature that not is implemented in this release is%%% the "netascii" transfer mode.%%%%%% The start/1 function starts a daemon process which, listens for%%% UDP packets on a port. When it receives a request for read or%%% write it spawns a temporary server process which handles the%%% actual transfer of the file. On the client side the read_file/3%%% and write_file/3 functions spawns a temporary client process which%%% establishes contact with a TFTP daemon and performs the actual%%% transfer of the file.%%%%%% Most of the options are common for both the client and the server%%% side, but some of them differs a little. Here are the available%%% options:%%% %%% {debug, Level}%%%%%% Level = none | brief | normal | verbose | all%%% %%% Controls the level of debug printouts. The default is none.%%% %%% {host, Host}%%%%%% The name or IP address of the host where the TFTP daemon%%% resides. This option is only used by the client. See%%% 'inet' about valid host names.%%% %%% {port, Port}%%%%%% Port = integer()%%% %%% The TFTP port where the daemon listens. It defaults to the%%% standardized number 69. On the server side it may sometimes%%% make sense to set it to 0, which means that the daemon just%%% will pick a free port (which is returned by the start/1%%% function).%%% %%% If a socket has somehow already has been connected, the%%% {udp, [{fd, integer()}]} option can be used to pass the%%% open file descriptor to gen_udp. This can be automated%%% a bit by using a command line argument stating the%%% prebound file descriptor number. For example, if the%%% Port is 69 and the file descriptor 22 has been opened by%%% setuid_socket_wrap. Then the command line argument%%% "-tftpd_69 22" will trigger the prebound file%%% descriptor 22 to be used instead of opening port 69.%%% The UDP option {udp, [{fd, 22}]} autmatically be added.%%% See init:get_argument/ about command line arguments and%%% gen_udp:open/2 about UDP options.%%%%%% {port_policy, Policy}%%%%%% Policy = random | Port | {range, MinPort, MaxPort}%%% Port = MinPort = MaxPort = integer()%%% %%% Policy for the selection of the temporary port which is used%%% by the server/client during the file transfer. It defaults to%%% 'random' which is the standardized policy. With this policy a%%% randomized free port used. A single port or a range of ports%%% can be useful if the protocol should pass thru a firewall.%%% %%% {prebound_fd, InitArgFlag}%%%%%% InitArgFlag = atom()%%%%%% If a socket has somehow already has been connected, the%%% {udp, [{fd, integer()}]} option can be used to pass the%%% open file descriptor to gen_udp.%%%%%% The prebound_fd option makes it possible to pass give the%%% file descriptor as a command line argument. The typical%%% usage is when used in conjunction with setuid_socket_wrap%%% to be able to open privileged sockets. For example if the%%% file descriptor 22 has been opened by setuid_socket_wrap%%% and you have choosen my_tftp_fd as init argument, the%%% command line should like this "erl -my_tftp_fd 22" and %%% FileDesc should be set to my_tftpd_fd. This would %%% automatically imply {fd, 22} to be set as UDP option.%%% %%% {udp, UdpOptions}%%%%%% Options to gen_udp:open/2.%%%%%% {use_tsize, Bool}%%%%%% Bool = boolean()%%% %%% Flag for automated usage of the "tsize" option. With this set%%% to true, the write_file/3 client will determine the filesize%%% and send it to the server as the standardized "tsize" option.%%% A read_file/3 client will just acquire filesize from the%%% server by sending a zero "tsize".%%% %%% {max_tsize, MaxTsize}%%%%%% MaxTsize = integer() | infinity%%% %%% Threshold for the maximal filesize in bytes. The transfer will%%% be aborted if the limit is exceeded. It defaults to%%% 'infinity'.%%%%%% {max_conn, MaxConn}%%% %%% MaxConn = integer() | infinity%%% %%% Threshold for the maximal number of active connections. The%%% daemon will reject the setup of new connections if the limit%%% is exceeded. It defaults to 'infinity'.%%% %%% {TftpKey, TftpVal}%%%%%% TftpKey = string()%%% TftpVal = string()%%%%%% The name and value of a TFTP option.%%% %%% {reject, Feature}%%% %%% Feature = Mode | TftpKey%%% Mode = read | write%%% TftpKey = string()%%% %%% Control which features that should be rejected.%%% This is mostly useful for the server as it may restrict%%% usage of certain TFTP options or read/write access.%%%%%% {callback, {RegExp, Module, State}}%%%%%% RegExp = string()%%% Module = atom()%%% State = term()%%% %%% Registration of a callback module. When a file is to be%%% transferred, its local filename will be matched to the%%% regular expressions of the registered callbacks. The first%%% matching callback will be used the during the transfer.The%%% callback module must implement the 'tftp' behaviour.%%%%%% On the server side the callback interaction starts with a%%% call to open/5 with the registered initial callback%%% state. open/5 is expected to open the (virtual) file. Then%%% either the read/1 or write/2 functions are invoked%%% repeatedly, once per transfererred block. At each function%%% call the state returned from the previous call is%%% obtained. When the last block has been encountered the read/1%%% or write/2 functions is expected to close the (virtual)%%% file.and return its last state. The abort/3 function is only%%% used in error situations. prepare/5 is not used on the server%%% side.%%% %%% On the client side the callback interaction is the same, but%%% it starts and ends a bit differently. It starts with a call%%% to prepare/5 with the same arguments as open/5%%% takes. prepare/5 is expected to validate the TFTP options,%%% suggested by the user and return the subset of them that it%%% accepts. Then the options is sent to the server which will%%% perform the same TFTP option negotiation procedure. The%%% options that are accepted by the server is forwarded to the%%% open/5 function on the client side. On the client side the%%% open/5 function must accept all option as is or reject the%%% transfer. Then the callback interaction follows the same%%% pattern as described above for the server side. When the last%%% block is encountered in read/1 or write/2 the returned stated%%% is forwarded to the user and returned from read_file/3 or%%% write_file/3.%%%--------------------------------------------------------------------module(tftp).%%-------------------------------------------------------------------%% Interface%%-------------------------------------------------------------------%% public functions-export([ read_file/3, write_file/3, start/1, info/1, change_config/2, start/0 ]).-export([behaviour_info/1]).behaviour_info(callbacks) -> [{prepare, 6}, {open, 6}, {read, 1}, {write, 2}, {abort, 3}];behaviour_info(_) -> undefined.-include("tftp.hrl").%%-------------------------------------------------------------------%% read_file(RemoteFilename, LocalFilename, Options) ->%% {ok, LastCallbackState} | {error, Reason}%%%% RemoteFilename = string()%% LocalFilename = binary | string()%% Options = [option()]%% LastCallbackState = term()%% Reason = term()%%%% Reads a (virtual) file from a TFTP server%%%% If LocalFilename is the atom 'binary', tftp_binary will be used as%% callback module. It will concatenate all transferred blocks and%% return them as one single binary in the CallbackState.%%%% When LocalFilename is a string, it will be matched to the%% registered callback modules and hopefully one of them will be%% selected. By default, tftp_file will be used as callback module. It%% will write each transferred block to the file named%% LocalFilename. The number of transferred bytes will be returned as%% LastCallbackState.%%-------------------------------------------------------------------read_file(RemoteFilename, LocalFilename, Options) -> tftp_engine:client_start(read, RemoteFilename, LocalFilename, Options). %%-------------------------------------------------------------------%% write(RemoteFilename, LocalFilename, Options) ->%% {ok, LastCallbackState} | {error, Reason}%%%% RemoteFilename = string()%% LocalFilename = binary() | string()%% Options = [option()]%% LastCallbackState = term()%% Reason = term()%%%% Writes a (virtual) file to a TFTP server%% %% If LocalFilename is a binary, tftp_binary will be used as callback%% module. The binary will be transferred block by block and the number%% of transferred bytes will be returned as LastCallbackState.%%%% When LocalFilename is a string, it will be matched to the%% registered callback modules and hopefully one of them will be%% selected. By default, tftp_file will be used as callback module. It%% will read the file named LocalFilename block by block. The number%% of transferred bytes will be returned as LastCallbackState.%%-------------------------------------------------------------------write_file(RemoteFilename, LocalFilename, Options) -> tftp_engine:client_start(write, RemoteFilename, LocalFilename, Options).%%-------------------------------------------------------------------%% start(Options) -> {ok, Pid} | {error, Reason}%% %% Options = [option()]%% Pid = pid()%% Reason = term()%%%% Starts a daemon process which listens for udp packets on a%% port. When it receives a request for read or write it spawns%% a temporary server process which handles the actual transfer%% of the (virtual) file.%%-------------------------------------------------------------------start(Options) -> tftp_engine:daemon_start(Options).%%-------------------------------------------------------------------%% info(Pid) -> {ok, Options} | {error, Reason}%% %% Options = [option()]%% Reason = term()%%%% Returns info about a tftp daemon, server or client process%%-------------------------------------------------------------------info(Pid) -> tftp_engine:info(Pid).%%-------------------------------------------------------------------%% change_config(Pid, Options) -> ok | {error, Reason}%% %% Options = [option()]%% Reason = term()%%%% Changes config for a tftp daemon, server or client process%% Must be used with care.%%-------------------------------------------------------------------change_config(Pid, Options) -> tftp_engine:change_config(Pid, Options).%%-------------------------------------------------------------------%% start() -> ok | {error, Reason}%% %% Reason = term()%%%% Start the application%%-------------------------------------------------------------------start() -> application:start(inets).
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -