For open/opendir requests we create a new handle and close it
when the client sends an SSH_FXP_CLOSE but if we return an error the
client will never send the close packet so we have to close the handle
ourselves
we need to add a case for this packet inside the packet worker otherwise
it will be handled in hasHandle case and it will become a "Put" request.
Client side if a Truncate request is called on the open file we should
send a FSETSTAT packet, the request is on the handle, and not a SETSTAT
packet that should be used for paths and not for handle.
after processing a packet we keep in memory the allocated slices and we reuse
them for new packets.
Slices are allocated in:
- recvPacket
- when we receive a sshFxpReadPacket (downloads)
The allocated slices have a fixed size = maxMsgLength.
Allocated slices are referenced to the request order id and are marked for reuse
after a request is served in maybeSendPackets.
The allocator is added to the packetManager struct and it is cleaned at the end
of the Serve() function.
This allocation mode is optional and disabled by default
Add an optional interface that readerAt and writerAt can implement
to be notified about the error causing Serve() to exit with the
request still open.
Implement the TransferError interface in request-example.
This way we can run the request server example in debug mode, for example:
cd examples/request-server
go run -tags debug main.go
simulate a connection error killing an sftp client while uploading/downloading
and see the debug log that shows that the error is correctly notifyed
Fixes#306
Previously if a client makes an unsupported operation,
like a POSIX rename, it would exit the server.
Both support POSIX rename, and do not abort the connection
if there is an unsupported operation is made by the client.
When fstat is called it now uses the handle to get the opened request,
pulls the filepath from that and creates a new request for the fstat
call. This eliminates the need to change the Method on the request
object and furthers the goal of eliminating post-creation mutation of
the request object to open up the possibility to eliminate or at least
reduce the use of the global request lock.
Just like with files, the call to the hander to create the Lister is
done when the OPENDIR packet is received. This eliminates the need for
the lock in the filelist() method and opens the path for eliminating
more locks.
Testing feasibility of creating the reader/writer when first receiving
the Open packet instead of waiting for the Get/Put.
This work is meant to make the Request locks easier to manage and
ultimately reducing/eliminating them as much as possible.
Previous code used the request ids to do ordering. This worked until a
client came along that used un-ordered request ids. This reworks the
ordering to use an internal counter (per session) to order all packets
ensuring that responses are sent in the same order as the requests were
received.
Fixes#260
Instead of accepting a more general type and then asserting it to the
proper type, just take the proper type as the argument.
Also clean up some of the use of it where it checked old direct sending
code's return error (error is now always nil).
PR #257 fixes the issue with running Stat and Readdir on the same
Request. Thus we no longer need to close and recreate the Request
when handling an Opendir call.
The initial Opendir packet is supposed to repond with an error status if
the directory wasn't found. It was just returning a handle without
checking, now it does a Stat on the path and only returns the handle if
the Stat is successful and it indicates it is a directory, otherwise it
returns an error.
Create a master Context in the per-session ReqeustServer.Serve method
that is then used as the parent for all Context's created in that
server. Its cancelFunc is then always called when Serve exits. This is
in line which out the http.serve code works.
Each Request gets a child WithCancel context created in the
requestFromPacket call. This Context is still closed on request.close().