Răsfoiți Sursa

only allow one user logged in at a time

Mike 2 ani în urmă
părinte
comite
8ab369a4f0
4 a modificat fișierele cu 41 adăugiri și 16 ștergeri
  1. 2 1
      cmd/main.go
  2. 8 0
      oscar/frames.go
  3. 17 15
      server/protocol.go
  4. 14 0
      server/session.go

+ 2 - 1
cmd/main.go

@@ -121,10 +121,11 @@ func handleBOSConnection(cfg server.Config, sm *server.InMemorySessionManager, f
 	}
 	}
 
 
 	defer sess.Close()
 	defer sess.Close()
+	defer conn.Close()
+
 	go func() {
 	go func() {
 		<-sess.Closed()
 		<-sess.Closed()
 		server.Signout(sess, sm, fm)
 		server.Signout(sess, sm, fm)
-		conn.Close()
 	}()
 	}()
 
 
 	if err := server.ReadBos(cfg, sess, seq, sm, fm, cr, conn, server.ChatRoom{}, router); err != nil {
 	if err := server.ReadBos(cfg, sess, seq, sm, fm, cr, conn, server.ChatRoom{}, router); err != nil {

+ 8 - 0
oscar/frames.go

@@ -10,6 +10,14 @@ type SnacError struct {
 	TLVRestBlock
 	TLVRestBlock
 }
 }
 
 
+const (
+	FlapFrameSignon    uint8 = 0x01
+	FlapFrameData      uint8 = 0x02
+	FlapFrameError     uint8 = 0x03
+	FlapFrameSignoff   uint8 = 0x04
+	FlapFrameKeepAlive uint8 = 0x05
+)
+
 type FlapFrame struct {
 type FlapFrame struct {
 	StartMarker   uint8
 	StartMarker   uint8
 	FrameType     uint8
 	FrameType     uint8

+ 17 - 15
server/protocol.go

@@ -78,7 +78,7 @@ func Address(host string, port int) string {
 func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) (oscar.FlapSignonFrame, error) {
 func SendAndReceiveSignonFrame(rw io.ReadWriter, sequence *uint32) (oscar.FlapSignonFrame, error) {
 	flapFrameOut := oscar.FlapFrame{
 	flapFrameOut := oscar.FlapFrame{
 		StartMarker:   42,
 		StartMarker:   42,
-		FrameType:     1,
+		FrameType:     oscar.FlapFrameSignon,
 		Sequence:      uint16(*sequence),
 		Sequence:      uint16(*sequence),
 		PayloadLength: 4, // size of FlapSignonFrame
 		PayloadLength: 4, // size of FlapSignonFrame
 	}
 	}
@@ -170,14 +170,6 @@ type XMessage struct {
 	snacOut   any
 	snacOut   any
 }
 }
 
 
-const (
-	FlapFrameSignon    uint8 = 0x01
-	FlapFrameData            = 0x02
-	FlapFrameError           = 0x03
-	FlapFrameSignoff         = 0x04
-	FlapFrameKeepAlive       = 0x05
-)
-
 func sendInvalidSNACErr(snac oscar.SnacFrame, w io.Writer, sequence *uint32) error {
 func sendInvalidSNACErr(snac oscar.SnacFrame, w io.Writer, sequence *uint32) error {
 	snacFrameOut := oscar.SnacFrame{
 	snacFrameOut := oscar.SnacFrame{
 		FoodGroup: snac.FoodGroup,
 		FoodGroup: snac.FoodGroup,
@@ -201,10 +193,10 @@ func readIncomingRequests(rw io.Reader, msgCh chan IncomingMessage, errCh chan e
 		}
 		}
 
 
 		switch flap.FrameType {
 		switch flap.FrameType {
-		case FlapFrameSignon:
+		case oscar.FlapFrameSignon:
 			errCh <- errors.New("shouldn't get FlapFrameSignon")
 			errCh <- errors.New("shouldn't get FlapFrameSignon")
 			return
 			return
-		case FlapFrameData:
+		case oscar.FlapFrameData:
 			b := make([]byte, flap.PayloadLength)
 			b := make([]byte, flap.PayloadLength)
 			if _, err := rw.Read(b); err != nil {
 			if _, err := rw.Read(b); err != nil {
 				errCh <- err
 				errCh <- err
@@ -223,13 +215,13 @@ func readIncomingRequests(rw io.Reader, msgCh chan IncomingMessage, errCh chan e
 				snac: snac,
 				snac: snac,
 				buf:  buf,
 				buf:  buf,
 			}
 			}
-		case FlapFrameError:
+		case oscar.FlapFrameError:
 			errCh <- fmt.Errorf("got FlapFrameError: %v", flap)
 			errCh <- fmt.Errorf("got FlapFrameError: %v", flap)
 			return
 			return
-		case FlapFrameSignoff:
+		case oscar.FlapFrameSignoff:
 			errCh <- ErrSignedOff
 			errCh <- ErrSignedOff
 			return
 			return
-		case FlapFrameKeepAlive:
+		case oscar.FlapFrameKeepAlive:
 			fmt.Println("keepalive heartbeat")
 			fmt.Println("keepalive heartbeat")
 		default:
 		default:
 			errCh <- fmt.Errorf("unknown frame type: %v", flap)
 			errCh <- fmt.Errorf("unknown frame type: %v", flap)
@@ -277,12 +269,22 @@ func ReadBos(cfg Config, sess *Session, seq uint32, sm SessionManager, fm *Feedb
 			if err := writeOutSNAC(oscar.SnacFrame{}, m.snacFrame, m.snacOut, &seq, rwc); err != nil {
 			if err := writeOutSNAC(oscar.SnacFrame{}, m.snacFrame, m.snacOut, &seq, rwc); err != nil {
 				return err
 				return err
 			}
 			}
+		case <-sess.Closed():
+			return gracefulDisconnect(seq, rwc)
 		case err := <-errCh:
 		case err := <-errCh:
 			return err
 			return err
 		}
 		}
 	}
 	}
 }
 }
 
 
+func gracefulDisconnect(seq uint32, rwc io.ReadWriter) error {
+	return oscar.Marshal(oscar.FlapFrame{
+		StartMarker: 42,
+		FrameType:   oscar.FlapFrameSignoff,
+		Sequence:    uint16(seq),
+	}, rwc)
+}
+
 func NewRouter() Router {
 func NewRouter() Router {
 	return Router{
 	return Router{
 		AlertRouter:    NewAlertRouter(),
 		AlertRouter:    NewAlertRouter(),
@@ -353,7 +355,7 @@ func writeOutSNAC(originsnac oscar.SnacFrame, snacFrame oscar.SnacFrame, snacOut
 
 
 	flap := oscar.FlapFrame{
 	flap := oscar.FlapFrame{
 		StartMarker:   42,
 		StartMarker:   42,
-		FrameType:     2,
+		FrameType:     oscar.FlapFrameData,
 		Sequence:      uint16(*sequence),
 		Sequence:      uint16(*sequence),
 		PayloadLength: uint16(snacBuf.Len()),
 		PayloadLength: uint16(snacBuf.Len()),
 	}
 	}

+ 14 - 0
server/session.go

@@ -293,6 +293,20 @@ func makeSession() *Session {
 func (s *InMemorySessionManager) NewSessionWithSN(sessID string, screenName string) *Session {
 func (s *InMemorySessionManager) NewSessionWithSN(sessID string, screenName string) *Session {
 	s.mapMutex.Lock()
 	s.mapMutex.Lock()
 	defer s.mapMutex.Unlock()
 	defer s.mapMutex.Unlock()
+
+	// Only allow one session at a time per screen name. A session may already
+	// exist because:
+	// 1) the user is signing on using an already logged-on screen name.
+	// 2) the session might be orphaned due to an undetected client
+	// disconnection.
+	for _, sess := range s.store {
+		if screenName == sess.ScreenName {
+			sess.Close()
+			delete(s.store, sess.ID)
+			break
+		}
+	}
+
 	sess := makeSession()
 	sess := makeSession()
 	sess.ID = sessID
 	sess.ID = sessID
 	sess.ScreenName = screenName
 	sess.ScreenName = screenName