예제 #1
0
// newSocket creates a new socket and initializes it.
func newSocket(server *Server, bs backend.BackendSocket) *Socket {
	// Create a new socket value.
	s := &Socket{
		server: server,
		bs:     bs,

		id:       utils.RandomString(socketIDLength),
		channels: newChannels(),

		writeChan:    bs.WriteChan(),
		readChan:     bs.ReadChan(),
		isClosedChan: make(chan struct{}),

		pingTimer:   time.NewTimer(pingPeriod),
		pingTimeout: time.NewTimer(pingResponseTimeout),
	}

	// Create the main channel.
	s.mainChannel = s.Channel(mainChannelName)

	// Set the event functions.
	bs.OnClose(s.onClose)

	// Stop the timeout again. It will be started by the ping timer.
	s.pingTimeout.Stop()

	// Add the new socket to the active sockets map.
	// If the ID is already present, then generate a new one.
	func() {
		// Lock the mutex.
		s.server.socketsMutex.Lock()
		defer s.server.socketsMutex.Unlock()

		// Be sure that the ID is unique.
		for {
			if _, ok := s.server.sockets[s.id]; !ok {
				break
			}

			s.id = utils.RandomString(socketIDLength)
		}

		// Add the socket to the map.
		s.server.sockets[s.id] = s
	}()

	// Start the loops and handlers in new goroutines.
	go s.pingTimeoutHandler()
	go s.readLoop()
	go s.pingLoop()

	return s
}
예제 #2
0
func (s *Server) initAjaxRequest(remoteAddr, userAgent string, w http.ResponseWriter) {
	var uid string

	// Create a new ajax socket value.
	a := newSocket(s)
	a.remoteAddr = remoteAddr
	a.userAgent = userAgent

	func() {
		// Lock the mutex
		s.socketsMutex.Lock()
		defer s.socketsMutex.Unlock()

		// Obtain a new unique ID.
		for {
			// Generate it.
			uid = utils.RandomString(ajaxUIDLength)

			// Check if the new UID is already used.
			// This is very unlikely, but we have to check this!
			_, ok := s.sockets[uid]
			if !ok {
				// Break the loop if the UID is unique.
				break
			}
		}

		// Set the UID.
		a.uid = uid

		// Add the new ajax socket to the map.
		s.sockets[uid] = a
	}()

	// Create a new poll token.
	a.pollToken = utils.RandomString(ajaxPollTokenLength)

	// Tell the client the UID and poll token.
	io.WriteString(w, uid+ajaxSocketDataDelimiter+a.pollToken)

	// Trigger the event that a new socket connection was made.
	s.onNewSocketConnection(a)
}
예제 #3
0
func (s *Server) pollAjaxRequest(uid, remoteAddr, userAgent, data string, w http.ResponseWriter) {
	// Obtain the ajax socket with the uid.
	a := func() *Socket {
		// Lock the mutex.
		s.socketsMutex.Lock()
		defer s.socketsMutex.Unlock()

		// Obtain the ajax socket with the uid-
		a, ok := s.sockets[uid]
		if !ok {
			return nil
		}
		return a
	}()

	if a == nil {
		log.L.WithFields(logrus.Fields{
			"remoteAddress": remoteAddr,
			"userAgent":     userAgent,
			"uid":           uid,
		}).Warningf("ajax: client requested an invalid ajax socket: uid is invalid!")

		http.Error(w, "Bad Request", 400)
		return
	}

	// The user agents have to match.
	if a.userAgent != userAgent {
		log.L.WithFields(logrus.Fields{
			"remoteAddress":   remoteAddr,
			"userAgent":       userAgent,
			"uid":             uid,
			"clientUserAgent": userAgent,
			"socketUserAgent": a.userAgent,
		}).Warningf("ajax: client poll request: user agents do not match!")

		http.Error(w, "Bad Request", 400)
		return
	}

	// Check if the poll tokens matches.
	// The poll token is the data value.
	if a.pollToken != data {
		log.L.WithFields(logrus.Fields{
			"remoteAddress":   remoteAddr,
			"userAgent":       userAgent,
			"uid":             uid,
			"clientPollToken": data,
			"socketPollToken": a.pollToken,
		}).Warningf("ajax: client poll request: poll tokens do not match!")

		http.Error(w, "Bad Request", 400)
		return
	}

	// Create a new poll token.
	a.pollToken = utils.RandomString(ajaxPollTokenLength)

	// Create a timeout timer for the poll.
	timeout := time.NewTimer(ajaxPollTimeout)

	defer func() {
		// Stop the timeout timer.
		timeout.Stop()
	}()

	// Send messages as soon as there are some available.
	select {
	case data := <-a.writeChan:
		// Send the new poll token and message data to the client.
		io.WriteString(w, a.pollToken+ajaxSocketDataDelimiter+data)
	case <-timeout.C:
		// Tell the client that this ajax connection has reached the timeout.
		io.WriteString(w, ajaxPollCmdTimeout)
	case <-a.closer.IsClosedChan:
		// Tell the client that this ajax connection is closed.
		io.WriteString(w, ajaxPollCmdClosed)
	}
}