"encoding/binary"
"errors"
"fmt"
+ "github.com/go-playground/validator/v10"
"go.uber.org/zap"
"io"
"io/fs"
"IsReply", t.IsReply,
"type", handler.Name,
"sentBytes", n,
- "remoteAddr", client.Connection.RemoteAddr(),
+ "remoteAddr", client.RemoteAddr,
)
return nil
}
}
}()
go func() {
- if err := s.handleNewConnection(conn); err != nil {
+ if err := s.handleNewConnection(conn, conn.RemoteAddr().String()); err != nil {
if err == io.EOF {
s.Logger.Infow("Client disconnected", "RemoteAddr", conn.RemoteAddr())
} else {
return err
}
-func (s *Server) NewClientConn(conn net.Conn) *ClientConn {
+func (s *Server) NewClientConn(conn net.Conn, remoteAddr string) *ClientConn {
s.mux.Lock()
defer s.mux.Unlock()
AutoReply: []byte{},
Transfers: make(map[int][]*FileTransfer),
Agreed: false,
+ RemoteAddr: remoteAddr,
}
*s.NextGuestID++
ID := *s.NextGuestID
if err != nil {
return err
}
+
+ validate := validator.New()
+ err = validate.Struct(s.Config)
+ if err != nil {
+ return err
+ }
return nil
}
}
// handleNewConnection takes a new net.Conn and performs the initial login sequence
-func (s *Server) handleNewConnection(conn net.Conn) error {
+func (s *Server) handleNewConnection(conn net.Conn, remoteAddr string) error {
defer dontPanic(s.Logger)
- handshakeBuf := make([]byte, 12)
- if _, err := io.ReadFull(conn, handshakeBuf); err != nil {
- return err
- }
- if err := Handshake(conn, handshakeBuf); err != nil {
+ if err := Handshake(conn); err != nil {
return err
}
return err
}
- c := s.NewClientConn(conn)
+ c := s.NewClientConn(conn, remoteAddr)
defer c.Disconnect()
encodedLogin := clientLogin.GetField(fieldUserLogin).Data
*c.Flags = []byte{0, 2}
}
- s.Logger.Infow("Client connection received", "login", login, "version", *c.Version, "RemoteAddr", conn.RemoteAddr().String())
+ s.Logger.Infow("Client connection received", "login", login, "version", *c.Version, "RemoteAddr", remoteAddr)
s.outbox <- c.NewReply(clientLogin,
NewField(fieldVersion, []byte{0x00, 0xbe}),
}
case FileUpload:
destinationFile := s.Config.FileRoot + ReadFilePath(fileTransfer.FilePath) + "/" + string(fileTransfer.FileName)
- tmpFile := destinationFile + ".incomplete"
- file, err := effectiveFile(destinationFile)
+ var file *os.File
+
+ // A file upload has three possible cases:
+ // 1) Upload a new file
+ // 2) Resume a partially transferred file
+ // 3) Replace a fully uploaded file
+ // Unfortunately we have to infer which case applies by inspecting what is already on the file system
+
+ // 1) Check for existing file:
+ _, err := os.Stat(destinationFile)
+ if err == nil {
+ // If found, that means this upload is intended to replace the file
+ if err = os.Remove(destinationFile); err != nil {
+ return err
+ }
+ file, err = os.Create(destinationFile + incompleteFileSuffix)
+ }
if errors.Is(err, fs.ErrNotExist) {
- file, err = FS.Create(tmpFile)
+ // If not found, open or create a new incomplete file
+ file, err = os.OpenFile(destinationFile+incompleteFileSuffix, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}