X-Git-Url: https://git.r.bdr.sh/rbdr/mobius/blobdiff_plain/00913df3521d967ac31ee22c23447b5aa711f2e6..b4d84cd8dc5e3d3bdbe84072bf5129ea2bcc3e49:/hotline/server.go diff --git a/hotline/server.go b/hotline/server.go index 9cf93d0..b17102e 100644 --- a/hotline/server.go +++ b/hotline/server.go @@ -2,7 +2,6 @@ package hotline import ( "bufio" - "bytes" "context" "encoding/binary" "errors" @@ -33,14 +32,6 @@ type requestCtx struct { name string } -const ( - userIdleSeconds = 300 // time in seconds before an inactive user is marked idle - idleCheckInterval = 10 // time in seconds to check for idle users - trackerUpdateFrequency = 300 // time in seconds between tracker re-registration -) - -var nostalgiaVersion = []byte{0, 0, 2, 0x2c} // version ID used by the Nostalgia client - type Server struct { Port int Accounts map[string]*Account @@ -158,18 +149,18 @@ func (s *Server) sendTransaction(t Transaction) error { s.mux.Lock() client := s.Clients[uint16(clientID)] + s.mux.Unlock() if client == nil { return fmt.Errorf("invalid client id %v", *t.clientID) } - s.mux.Unlock() - b, err := t.MarshalBinary() if err != nil { return err } - if _, err := client.Connection.Write(b); err != nil { + _, err = client.Connection.Write(b) + if err != nil { return err } @@ -386,7 +377,6 @@ func (s *Server) NewClientConn(conn io.ReadWriteCloser, remoteAddr string) *Clie Version: []byte{}, AutoReply: []byte{}, transfers: map[int]map[[4]byte]*FileTransfer{}, - Agreed: false, RemoteAddr: remoteAddr, } clientConn.transfers = map[int]map[[4]byte]*FileTransfer{ @@ -473,9 +463,6 @@ func (s *Server) connectedUsers() []Field { var connectedUsers []Field for _, c := range sortedClients(s.Clients) { - if !c.Agreed { - continue - } user := User{ ID: *c.ID, Icon: c.Icon, @@ -570,8 +557,13 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser scanner.Scan() + // Make a new []byte slice and copy the scanner bytes to it. This is critical to avoid a data race as the + // scanner re-uses the buffer for subsequent scans. + buf := make([]byte, len(scanner.Bytes())) + copy(buf, scanner.Bytes()) + var clientLogin Transaction - if _, err := clientLogin.Write(scanner.Bytes()); err != nil { + if _, err := clientLogin.Write(buf); err != nil { return err } @@ -673,22 +665,20 @@ func (s *Server) handleNewConnection(ctx context.Context, rwc io.ReadWriteCloser } // Used simplified hotline v1.2.3 login flow for clients that do not send login info in tranAgreed - if c.Version == nil || bytes.Equal(c.Version, nostalgiaVersion) { - c.Agreed = true - c.logger = c.logger.With("name", string(c.UserName)) - c.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%v", func() int { i, _ := byteToInt(c.Version); return i }())) - - for _, t := range c.notifyOthers( - *NewTransaction( - tranNotifyChangeUser, nil, - NewField(fieldUserName, c.UserName), - NewField(fieldUserID, *c.ID), - NewField(fieldUserIconID, c.Icon), - NewField(fieldUserFlags, c.Flags), - ), - ) { - c.Server.outbox <- t - } + // TODO: figure out a generalized solution that doesn't require playing whack-a-mole for specific client versions + c.logger = c.logger.With("name", string(c.UserName)) + c.logger.Infow("Login successful", "clientVersion", fmt.Sprintf("%v", func() int { i, _ := byteToInt(c.Version); return i }())) + + for _, t := range c.notifyOthers( + *NewTransaction( + tranNotifyChangeUser, nil, + NewField(fieldUserName, c.UserName), + NewField(fieldUserID, *c.ID), + NewField(fieldUserIconID, c.Icon), + NewField(fieldUserFlags, c.Flags), + ), + ) { + c.Server.outbox <- t } c.Server.Stats.ConnectionCounter += 1 @@ -754,6 +744,10 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro delete(s.fileTransfers, t.ReferenceNumber) s.mux.Unlock() + // Wait a few seconds before closing the connection: this is a workaround for problems + // observed with Windows clients where the client must initiate close of the TCP connection before + // the server does. This is gross and seems unnecessary. TODO: Revisit? + time.Sleep(3 * time.Second) }() s.mux.Lock() @@ -788,7 +782,9 @@ func (s *Server) handleFileTransfer(ctx context.Context, rwc io.ReadWriter) erro case FileDownload: s.Stats.DownloadCounter += 1 s.Stats.DownloadsInProgress += 1 - defer func() { s.Stats.DownloadsInProgress -= 1 }() + defer func() { + s.Stats.DownloadsInProgress -= 1 + }() var dataOffset int64 if fileTransfer.fileResumeData != nil {