4
0
Эх сурвалжийг харах

fix flap signoff tests and document methods

Mike 10 сар өмнө
parent
commit
dbf385c5b7

+ 14 - 14
server/oscar/server.go

@@ -568,9 +568,13 @@ func (s oscarServer) dispatchIncomingMessages(
 				}
 			}
 		case <-sess.Closed():
-			block := wire.TLVRestBlock{}
 			// add logoff reason to clients that support multi-conn
-			if sess.MultiConnFlag() != wire.MultiConnFlagsOldClient {
+			if sess.MultiConnFlag() == wire.MultiConnFlagsOldClient {
+				if err := flapc.OldSignoff(); err != nil {
+					return fmt.Errorf("unable to gracefully disconnect user. %w", err)
+				}
+			} else {
+				block := wire.TLVRestBlock{}
 				// error code indicating user signed in a different location
 				block.Append(wire.NewTLVBE(0x0009, wire.OServiceDiscErrNewLogin))
 				// "more info" button
@@ -579,20 +583,16 @@ func (s oscarServer) dispatchIncomingMessages(
 					return fmt.Errorf("unable to gracefully disconnect user. %w", err)
 				}
 			}
-			if err := flapc.OldSignoff(); err != nil {
-				return fmt.Errorf("unable to gracefully disconnect user. %w", err)
-			}
 			return nil
 		case <-ctx.Done():
-			block := wire.TLVRestBlock{}
-			// send explicit disconnect notification to client since proxies
-			// between client and server may not properly terminate connections
-			if err := flapc.NewSignoff(block); err != nil {
-				return fmt.Errorf("unable to gracefully disconnect user. %w", err)
-			}
-			// application is shutting down
-			if err := flapc.OldSignoff(); err != nil {
-				return fmt.Errorf("unable to gracefully disconnect user. %w", err)
+			if sess.MultiConnFlag() == wire.MultiConnFlagsOldClient {
+				if err := flapc.OldSignoff(); err != nil {
+					return fmt.Errorf("unable to gracefully disconnect user. %w", err)
+				}
+			} else {
+				if err := flapc.NewSignoff(wire.TLVRestBlock{}); err != nil {
+					return fmt.Errorf("unable to gracefully disconnect user. %w", err)
+				}
 			}
 			return nil
 		case err := <-errCh:

+ 1 - 0
server/oscar/server_test.go

@@ -634,6 +634,7 @@ func Test_oscarServer_dispatchIncomingMessages_shutdownSignoff(t *testing.T) {
 			Logger: slog.Default(),
 		}
 		sess := state.NewSession()
+		sess.SetMultiConnFlag(wire.MultiConnFlagsRecentClient)
 		flapc := wire.NewFlapClient(0, serverConn, serverConn)
 		err := srv.dispatchIncomingMessages(ctx, wire.BOS, sess, flapc, serverConn, config.Listener{})
 		assert.NoError(t, err)

+ 13 - 2
wire/frames.go

@@ -148,7 +148,13 @@ func (f *FlapClient) ReceiveFLAP() (FLAPFrame, error) {
 	return flap, err
 }
 
-// OldSignoff sends a signoff FLAP frame to clients that don't support multi-conn.
+// OldSignoff sends a signoff FLAP frame for legacy clients that do not
+// support multi-connection (Windows AIM 1.x–4.1).
+//
+// When these clients receive this frame, they display a "connection lost"
+// message and close the session. Unlike normal FLAP frames, this variant
+// omits the payload size field. If the size field were present, the client
+// would hang without displaying any message upon server disconnection.
 func (f *FlapClient) OldSignoff() error {
 	f.mutex.Lock()
 	defer f.mutex.Unlock()
@@ -161,7 +167,12 @@ func (f *FlapClient) OldSignoff() error {
 	return MarshalBE(flap, f.w)
 }
 
-// NewSignoff sends a signoff FLAP frame to multi-conn clients with metadata.
+// NewSignoff sends a signoff FLAP frame for multi-connection clients.
+//
+// The frame includes a TLV block with additional metadata such as error codes.
+// Client behavior depends on the version:
+//   - AIM 4.3–5.x: the client minimizes and enters a "signed off" state.
+//   - AIM 6.x–7.x: the client closes and displays a disconnection error.
 func (f *FlapClient) NewSignoff(tlvs TLVRestBlock) error {
 	tlvBuf := &bytes.Buffer{}
 	if err := MarshalBE(tlvs, tlvBuf); err != nil {