Example #1
0
// Checks for "attach <id>" entries attaching this node ID to sessions we lack
// a connection to. Starts a timer to delete them if present.
// Must be called during a transaction, holding the session lock.
func checkOrphanAttaches() {
	attachedTo := store.AllAttachedTo(uint64(config.Id()))

	for _, session := range attachedTo {
		if sessions[session] == nil {
			startOrphanTimeout(session)
		}
	}
}
Example #2
0
// Must be called in a transaction, holding session and waiting locks.
func handleAuthComplete(conn *userConn, idemChanges []store.Change) {

	// We're no longer waiting for authentication to complete.
	delete(waiting, conn.waitingAuth.requestId)
	waitingAuth := conn.waitingAuth
	conn.waitingAuth = nil

	// Find the created session entity.
	newSessionId := uint64(0)
	for i := range idemChanges {
		if idemChanges[i].Key == "kind" &&
			idemChanges[i].Value == "session" {

			newSessionId = idemChanges[i].TargetEntity
			break
		}
	}

	// Check session exists.
	session := store.GetEntity(newSessionId)
	if session == nil ||
		session.Value("kind") != "session" {
		sendAuthFail(conn, "Session Deleted")
		return
	}

	// Check it is attached to a user.
	attachedTo := store.AllAttachedTo(newSessionId)
	if len(attachedTo) == 0 {
		sendAuthFail(conn, "User Deleted")
		return
	}

	// Check that user has a username.
	user := store.GetEntity(attachedTo[0])
	if user.Value("name username") == "" {
		sendAuthFail(conn, "Username Already In Use")

		// TODO: Should request deletion of user, leaning on timeout.
		return
	}

	// This connection is successfully authenticated with that session.
	conn.session = newSessionId

	// If there is an existing connection associated with that session,
	// drop it.
	if existingConn := sessions[newSessionId]; existingConn != nil {
		existingConn.conn.Close()
	}

	sessions[conn.session] = conn
	sendAuthSuccess(conn, waitingAuth.password)
}
Example #3
0
// Main function for the handling goroutine for conn.
func handleConn(conn *userConn) {

	// Do cleanup in a defer, so if they crash us we still tidy up here.
	// A small nod towards tolerating bad input, with much more needed.
	defer func() {
		// Remove the connection from our connection set if present.
		// It will not be present if we are degraded or similar.
		connectionsLock.Lock()

		if _, exists := connections[conn]; exists {
			delete(connections, conn)
		}

		// Remove the connection from our waiting map if present.
		// This must happen before session removal, as otherwise
		// auth could complete between the session check and this one.
		waitingLock.Lock()
		if conn.waitingAuth != nil {
			waitingConn := waiting[conn.waitingAuth.requestId]
			if waitingConn == conn {
				delete(waiting, conn.waitingAuth.requestId)
			}
		}
		waitingLock.Unlock()

		// Remove the connection from our sessions map if present.
		// It will not be present if we are degraded,
		// or have replaced this connection.
		sessionsLock.Lock()
		if conn.session != 0 {
			sessionConn := sessions[conn.session]
			if sessionConn == conn {
				delete(sessions, conn.session)

				// Send a change detaching this node
				// from that session.
				idStr := strconv.FormatUint(uint64(config.Id()),
					10)
				ourAttachStr := "attach " + idStr

				chset := make([]store.Change, 1)
				chset[0].TargetEntity = conn.session
				chset[0].Key = ourAttachStr
				chset[0].Value = ""

				req := makeRequest(chset)
				go chrequest.Request(req)
			}

		}
		sessionsLock.Unlock()

		connectionsLock.Unlock()
	}()

	for {
		select {
		case msg, ok := <-conn.conn.Received:
			if !ok {
				return
			}

			switch *msg.MsgType {
			case 2:
				handleAuth(conn, msg.Content)
			case 3:
				handleFollowUsername(conn, msg.Content)
			case 4:
				handleFollowUser(conn, msg.Content)
			case 5:
				handleStopFollowingUser(conn, msg.Content)
			case 6:
				handleSend(conn, msg.Content)
			default:
				conn.conn.Close()
			}

		case userMsg := <-conn.deliver:

			// Get the sender's user ID.
			store.StartTransaction()
			attachedTo := store.AllAttachedTo(userMsg.Sender)
			store.EndTransaction()

			// We don't know who the sender is. Drop message.
			if len(attachedTo) == 0 {
				break
			}

			// Deliver any user messages given to us.
			var deliverMsg cliproto_down.Received
			deliverMsg.SenderUserId = new(uint64)
			deliverMsg.SenderSessionId = new(uint64)
			deliverMsg.Tag = new(string)
			deliverMsg.Content = new(string)
			*deliverMsg.SenderUserId = attachedTo[0]
			*deliverMsg.SenderSessionId = userMsg.Sender
			*deliverMsg.Tag = userMsg.Tag
			*deliverMsg.Content = userMsg.Content

			conn.conn.SendProto(10, &deliverMsg)
		}
	}

}