Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
Nodemcu Firmware
Commits
8d091c47
Commit
8d091c47
authored
Jun 03, 2020
by
Marcel Stör
Browse files
Make the telnet example an Lua module (#3133)
Also update ftp server
parent
f20591a8
Changes
6
Show whitespace changes
Inline
Side-by-side
lua_examp
les/telnet
/README
.md
→
docs/lua-modu
les/telnet.md
View file @
8d091c47
...
@@ -2,21 +2,15 @@
...
@@ -2,21 +2,15 @@
| Since | Origin / Contributor | Maintainer | Source |
| Since | Origin / Contributor | Maintainer | Source |
| :----- | :-------------------- | :---------- | :------ |
| :----- | :-------------------- | :---------- | :------ |
| 2014-12-22 |
[
Zeroday
](
https://github.com/funshine
)
|
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
simple_telnet.lua
](
./simple_telnet.lua
)
|
| 2018-05-24 |
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
telnet.lua
](
../../lua_modules/telnet/telnet.lua
)
|
| 2018-05-24 |
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
Terry Ellison
](
https://github.com/TerryE
)
|
[
telnet.lua
](
./telnet.lua
)
|
The current version of this module exploits the stdin / stdout pipe functionality and
This README discusses the packet marshalling versions of telnet. The first (fifosock)
task integration that is now build into the NodeNMCU Lua core.
version was written for SDK 2 implementations, with all of the marshalling imlemented
in Lua; the second (pipe) version uses the latest features added to the SDK 3 version
that have been added to prepare for the
`lua53`
implementation. These exploit the
stdin / stdout pipe functionality and task integration that is now build into the
NodeNMCU Lua core.
There are two nice advantages of this core implementation:
There are two nice advantages of this core implementation:
-
Errors are now written to stdout in a s
p
earate task execution.
-
Errors are now written to stdout in a se
p
arate task execution.
-
The pipes pretty much eliminate
uart
and telnet overrun.
-
The pipes pretty much eliminate
UART
and telnet overrun.
Both have the same interface if required into the variable
`telnet`
Both have the same interface if required into the variable
`telnet`
...
@@ -31,13 +25,13 @@ Open a telnet server based on the provided parameters.
...
@@ -31,13 +25,13 @@ Open a telnet server based on the provided parameters.
#### Parameters
#### Parameters
`ssid`
and
`password`
. Strings. SSID and Password for the Wifi network. If these are
`ssid`
and
`password`
. Strings. SSID and Password for the Wifi network. If these are
`nil`
then the wifi is assumed to be configured or autoconfigured.
`nil`
then the wifi is assumed to be configured or auto
-
configured.
`port`
. Integer TCP listen
t
ing port for the Telnet service. The default is 2323
`port`
. Integer TCP listening port for the Telnet service. The default is 2323
#### Returns
#### Returns
Nothing returned (this is evaluted as
`nil`
in a scalar context).
Nothing returned (this is evalu
a
ted as
`nil`
in a scalar context).
## telnet:close()
## telnet:close()
...
@@ -53,4 +47,4 @@ None
...
@@ -53,4 +47,4 @@ None
#### Returns
#### Returns
Nothing returned (this is evaluted as
`nil`
in a scalar context).
Nothing returned (this is evalu
a
ted as
`nil`
in a scalar context).
lua_examples/telnet/telnet_fifosock.lua
deleted
100644 → 0
View file @
f20591a8
--[[ A telnet server T. Ellison, May 2018
This version is more complex than the simple Lua example previously provided in our
distro. The main reason is that a single Lua command can produce a LOT of output,
and the server has to work within four constraints:
- The SDK rules are that you can only issue one send per task invocation, so any
overflow must be buffered, and the buffer emptied using an on:sent cb
- Since the interpeter invokes a node.output cb per field, you have a double
whammy that these fields are typically small, so using a simple array FIFO
would rapidly exhaust RAM.
- For network efficiency, you want to aggregate any FIFO buffered into sensible
sized packet, say 1024 bytes, but you also need to handle the case when larger
string span multiple packets. However, you must flush the buffer if necessary.
- The overall buffering strategy needs to be reasonably memory efficient and avoid
hitting the GC too hard, so where practical avoid aggregating small strings to
more than 256 chars (as NodeMCU handles <256 using stack buffers), and avoid
serial aggregation such as buf = buf .. str as this hammers the GC.
So this server adopts a simple buffering scheme using a two level FIFO. The node.output
cb adds cb records to the 1st level FIFO until the #recs is > 32 or the total size
would exceed 256 bytes. Once over this threashold, the contents of the FIFO are
concatenated into a 2nd level FIFO entry of upto 256 bytes, and the 1st level FIFO
cleared down to any residue.
]]
--luacheck: no unused args
local
node
,
tmr
,
wifi
,
uwrite
=
node
,
tmr
,
wifi
,
uart
.
write
local
function
telnet_listener
(
socket
)
local
queueLine
=
(
require
"fifosock"
).
wrap
(
socket
)
local
function
receiveLine
(
s
,
line
)
node
.
input
(
line
)
end
local
function
disconnect
(
s
)
socket
:
on
(
"disconnection"
,
nil
)
socket
:
on
(
"reconnection"
,
nil
)
socket
:
on
(
"connection"
,
nil
)
socket
:
on
(
"receive"
,
nil
)
socket
:
on
(
"sent"
,
nil
)
node
.
output
(
nil
)
end
socket
:
on
(
"receive"
,
receiveLine
)
socket
:
on
(
"disconnection"
,
disconnect
)
node
.
output
(
queueLine
,
0
)
print
((
"Welcome to NodeMCU world (%d mem free, %s)"
):
format
(
node
.
heap
(),
wifi
.
sta
.
getip
()))
end
local
listenerSocket
return
{
open
=
function
(
this
,
ssid
,
pwd
,
port
)
if
ssid
then
wifi
.
setmode
(
wifi
.
STATION
,
false
)
wifi
.
sta
.
config
{
ssid
=
ssid
,
pwd
=
pwd
,
save
=
false
}
end
local
t
=
tmr
.
create
()
t
:
alarm
(
500
,
tmr
.
ALARM_AUTO
,
function
()
if
(
wifi
.
sta
.
status
()
==
wifi
.
STA_GOTIP
)
then
t
:
unregister
()
t
=
nil
print
((
"Telnet server started (%d mem free, %s)"
):
format
(
node
.
heap
(),
wifi
.
sta
.
getip
()))
net
.
createServer
(
net
.
TCP
,
180
):
listen
(
port
or
23
,
telnet_listener
)
else
uwrite
(
0
,
"."
)
end
end
)
end
,
close
=
function
(
this
)
if
listenerSocket
then
listenerSocket
:
close
()
package.loaded
.
telnet
=
nil
listenerSocket
=
nil
collectgarbage
()
end
end
,
}
lua_modules/ftp/ftpserver.lua
View file @
8d091c47
--[[SPLIT MODULE ftp]]
--[[ A simple ftp server
--[[ A simple ftp server
This is my implementation of a FTP server using Github user Neronix's
This is my implementation of a FTP server using Github user Neronix's
example as inspriration, but as a cleaner Lua implementation that
has been
example as inspriration, but as a cleaner Lua implementation that
is
optimised
for use in LFS. The coding style adopted here is more similar to
suitable
for use in LFS. The coding style adopted here is more similar to
best practice for normal (PC) module implementations, as using LFS enables
best practice for normal (PC) module implementations, as using LFS enables
me to bias towards clarity of coding over brevity. It includes extra logic
me to bias towards clarity of coding over brevity. It includes extra logic
to handle some of the edge case issues more robustly. It also uses a
to handle some of the edge case issues more robustly. It also uses a
...
@@ -13,113 +15,116 @@
...
@@ -13,113 +15,116 @@
with any multiple calls requected, so FTP is a singleton static object.
with any multiple calls requected, so FTP is a singleton static object.
However there is nothing to stop multiple clients connecting to the FTP
However there is nothing to stop multiple clients connecting to the FTP
listener at the same time, and indeed some FTP clients do use multiple
listener at the same time, and indeed some FTP clients do use multiple
connections, so this server can accept and create multiple
CON
objects.
connections, so this server can accept and create multiple
cxt
objects.
Each
CON
object can also have a single DATA connection.
Each
cxt
object can also have a single DATA connection.
Note that FTP also exposes a number of really private properties (which
Note that FTP also exposes a number of really private properties (which
could be stores in local / upvals) as FTP properties for debug purposes.
could be stores in local / upvals) as FTP properties for debug purposes.
Note that this version has now been updated to allow the main methods to
be optionally loaded lazily, and SPILT comments allow the source to be
preprocessed for loading as either components in the "fast" Cmodule or as
LC files in SPIFFS.
]]
]]
local
file
,
net
,
wifi
,
node
,
table
,
tmr
,
pairs
,
print
,
pcall
,
tostring
=
--luacheck: read globals fast file net node tmr uart wifi FAST_ftp SPIFFS_ftp
file
,
net
,
wifi
,
node
,
table
,
tmr
,
pairs
,
print
,
pcall
,
tostring
local
post
=
node
.
task
.
post
local
FTP
,
FTPindex
=
{
client
=
{}},
nil
local
FTP
,
cnt
=
{
client
=
{}},
0
if
FAST_ftp
then
-- Local functions
function
FTPindex
(
_
,
name
)
return
fast
.
load
(
'ftp-'
..
name
)
end
elseif
SPIFFS_ftp
then
local
processCommand
-- function(cxt, sock, data)
function
FTPindex
(
_
,
name
)
return
loadfile
(
'ftp-'
..
name
..
'.lc'
)
end
local
processBareCmds
-- function(cxt, cmd)
local
processSimpleCmds
-- function(cxt, cmd, arg)
local
processDataCmds
-- function(cxt, cmd, arg)
local
dataServer
-- function(cxt, n)
local
ftpDataOpen
-- function(dataSocket)
-- Note these routines all used hoisted locals such as table and debug as
-- upvals for performance (ROTable lookup is slow on NodeMCU Lua), but
-- data upvals (e.g. FTP) are explicitly list is -- "upval:" comments.
-- Note that the space between debug and the arglist is there for a reason
-- so that a simple global edit " debug(" -> "-- debug(" or v.v. to
-- toggle debug compiled into the module.
local
function
debug
(
fmt
,
...
)
-- upval: cnt (, print, node, tmr)
if
not
FTP
.
debug
then
return
end
if
(
...
)
then
fmt
=
fmt
:
format
(
...
)
end
print
(
node
.
heap
(),
fmt
)
cnt
=
cnt
+
1
if
cnt
%
10
then
tmr
.
wdclr
()
end
end
end
if
FTPindex
then
return
setmetatable
(
FTP
,{
__index
=
FTPindex
})
end
function
FTP
.
open
(
...
)
--[[SPLIT HERE ftp-open]]
--------------------------- Set up the FTP object ----------------------------
--------------------------- Set up the FTP object ----------------------------
-- FTP has three static methods: open, createServer and close
-- FTP has three static methods: open, createServer and close
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- optional wrapper around createServer() which also starts the wifi session
-- optional wrapper around createServer() which also starts the wifi session
function
FTP
.
open
(
user
,
pass
,
ssid
,
pwd
,
dbgFlag
)
-- upval: FTP (, wifi, tmr, print)
-- Lua: FTP:open(user, pass, ssid, pwd[, dbgFlag])
local
this
,
user
,
pass
,
ssid
,
pwd
,
dbgFlag
=
...
if
ssid
then
if
ssid
then
wifi
.
setmode
(
wifi
.
STATION
,
false
)
wifi
.
setmode
(
wifi
.
STATION
,
false
)
wifi
.
sta
.
config
{
ssid
=
ssid
,
pwd
=
pwd
,
save
=
false
}
wifi
.
sta
.
config
{
ssid
=
ssid
,
pwd
=
pwd
,
save
=
false
}
end
end
local
t
=
tmr
.
create
()
tmr
.
create
():
alarm
(
500
,
tmr
.
ALARM_AUTO
,
function
(
t
)
-- this: FTP, user, pass, dbgFlag
t
:
alarm
(
500
,
tmr
.
ALARM_AUTO
,
function
()
if
(
wifi
.
sta
.
status
()
==
wifi
.
STA_GOTIP
)
then
if
(
wifi
.
sta
.
status
()
==
wifi
.
STA_GOTIP
)
then
t
:
unregister
()
t
:
unregister
()
t
=
nil
print
(
"Welcome to NodeMCU world"
,
node
.
heap
(),
wifi
.
sta
.
getip
())
print
(
"Welcome to NodeMCU world"
,
node
.
heap
(),
wifi
.
sta
.
getip
())
return
FTP
.
createServer
(
user
,
pass
,
dbgFlag
)
return
this
:
createServer
(
user
,
pass
,
dbgFlag
)
else
else
uart
.
write
(
0
,
"."
)
uart
.
write
(
0
,
"."
)
end
end
end
)
end
)
end
end
--[[SPLIT IGNORE]]
function
FTP
.
createServer
(
...
)
--[[SPLIT HERE ftp-createServer]]
-- Lua: FTP:createServer(user, pass[, dbgFlag])
local
this
,
user
,
pass
,
dbgFlag
=
...
local
cnt
=
0
this
.
user
,
this
.
pass
,
dbgFlag
=
user
,
pass
,
(
dbgFlag
and
true
or
false
)
function
FTP
.
createServer
(
user
,
pass
,
dbgFlag
)
-- upval: FTP (, debug, tostring, pcall, type, processCommand)
this
.
debug
=
(
not
dbgFlag
)
and
type
-- executing type(...) is in effect a NOOP
FTP
.
user
,
FTP
.
pass
,
FTP
.
debug
=
user
,
pass
,
dbgFlag
or
function
(
fmt
,
...
)
-- upval: cnt
FTP
.
server
=
net
.
createServer
(
net
.
TCP
,
180
)
if
(
...
)
then
fmt
=
fmt
:
format
(
...
)
end
_G
.
FTP
=
FTP
print
(
node
.
heap
(),
fmt
)
debug
(
"Server created: (userdata) %s"
,
tostring
(
FTP
.
server
))
cnt
=
cnt
+
1
if
cnt
%
10
then
tmr
.
wdclr
()
end
end
this
.
server
=
net
.
createServer
(
net
.
TCP
,
180
)
_G
.
FTP
=
this
this
.
debug
(
"Server created: (userdata) %s"
,
tostring
(
this
.
server
))
FTP
.
server
:
listen
(
21
,
function
(
sock
)
-- upval:
FTP (, debug, pcall, type, processCommand)
this
.
server
:
listen
(
21
,
function
(
sock
)
-- upval:
this
-- since a server can have multiple connections, each connection
-- since a server can have multiple connections, each connection
-- has a CNX table to store connection-wide globals.
-- has its own CXN object (table) to store connection-wide globals.
local
client
=
FTP
.
client
local
CXN
;
CXN
=
{
local
CNX
;
CNX
=
{
validUser
=
false
,
validUser
=
false
,
cmdSocket
=
sock
,
cmdSocket
=
sock
,
send
=
function
(
rec
,
cb
)
-- upval: CNX (,debug)
debug
=
this
.
debug
,
-- debug("Sending: %s", rec)
FTP
=
this
,
return
CNX
.
cmdSocket
:
send
(
rec
..
"
\r\n
"
,
cb
)
send
=
function
(
rec
,
cb
)
-- upval: CXN
end
,
--- send()
CXN
.
debug
(
"Sending: %s"
,
rec
)
close
=
function
(
socket
)
-- upval: client, CNX (,debug, pcall, type)
return
CXN
.
cmdSocket
:
send
(
rec
..
"
\r\n
"
,
cb
)
-- debug("Closing CNX.socket=%s, sock=%s", tostring(CNX.socket), tostring(sock))
end
,
--- CXN. send()
close
=
function
(
socket
)
-- upval: CXN
CXN
.
debug
(
"Closing CXN.cmdSocket=%s"
,
tostring
(
CXN
.
cmdSocket
))
for
_
,
s
in
ipairs
{
'cmdSocket'
,
'dataServer'
,
'dataSocket'
}
do
for
_
,
s
in
ipairs
{
'cmdSocket'
,
'dataServer'
,
'dataSocket'
}
do
local
sck
;
sck
,
CNX
[
s
]
=
CNX
[
s
],
nil
CXN
.
debug
(
"closing CXN.%s=%s"
,
s
,
tostring
(
CXN
[
s
]))
-- debug("closing CNX.%s=%s", s, tostring(sck))
if
type
(
CXN
[
s
])
==
'userdata'
then
if
type
(
sck
)
==
'userdata'
then
pcall
(
sck
.
close
,
sck
)
end
pcall
(
socket
.
close
,
CXN
[
s
])
CXN
[
s
]
=
nil
end
end
client
[
socket
]
=
nil
end
end
-- CNX.close()
CXN
.
FTP
.
client
[
socket
]
=
nil
end
-- CXN.close()
}
}
local
function
validateUser
(
socket
,
data
)
-- upval: CN
X, FTP (, debug, processCommand)
local
function
validateUser
(
socket
,
data
)
-- upval: C
X
N
-- validate the logon and if then switch to processing commands
-- validate the logon and if then switch to processing commands
CXN
.
debug
(
"Authorising: %s"
,
data
)
-- debug("Authorising: %s", data)
local
cmd
,
arg
=
data
:
match
(
'([A-Za-z]+) *([^\r\n]*)'
)
local
cmd
,
arg
=
data
:
match
(
'([A-Za-z]+) *([^\r\n]*)'
)
local
msg
=
"530 Not logged in, authorization required"
local
msg
=
"530 Not logged in, authorization required"
cmd
=
cmd
:
upper
()
cmd
=
cmd
:
upper
()
if
cmd
==
'USER'
then
if
cmd
==
'USER'
then
C
N
X
.
validUser
=
(
arg
==
FTP
.
user
)
CX
N
.
validUser
=
(
arg
==
CXN
.
FTP
.
user
)
msg
=
C
N
X
.
validUser
and
msg
=
CX
N
.
validUser
and
"331 OK. Password required"
or
"331 OK. Password required"
or
"530 user not found"
"530 user not found"
elseif
CNX
.
validUser
and
cmd
==
'PASS'
then
elseif
CXN
.
validUser
and
cmd
==
'PASS'
then
if
arg
==
FTP
.
pass
then
if
arg
==
CXN
.
FTP
.
pass
then
CNX
.
cwd
=
'/'
CXN
.
cwd
=
'/'
socket
:
on
(
"receive"
,
function
(
socketObj
,
dataObj
)
socket
:
on
(
"receive"
,
function
(
soc
,
rec
)
-- upval: CXN
processCommand
(
CNX
,
socketObj
,
dataObj
)
assert
(
soc
==
CXN
.
cmdSocket
)
CXN
.
FTP
.
processCommand
(
CXN
,
rec
)
end
)
-- logged on so switch to command mode
end
)
-- logged on so switch to command mode
msg
=
"230 Login successful. Username & password correct; proceed."
msg
=
"230 Login successful. Username & password correct; proceed."
else
else
...
@@ -128,46 +133,45 @@ function FTP.createServer(user, pass, dbgFlag) -- upval: FTP (, debug, tostring
...
@@ -128,46 +133,45 @@ function FTP.createServer(user, pass, dbgFlag) -- upval: FTP (, debug, tostring
elseif
cmd
==
'AUTH'
then
elseif
cmd
==
'AUTH'
then
msg
=
"500 AUTH not understood"
msg
=
"500 AUTH not understood"
end
end
return
C
N
X
.
send
(
msg
)
return
CX
N
.
send
(
msg
)
end
end
local
port
,
ip
=
sock
:
getpeer
()
-- luacheck: no unused
local
port
,
ip
=
sock
:
getpeer
()
-- luacheck: no unused
--debug("Connection accepted: (userdata) %s client %s:%u", tostring(sock), ip, port)
--
cxt.
debug("Connection accepted: (userdata) %s client %s:%u", tostring(sock), ip, port)
sock
:
on
(
"receive"
,
validateUser
)
sock
:
on
(
"receive"
,
validateUser
)
sock
:
on
(
"disconnection"
,
C
N
X
.
close
)
sock
:
on
(
"disconnection"
,
CX
N
.
close
)
FTP
.
client
[
sock
]
=
C
N
X
this
.
client
[
sock
]
=
CX
N
CNX
.
send
(
"220 FTP server ready"
);
CXN
.
send
(
"220 FTP server ready"
);
end
)
-- FTP.server:listen()
end
)
-- this.server:listen()
end
-- FTP.createServer()
end
--[[SPLIT IGNORE]]
function
FTP
.
close
(
...
)
--[[SPLIT HERE ftp-close]]
-- Lua: FTP:close()
local
this
=
...
function
FTP
.
close
()
-- upval: FTP (, debug, post, tostring)
-- this.client is a table of soc = cnx. The first (and usually only connection) is cleared
local
svr
=
FTP
.
server
-- immediately and next() used to do a post chain so we only close one client per task
local
function
rollupClients
(
skt
,
cxt
)
-- upval: this, rollupClients
local
function
rollupClients
(
client
,
server
)
-- upval: FTP (,debug, post, tostring, rollupClients)
-- this is done recursively so that we only close one client per task
local
skt
,
cxt
=
next
(
client
)
if
skt
then
if
skt
then
--
debug("Client close: %s", tostring(skt))
this
.
debug
(
"Client close: %s"
,
tostring
(
skt
))
cxt
.
close
(
skt
)
cxt
.
close
(
skt
)
post
(
function
()
return
rollupClients
(
client
,
server
)
end
)
-- upval: rollupClients, client, server
this
.
client
[
skt
]
=
nil
else
node
.
task
.
post
(
function
()
return
rollupClients
(
next
(
this
.
client
,
skt
))
end
)
-- upval: rollupClients, this, skt
-- debug("Server close: %s", tostring(server))
else
-- we have emptied the open socket table, so can now shut the server
server
:
close
()
this
.
debug
(
"Server close: %s"
,
tostring
(
this
.
server
))
server
:
__gc
()
this
.
server
:
close
()
FTP
,
_G
.
FTP
=
nil
,
nil
-- the upval FTP can only be zeroed once FTP.client is cleared.
this
.
server
:
__gc
()
_G
.
FTP
=
nil
end
end
end
end
rollupClients
(
next
(
this
.
client
))
package.loaded
.
ftpserver
=
nil
if
svr
then
rollupClients
(
FTP
.
client
,
svr
)
end
end
--[[SPLIT IGNORE]]
package.loaded
.
ftpserver
=
nil
function
FTP
.
processCommand
(
...
)
--[[SPLIT HERE ftp-processCommand]]
end
-- FTP.close()
----------------------------- Process Command --------------------------------
----------------------------- Process Command --------------------------------
-- This splits the valid commands into one of three categories:
-- This splits the valid commands into one of three categories:
-- * bare commands (which take no arg)
-- * bare commands (which take no arg)
...
@@ -177,28 +181,30 @@ end -- FTP.close()
...
@@ -177,28 +181,30 @@ end -- FTP.close()
--
--
-- Find strings are used do this lookup and minimise long if chains.
-- Find strings are used do this lookup and minimise long if chains.
------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- upvals: (, debug, processBareCmds, processSimpleCmds, processDataCmds)
processCommand
=
function
(
cxt
,
socket
,
data
)
-- luacheck: no unused
local
cxt
,
data
=
...
debug
(
"Command: %s"
,
data
)
cxt
.
debug
(
"Command: %s"
,
data
)
data
=
data
:
gsub
(
'[\r\n]+$'
,
''
)
-- chomp trailing CRLF
data
=
data
:
gsub
(
'[\r\n]+$'
,
''
)
-- chomp trailing CRLF
local
cmd
,
arg
=
data
:
match
(
'([a-zA-Z]+) *(.*)'
)
local
cmd
,
arg
=
data
:
match
(
'([a-zA-Z]+) *(.*)'
)
cmd
=
cmd
:
upper
()
cmd
=
cmd
:
upper
()
local
_cmd_
=
'_'
..
cmd
..
'_'
local
_cmd_
=
'_'
..
cmd
..
'_'
if
(
'_CDUP_NOOP_PASV_PWD_QUIT_SYST_'
):
find
(
_cmd_
)
then
if
(
'_CDUP_NOOP_PASV_PWD_QUIT_SYST_'
):
find
(
_cmd_
)
then
processBareCmds
(
cxt
,
cmd
)
cxt
.
FTP
.
processBareCmds
(
cxt
,
cmd
)
elseif
(
'_CWD_DELE_MODE_PORT_RNFR_RNTO_SIZE_TYPE_'
):
find
(
_cmd_
)
then
elseif
(
'_CWD_DELE_MODE_PORT_RNFR_RNTO_SIZE_TYPE_'
):
find
(
_cmd_
)
then
processSimpleCmds
(
cxt
,
cmd
,
arg
)
cxt
.
FTP
.
processSimpleCmds
(
cxt
,
cmd
,
arg
)
elseif
(
'_LIST_NLST_RETR_STOR_'
):
find
(
_cmd_
)
then
elseif
(
'_LIST_NLST_RETR_STOR_'
):
find
(
_cmd_
)
then
processDataCmds
(
cxt
,
cmd
,
arg
)
cxt
.
FTP
.
processDataCmds
(
cxt
,
cmd
,
arg
)
else
else
cxt
.
send
(
"500 Unknown error"
)
cxt
.
send
(
"500 Unknown error"
)
end
end
end
-- processCommand(sock, data)
end
--[[SPLIT IGNORE]]
function
FTP
.
processBareCmds
(
...
)
--[[SPLIT HERE ftp-processBareCmds]]
-------------------------- Process Bare Commands -----------------------------
-------------------------- Process Bare Commands -----------------------------
processBareCmds
=
function
(
cxt
,
cmd
)
-- upval: (dataServer)
local
cxt
,
cmd
=
...
local
send
=
cxt
.
send
local
send
=
cxt
.
send
...
@@ -220,7 +226,7 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
...
@@ -220,7 +226,7 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
pplo
=
port
%
256
pplo
=
port
%
256
pphi
=
(
port
-
pplo
)
/
256
pphi
=
(
port
-
pplo
)
/
256
i1
,
i2
,
i3
,
i4
=
ip
:
match
(
"(%d+).(%d+).(%d+).(%d+)"
)
i1
,
i2
,
i3
,
i4
=
ip
:
match
(
"(%d+).(%d+).(%d+).(%d+)"
)
dataServer
(
cxt
,
port
)
cxt
.
FTP
.
dataServer
(
cxt
,
port
)
return
send
(
return
send
(
(
'227 Entering Passive Mode(%d,%d,%d,%d,%d,%d)'
):
format
(
(
'227 Entering Passive Mode(%d,%d,%d,%d,%d,%d)'
):
format
(
i1
,
i2
,
i3
,
i4
,
pphi
,
pplo
))
i1
,
i2
,
i3
,
i4
,
pphi
,
pplo
))
...
@@ -229,7 +235,7 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
...
@@ -229,7 +235,7 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
return
send
(
'257 "/" is the current directory'
)
return
send
(
'257 "/" is the current directory'
)
elseif
cmd
==
'QUIT'
then
elseif
cmd
==
'QUIT'
then
send
(
"221 Goodbye"
,
function
()
cxt
.
close
(
cxt
.
cmdSocket
)
end
)
send
(
"221 Goodbye"
,
function
()
cxt
.
close
(
cxt
.
cmdSocket
)
end
)
-- upval: cxt
return
return
elseif
cmd
==
'SYST'
then
elseif
cmd
==
'SYST'
then
...
@@ -239,11 +245,14 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
...
@@ -239,11 +245,14 @@ processBareCmds = function(cxt, cmd) -- upval: (dataServer)
else
else
error
(
'Oops. Missed '
..
cmd
)
error
(
'Oops. Missed '
..
cmd
)
end
end
end
-- processBareCmds(cmd, send)
end
--[[SPLIT IGNORE]]
function
FTP
.
processSimpleCmds
(
...
)
--[[SPLIT HERE ftp-processSimpleCmds]]
------------------------- Process Simple Commands ----------------------------
------------------------- Process Simple Commands ----------------------------
local
from
-- needs to persist between simple commands
processSimpleCmds
=
function
(
cxt
,
cmd
,
arg
)
-- upval: from (, file, tostring, dataServer, debug)
local
cxt
,
cmd
,
arg
=
...
local
send
=
cxt
.
send
local
send
=
cxt
.
send
...
@@ -252,7 +261,7 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
...
@@ -252,7 +261,7 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
"504 Only S(tream) is suported"
)
"504 Only S(tream) is suported"
)
elseif
cmd
==
'PORT'
then
elseif
cmd
==
'PORT'
then
dataServer
(
cxt
,
nil
)
-- clear down any PASV setting
cxt
.
FTP
.
dataServer
(
cxt
,
nil
)
-- clear down any PASV setting
return
send
(
"502 Active mode not supported. PORT not implemented"
)
return
send
(
"502 Active mode not supported. PORT not implemented"
)
elseif
cmd
==
'TYPE'
then
elseif
cmd
==
'TYPE'
then
...
@@ -269,7 +278,7 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
...
@@ -269,7 +278,7 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
-- The remaining commands take a filename as an arg. Strip off leading / and ./
-- The remaining commands take a filename as an arg. Strip off leading / and ./
arg
=
arg
:
gsub
(
'^%.?/'
,
''
):
gsub
(
'^%.?/'
,
''
)
arg
=
arg
:
gsub
(
'^%.?/'
,
''
):
gsub
(
'^%.?/'
,
''
)
debug
(
"Filename is %s"
,
arg
)
cxt
.
debug
(
"Filename is %s"
,
arg
)
if
cmd
==
'CWD'
then
if
cmd
==
'CWD'
then
if
arg
:
match
(
'^[%./]*$'
)
then
if
arg
:
match
(
'^[%./]*$'
)
then
...
@@ -285,14 +294,14 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
...
@@ -285,14 +294,14 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
return
send
(
"550 Requested action not taken"
)
return
send
(
"550 Requested action not taken"
)
elseif
cmd
==
'RNFR'
then
elseif
cmd
==
'RNFR'
then
from
=
arg
cxt
.
from
=
arg
send
(
"350 RNFR accepted"
)
send
(
"350 RNFR accepted"
)
return
return
elseif
cmd
==
'RNTO'
then
elseif
cmd
==
'RNTO'
then
local
status
=
from
and
file
.
rename
(
from
,
arg
)
local
status
=
cxt
.
from
and
file
.
rename
(
cxt
.
from
,
arg
)
--
debug("rename('%s','%s')=%s", tostring(from), tostring(arg), tostring(status))
cxt
.
debug
(
"rename('%s','%s')=%s"
,
tostring
(
cxt
.
from
),
tostring
(
arg
),
tostring
(
status
))
from
=
nil
cxt
.
from
=
nil
return
send
(
status
and
"250 File renamed"
or
return
send
(
status
and
"250 File renamed"
or
"550 Requested action not taken"
)
"550 Requested action not taken"
)
elseif
cmd
==
"SIZE"
then
elseif
cmd
==
"SIZE"
then
...
@@ -303,16 +312,19 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
...
@@ -303,16 +312,19 @@ processSimpleCmds = function(cxt, cmd, arg) -- upval: from (, file, tostring, d
else
else
error
(
'Oops. Missed '
..
cmd
)
error
(
'Oops. Missed '
..
cmd
)
end
end
end
-- processSimpleCmds(cmd, arg, send)
end
--[[SPLIT IGNORE]]
function
FTP
.
processDataCmds
(
...
)
--[[SPLIT HERE ftp-processDataCmds]]
-------------------------- Process Data Commands -----------------------------
-------------------------- Process Data Commands -----------------------------
processDataCmds
=
function
(
cxt
,
cmd
,
arg
)
-- upval: FTP (, pairs, file, tostring, debug, post)
local
send
=
cxt
.
send
local
cxt
,
cmd
,
arg
=
...
local
send
,
FTP
=
cxt
.
send
,
cxt
.
FTP
-- luacheck: ignore FTP
-- The data commands are only accepted if a PORT command is in scope
-- The data commands are only accepted if a PORT command is in scope
if
cxt
.
dataServer
==
nil
and
cxt
.
dataSocket
==
nil
then
if
FTP
.
dataServer
==
nil
and
cxt
.
dataSocket
==
nil
then
return
send
(
"502 Active mode not supported. "
..
cmd
..
" not implemented"
)
return
send
(
"502 Active mode not supported. "
..
cmd
..
" not implemented"
)
end
end
...
@@ -340,8 +352,8 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
...
@@ -340,8 +352,8 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
end
end
table.sort
(
nameList
)
table.sort
(
nameList
)
function
cxt
.
getData
()
-- upval: cmd, fileSize, nameList
(, table)
function
cxt
.
getData
(
c
)
-- upval: cmd, fileSize, nameList
local
list
,
user
=
{},
FTP
.
user
local
list
,
user
=
{},
c
.
FTP
.
user
for
i
=
1
,
10
do
-- luacheck: no unused
for
i
=
1
,
10
do
-- luacheck: no unused
if
#
nameList
==
0
then
break
end
if
#
nameList
==
0
then
break
end
local
f
=
table.remove
(
nameList
,
1
)
local
f
=
table.remove
(
nameList
,
1
)
...
@@ -355,7 +367,7 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
...
@@ -355,7 +367,7 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
elseif
cmd
==
"RETR"
then
elseif
cmd
==
"RETR"
then
local
f
=
file
.
open
(
arg
,
"r"
)
local
f
=
file
.
open
(
arg
,
"r"
)
if
f
then
-- define a getter to read the file
if
f
then
-- define a getter to read the file
function
cxt
.
getData
()
-- upval: f
function
cxt
.
getData
(
c
)
-- luacheck: ignore c
-- upval: f
local
buf
=
f
:
read
(
1024
)
local
buf
=
f
:
read
(
1024
)
if
not
buf
then
f
:
close
();
f
=
nil
;
end
if
not
buf
then
f
:
close
();
f
=
nil
;
end
return
buf
return
buf
...
@@ -365,13 +377,13 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
...
@@ -365,13 +377,13 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
elseif
cmd
==
"STOR"
then
elseif
cmd
==
"STOR"
then
local
f
=
file
.
open
(
arg
,
"w"
)
local
f
=
file
.
open
(
arg
,
"w"
)
if
f
then
-- define a setter to write the file
if
f
then
-- define a setter to write the file
function
cxt
.
setData
(
rec
)
-- upval f, ar
g (, debu
g)
function
cxt
.
setData
(
c
,
rec
)
--
luacheck: ignore c --
upval
:
f
(
, arg)
--
debug("writing %u bytes to %s", #rec, arg)
cxt
.
debug
(
"writing %u bytes to %s"
,
#
rec
,
arg
)
return
f
:
write
(
rec
)
return
f
:
write
(
rec
)
end
-- cxt.saveData(rec)
end
-- cxt.saveData(rec)
function
cxt
.
fileClose
()
--
upval cxt, f, arg (,debu
g)
function
cxt
.
fileClose
(
c
)
--
luacheck: ignore c -- upval: f (,ar
g)
--
debug("closing %s", arg)
cxt
.
debug
(
"closing %s"
,
arg
)
f
:
close
();
cxt
.
fileClose
,
f
=
nil
,
nil
f
:
close
();
f
=
nil
end
-- cxt.close()
end
-- cxt.close()
end
end
...
@@ -380,13 +392,12 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
...
@@ -380,13 +392,12 @@ processDataCmds = function(cxt, cmd, arg) -- upval: FTP (, pairs, file, tostrin
send
((
cxt
.
getData
or
cxt
.
setData
)
and
"150 Accepted data connection"
or
send
((
cxt
.
getData
or
cxt
.
setData
)
and
"150 Accepted data connection"
or
"451 Can't open/create "
..
arg
)
"451 Can't open/create "
..
arg
)
if
cxt
.
getData
and
cxt
.
dataSocket
then
if
cxt
.
getData
and
cxt
.
dataSocket
then
debug
(
"poking sender to initiate first xfer"
)
cxt
.
debug
(
"poking sender to initiate first xfer"
)
post
(
function
()
cxt
.
sender
(
cxt
.
dataSocket
)
end
)
node
.
task
.
post
(
function
()
cxt
.
sender
(
cxt
.
dataSocket
)
end
)
-- upval: cxt
end
end
end
-- processDataCmds(cmd, arg, send)
end
--[[SPLIT IGNORE]]
function
FTP
.
dataServer
(
...
)
--[[SPLIT HERE ftp-dataServer]]
----------------------------- Data Port Routines -----------------------------
----------------------------- Data Port Routines -----------------------------
-- These are used to manage the data transfer over the data port. This is
-- These are used to manage the data transfer over the data port. This is
-- set up lazily either by a PASV or by the first LIST NLST RETR or STOR
-- set up lazily either by a PASV or by the first LIST NLST RETR or STOR
...
@@ -394,51 +405,53 @@ end -- processDataCmds(cmd, arg, send)
...
@@ -394,51 +405,53 @@ end -- processDataCmds(cmd, arg, send)
-- handle the actual xfer. Also note that the sending process can be primed in
-- handle the actual xfer. Also note that the sending process can be primed in
--
--
---------------- Open a new data server and port ---------------------------
---------------- Open a new data server and port ---------------------------
dataServer
=
function
(
cxt
,
n
)
-- upval: (pcall, net, ftpDataOpen, debug, tostring)
local
dataSrv
=
cxt
.
dataServer
local
cxt
,
n
=
...
if
dataSrv
then
-- close any existing listener
p
cal
l
(
dataS
rv
.
close
,
dataSrv
)
lo
cal
dataS
vr
=
cxt
.
dataS
e
rv
er
end
if
dataSvr
then
pcall
(
dataSvr
.
close
,
dataSrv
)
end
-- luacheck: ignore -- close any existing listener
if
n
then
if
n
then
-- Open a new listener if needed. Note that this is only used to establish
-- Open a new listener if needed. Note that this is only used to establish
-- a single connection, so ftpDataOpen closes the server socket
-- a single connection, so ftpDataOpen closes the server socket
cxt
.
dataServer
=
net
.
createServer
(
net
.
TCP
,
300
)
dataSvr
=
net
.
createServer
(
net
.
TCP
,
300
)
cxt
.
dataServer
:
listen
(
n
,
function
(
sock
)
-- upval: cxt, (ftpDataOpen)
cxt
.
dataServer
=
dataSvr
ftpDataOpen
(
cxt
,
sock
)
dataSvr
:
listen
(
n
,
function
(
sock
)
-- upval: cxt
cxt
.
FTP
.
ftpDataOpen
(
cxt
,
sock
)
end
)
end
)
--
debug("Listening on Data port %u, server %s",n, tostring(cxt.dataServer))
cxt
.
debug
(
"Listening on Data port %u, server %s"
,
n
,
tostring
(
cxt
.
dataServer
))
else
else
cxt
.
dataServer
=
nil
cxt
.
dataServer
=
nil
--
debug("Stopped listening on Data port",n)
cxt
.
debug
(
"Stopped listening on Data port"
,
n
)
end
end
end
-- dataServer(n)
end
--[[SPLIT IGNORE]]
function
FTP
.
ftpDataOpen
(
...
)
--[[SPLIT HERE ftp-ftpDataOpen]]
----------------------- Connection on FTP data port ------------------------
----------------------- Connection on FTP data port ------------------------
ftpDataOpen
=
function
(
cxt
,
dataSocket
)
-- upval: (debug, tostring, post, pcall)
local
cxt
,
dataSocket
=
...
local
sport
,
sip
=
dataSocket
:
getaddr
()
local
sport
,
sip
=
dataSocket
:
getaddr
()
local
cport
,
cip
=
dataSocket
:
getpeer
()
local
cport
,
cip
=
dataSocket
:
getpeer
()
debug
(
"Opened data socket %s from %s:%u to %s:%u"
,
tostring
(
dataSocket
),
sip
,
sport
,
cip
,
cport
)
cxt
.
debug
(
"Opened data socket %s from %s:%u to %s:%u"
,
tostring
(
dataSocket
),
sip
,
sport
,
cip
,
cport
)
cxt
.
dataSocket
=
dataSocket
cxt
.
dataSocket
=
dataSocket
cxt
.
dataServer
:
close
()
cxt
.
dataServer
:
close
()
cxt
.
dataServer
=
nil
cxt
.
dataServer
=
nil
local
function
cleardown
(
skt
,
type
)
--
upval: cxt (, debug, tostring, post, pcall)
function
cxt
.
cleardown
(
cxt
,
skt
,
cd
type
)
--
luacheck: ignore cxt -- shadowing
-- luacheck:
push no unused
-- luacheck:
ignore cdtype which
type
=
type
==
1
and
"disconnection"
or
"reconnection"
cd
type
=
cd
type
==
1
and
"disconnection"
or
"reconnection"
local
which
=
cxt
.
setData
and
"setData"
or
(
cxt
.
getData
and
cxt
.
getData
or
"neither"
)
local
which
=
cxt
.
setData
and
"setData"
or
(
cxt
.
getData
and
cxt
.
getData
or
"neither"
)
--debug("Cleardown entered from %s with %s", type, which)
cxt
.
debug
(
"Cleardown entered from %s with %s"
,
cdtype
,
which
)
-- luacheck: pop
if
cxt
.
setData
then
if
cxt
.
setData
then
cxt
.
fileClose
()
cxt
:
fileClose
()
cxt
.
setData
=
nil
cxt
.
setData
=
nil
cxt
.
send
(
"226 Transfer complete."
)
cxt
.
send
(
"226 Transfer complete."
)
else
else
cxt
.
getData
,
cxt
.
sender
=
nil
,
nil
cxt
.
getData
,
cxt
.
sender
=
nil
,
nil
end
end
--
debug("Clearing down data socket %s", tostring(skt))
cxt
.
debug
(
"Clearing down data socket %s"
,
tostring
(
skt
))
post
(
function
()
-- upval:
skt, cxt, (, pcall)
node
.
task
.
post
(
function
()
-- upval:
cxt, skt
pcall
(
skt
.
close
,
skt
);
skt
=
nil
pcall
(
skt
.
close
,
skt
);
skt
=
nil
cxt
.
dataSocket
=
nil
cxt
.
dataSocket
=
nil
end
)
end
)
...
@@ -446,10 +459,10 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
...
@@ -446,10 +459,10 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
local
on_hold
=
false
local
on_hold
=
false
dataSocket
:
on
(
"receive"
,
function
(
skt
,
rec
)
--upval: cxt, on_hold
(, debug, tstring, post, node, pcall)
dataSocket
:
on
(
"receive"
,
function
(
skt
,
rec
)
--
upval: cxt, on_hold
local
which
=
cxt
.
setData
and
"setData"
or
(
cxt
.
getData
and
cxt
.
getData
or
"neither"
)
-- luacheck: no unused
local
rectype
=
cxt
.
setData
and
"setData"
or
(
cxt
.
getData
and
cxt
.
getData
or
"neither"
)
--
debug("Received %u data bytes with %s", #rec,
which
)
cxt
.
debug
(
"Received %u data bytes with %s"
,
#
rec
,
rectype
)
if
not
cxt
.
setData
then
return
end
if
not
cxt
.
setData
then
return
end
...
@@ -458,33 +471,33 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
...
@@ -458,33 +471,33 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
-- large file. As soon as a record arrives assert a flow control hold.
-- large file. As soon as a record arrives assert a flow control hold.
-- This can take up to 5 packets to come into effect at which point the
-- This can take up to 5 packets to come into effect at which point the
-- low priority unhold task is executed releasing the flow again.
-- low priority unhold task is executed releasing the flow again.
--
debug("Issuing hold on data socket %s", tostring(skt))
cxt
.
debug
(
"Issuing hold on data socket %s"
,
tostring
(
skt
))
skt
:
hold
();
on_hold
=
true
skt
:
hold
();
on_hold
=
true
post
(
node
.
task
.
LOW_PRIORITY
,
node
.
task
.
post
(
node
.
task
.
LOW_PRIORITY
,
function
()
-- upval: skt, on_hold
(, debug, tostring))
function
()
-- upval: skt, on_hold
--
debug("Issuing unhold on data socket %s", tostring(skt))
cxt
.
debug
(
"Issuing unhold on data socket %s"
,
tostring
(
skt
))
pcall
(
skt
.
unhold
,
skt
);
on_hold
=
false
pcall
(
skt
.
unhold
,
skt
);
on_hold
=
false
end
)
end
)
end
end
if
not
cxt
.
setData
(
rec
)
then
if
not
cxt
:
setData
(
rec
)
then
--
debug("Error writing to SPIFFS")
cxt
.
debug
(
"Error writing to SPIFFS"
)
cxt
.
fileClose
()
cxt
:
fileClose
()
cxt
.
setData
=
nil
cxt
.
setData
=
nil
cxt
.
send
(
"552 Upload aborted. Exceeded storage allocation"
)
cxt
.
send
(
"552 Upload aborted. Exceeded storage allocation"
)
end
end
end
)
end
)
function
cxt
.
sender
(
skt
)
-- upval: cxt
(, debug)
function
cxt
.
sender
(
skt
)
-- upval: cxt
debug
(
"entering sender"
)
cxt
.
debug
(
"entering sender"
)
if
not
cxt
.
getData
then
return
end
if
not
cxt
.
getData
then
return
end
skt
=
skt
or
cxt
.
dataSocket
skt
=
skt
or
cxt
.
dataSocket
local
rec
=
cxt
.
getData
()
local
rec
=
cxt
:
getData
()
if
rec
and
#
rec
>
0
then
if
rec
and
#
rec
>
0
then
--
debug("Sending %u data bytes", #rec)
cxt
.
debug
(
"Sending %u data bytes"
,
#
rec
)
skt
:
send
(
rec
)
skt
:
send
(
rec
)
else
else
--
debug("Send of data completed")
cxt
.
debug
(
"Send of data completed"
)
skt
:
close
()
skt
:
close
()
cxt
.
send
(
"226 Transfer complete."
)
cxt
.
send
(
"226 Transfer complete."
)
cxt
.
getData
,
cxt
.
dataSocket
=
nil
,
nil
cxt
.
getData
,
cxt
.
dataSocket
=
nil
,
nil
...
@@ -492,14 +505,11 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
...
@@ -492,14 +505,11 @@ ftpDataOpen = function(cxt, dataSocket) -- upval: (debug, tostring, post, pcall)
end
end
dataSocket
:
on
(
"sent"
,
cxt
.
sender
)
dataSocket
:
on
(
"sent"
,
cxt
.
sender
)
dataSocket
:
on
(
"disconnection"
,
function
(
skt
)
return
cleardown
(
skt
,
1
)
end
)
dataSocket
:
on
(
"disconnection"
,
function
(
skt
)
return
cxt
:
cleardown
(
skt
,
1
)
end
)
-- upval: cxt
dataSocket
:
on
(
"reconnection"
,
function
(
skt
)
return
cleardown
(
skt
,
2
)
end
)
dataSocket
:
on
(
"reconnection"
,
function
(
skt
)
return
cxt
:
cleardown
(
skt
,
2
)
end
)
-- upval: cxt
-- if we are sending to client then kick off the first send
-- if we are sending to client then kick off the first send
if
cxt
.
getData
then
cxt
.
sender
(
cxt
.
dataSocket
)
end
if
cxt
.
getData
then
cxt
.
sender
(
cxt
.
dataSocket
)
end
end
-- ftpDataOpen(socket)
end
--[[SPLIT HERE]]
return
FTP
--[[SPLIT IGNORE]]
------------------------------------------------ -----------------------------
return
FTP
lua_modules/telnet/README.md
0 → 100644
View file @
8d091c47
# Telnet Module
Documentation for this Lua module is available in the
[
telnet.md
](
../../docs/lua-modules/telnet.md
)
file and in the
[
Official NodeMCU Documentation
](
https://nodemcu.readthedocs.io/
)
in
`Lua Modules`
section.
lua_
examp
les/telnet/telnet
_pipe
.lua
→
lua_
modu
les/telnet/telnet.lua
View file @
8d091c47
--[[SPLIT MODULE telnet]]
--[[ A telnet server T. Ellison, June 2019
--[[ A telnet server T. Ellison, June 2019
This version of the telnet server demonstrates the use of the new stdin and stout
This version of the telnet server demonstrates the use of the new stdin and stout
...
@@ -65,5 +67,4 @@ function M.close(this)
...
@@ -65,5 +67,4 @@ function M.close(this)
end
end
return
M
return
M
--[[SPLIT HERE]]
mkdocs.yml
View file @
8d091c47
...
@@ -58,6 +58,7 @@ pages:
...
@@ -58,6 +58,7 @@ pages:
-
'
lm92'
:
'
lua-modules/lm92.md'
-
'
lm92'
:
'
lua-modules/lm92.md'
-
'
mcp23008'
:
'
lua-modules/mcp23008.md'
-
'
mcp23008'
:
'
lua-modules/mcp23008.md'
-
'
redis'
:
'
lua-modules/redis.md'
-
'
redis'
:
'
lua-modules/redis.md'
-
'
telnet'
:
'
lua-modules/telnet.md'
-
'
yeelink'
:
'
lua-modules/yeelink.md'
-
'
yeelink'
:
'
lua-modules/yeelink.md'
-
C Modules
:
-
C Modules
:
-
'
adc'
:
'
modules/adc.md'
-
'
adc'
:
'
modules/adc.md'
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment