Exemple #1
0
func (c *WebConn) WritePump() {
	ticker := time.NewTicker(PING_PERIOD)
	authTicker := time.NewTicker(AUTH_TIMEOUT)

	defer func() {
		ticker.Stop()
		authTicker.Stop()
		c.WebSocket.Close()
	}()

	for {
		select {
		case msg, ok := <-c.Send:
			if !ok {
				c.WebSocket.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
				c.WebSocket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			c.WebSocket.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
			if err := c.WebSocket.WriteMessage(websocket.TextMessage, msg.GetPreComputeJson()); err != nil {
				// browsers will appear as CloseNoStatusReceived
				if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
					l4g.Debug(fmt.Sprintf("websocket.send: client side closed socket userId=%v", c.UserId))
				} else {
					l4g.Debug(fmt.Sprintf("websocket.send: closing websocket for userId=%v, error=%v", c.UserId, err.Error()))
				}

				return
			}

			if msg.EventType() == model.WEBSOCKET_EVENT_POSTED {
				if einterfaces.GetMetricsInterface() != nil {
					einterfaces.GetMetricsInterface().IncrementPostBroadcast()
				}
			}

		case <-ticker.C:
			c.WebSocket.SetWriteDeadline(time.Now().Add(WRITE_WAIT))
			if err := c.WebSocket.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
				// browsers will appear as CloseNoStatusReceived
				if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
					l4g.Debug(fmt.Sprintf("websocket.ticker: client side closed socket userId=%v", c.UserId))
				} else {
					l4g.Debug(fmt.Sprintf("websocket.ticker: closing websocket for userId=%v error=%v", c.UserId, err.Error()))
				}

				return
			}

		case <-authTicker.C:
			if c.SessionToken == "" {
				l4g.Debug(fmt.Sprintf("websocket.authTicker: did not authenticate ip=%v", c.WebSocket.RemoteAddr()))
				return
			}
			authTicker.Stop()
		}
	}
}
Exemple #2
0
func (np *NatsProxy) activateWSProxySubject(conn *websocket.Conn, wsID string) {
	np.addToWSMapper(conn, wsID)
	np.conn.Subscribe("WS_OUT"+wsID, func(m *nats.Msg) {
		err := conn.WriteMessage(websocket.TextMessage, m.Data)
		if err != nil {
			log.Println("Error writing a message", err)
		}
	})
	go func() {
		for {
			if _, p, err := conn.ReadMessage(); err == nil {
				np.conn.Publish("WS_IN"+wsID, p)
			} else {
				np.removeFromWSMapper(conn, wsID)
				conn.Close()
				// If websocket is closed normally RFC6455
				// code 1000, then no error logged
				if !websocket.IsCloseError(err, websocket.CloseNormalClosure) {
					logWebsocketError(wsID, err)
				}
				break
			}
		}
	}()
}
func (wsc *WebSocketClient) Listen() {
	go func() {
		defer func() {
			wsc.Conn.Close()
			close(wsc.EventChannel)
			close(wsc.ResponseChannel)
		}()

		for {
			var rawMsg json.RawMessage
			var err error
			if _, rawMsg, err = wsc.Conn.ReadMessage(); err != nil {
				if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
					wsc.ListenError = NewLocAppError("NewWebSocketClient", "model.websocket_client.connect_fail.app_error", nil, err.Error())
				}

				return
			}

			var event WebSocketEvent
			if err := json.Unmarshal(rawMsg, &event); err == nil && event.IsValid() {
				wsc.EventChannel <- &event
				continue
			}

			var response WebSocketResponse
			if err := json.Unmarshal(rawMsg, &response); err == nil && response.IsValid() {
				wsc.ResponseChannel <- &response
				continue
			}

		}
	}()
}
Exemple #4
0
func (h *Hijacker) handleOutput(conn *websocket.Conn, pio ProcessIO) int {
	var exitStatus int
	for {
		var output atc.HijackOutput
		err := conn.ReadJSON(&output)
		if err != nil {
			if !websocket.IsCloseError(err) && !websocket.IsUnexpectedCloseError(err) {
				fmt.Println(err)
			}
			break
		}

		if output.ExitStatus != nil {
			exitStatus = *output.ExitStatus
		} else if len(output.Error) > 0 {
			fmt.Fprintf(os.Stderr, "%s\n", ansi.Color(output.Error, "red+b"))
			exitStatus = 255
		} else if len(output.Stdout) > 0 {
			pio.Out.Write(output.Stdout)
		} else if len(output.Stderr) > 0 {
			pio.Err.Write(output.Stderr)
		}
	}

	return exitStatus
}
Exemple #5
0
func (c *WebConn) ReadPump() {
	defer func() {
		HubUnregister(c)
		c.WebSocket.Close()
	}()
	c.WebSocket.SetReadLimit(model.SOCKET_MAX_MESSAGE_SIZE_KB)
	c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
	c.WebSocket.SetPongHandler(func(string) error {
		c.WebSocket.SetReadDeadline(time.Now().Add(PONG_WAIT))
		if c.IsAuthenticated() {
			go SetStatusAwayIfNeeded(c.UserId, false)
		}
		return nil
	})

	for {
		var req model.WebSocketRequest
		if err := c.WebSocket.ReadJSON(&req); err != nil {
			// browsers will appear as CloseNoStatusReceived
			if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseNoStatusReceived) {
				l4g.Debug(fmt.Sprintf("websocket.read: client side closed socket userId=%v", c.UserId))
			} else {
				l4g.Debug(fmt.Sprintf("websocket.read: closing websocket for userId=%v error=%v", c.UserId, err.Error()))
			}

			return
		} else {
			Srv.WebSocketRouter.ServeWebSocket(c, &req)
		}
	}
}
Exemple #6
0
// IsExpectedWSCloseError returns boolean indicating whether the error is a
// clean disconnection.
func IsExpectedWSCloseError(err error) bool {
	return err == io.EOF || err == io.ErrClosedPipe || websocket.IsCloseError(err,
		websocket.CloseNormalClosure,
		websocket.CloseGoingAway,
		websocket.CloseNoStatusReceived,
		websocket.CloseAbnormalClosure,
	)
}
Exemple #7
0
// IsExpectedWSCloseError returns boolean indicating whether the error is a
// clean disconnection.
func IsExpectedWSCloseError(err error) bool {
	return websocket.IsCloseError(
		err,
		websocket.CloseNormalClosure,
		websocket.CloseGoingAway,
		websocket.CloseNoStatusReceived,
	)
}
Exemple #8
0
func (ep *websocketPeer) run() {
	go ep.sending()

	if ep.MaxMsgSize > 0 {
		ep.conn.SetReadLimit(ep.MaxMsgSize)
	}
	ep.conn.SetPongHandler(func(v string) error {
		log.Println("pong:", v)
		ep.updateReadDeadline()
		return nil
	})
	ep.conn.SetPingHandler(func(v string) error {
		log.Println("ping:", v)
		ep.updateReadDeadline()
		return nil
	})

	for {
		// TODO: use conn.NextMessage() and stream
		// TODO: do something different based on binary/text frames
		ep.updateReadDeadline()
		if msgType, b, err := ep.conn.ReadMessage(); err != nil {
			if ep.isClosed() {
				log.Println("peer connection closed")
			} else {
				log.Println("error reading from peer:", err)
				if !websocket.IsCloseError(err) {
					ep.conn.Close()
				}
			}
			log.Println("Closing channel")
			close(ep.messages)
			break
		} else if msgType == websocket.CloseMessage {
			ep.conn.Close()
			close(ep.messages)
			break
		} else {
			msg, err := ep.serializer.Deserialize(b)
			if err != nil {
				log.Println("error deserializing peer message:", err)
				// TODO: handle error
			} else {
				ep.messages <- msg
			}
		}
	}
}
Exemple #9
0
func isReadFromClosedConnError(err error) bool {
	return websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseAbnormalClosure)
}
Exemple #10
0
// @Title getSignalsWs
// @router /signal/:name/ws [get]
func (c *ClientController) WebSocket() {
	name := c.GetString(":name")
	beego.Debug("[C] Got name:", name)
	if name != "" {
		host := &models.Hosts{
			Name: name,
		}
		hosts, err := models.GetHosts(host, 1, 0)
		if err != nil {
			c.Data["json"] = map[string]string{
				"message": fmt.Sprint("Failed to get with name:", name),
				"error":   err.Error(),
			}
			beego.Warn("[C] Got error:", err)
			c.Ctx.Output.SetStatus(http.StatusInternalServerError)
			c.ServeJSON()
			return
		}
		if len(hosts) == 0 {
			beego.Debug("[C] Got nothing with name:", name)
			c.Ctx.Output.SetStatus(http.StatusNotFound)
			c.ServeJSON()
			return
		}
		HostId := hosts[0].Id

		ws, err := websocket.Upgrade(
			c.Ctx.ResponseWriter, c.Ctx.Request,
			nil, 1024, 1024)
		if err != nil {
			c.Data["json"] = map[string]string{
				"message": "Failed on upgrading to websocket",
				"error":   err.Error(),
			}
			beego.Warn("[C] Got error:", err)
			c.Ctx.Output.SetStatus(http.StatusInternalServerError)
			c.ServeJSON()
			return
		}
		defer ws.Close()

		tick, err := beego.AppConfig.Int64("websocket::pingperiod")
		if err != nil {
			tick = 5
		}
		ticker := time.NewTicker(
			time.Duration(tick) * time.Second)
		defer ticker.Stop()

		timeout, err := beego.AppConfig.Int64("websocket::timeout")
		if err != nil {
			timeout = 10
		}
		ws.SetReadDeadline(time.Now().Add(
			time.Duration(timeout) * time.Second),
		)
		ws.SetWriteDeadline(time.Now().Add(
			time.Duration(timeout) * time.Second),
		)
		ws.SetPongHandler(func(string) error {
			beego.Debug("Host:", name, "is still alive.")
			ws.SetReadDeadline(time.Now().Add(
				time.Duration(timeout) * time.Second),
			)
			ws.SetWriteDeadline(time.Now().Add(
				time.Duration(timeout) * time.Second),
			)
			return nil
		})
		var c chan models.Signal
		c, ok := models.SignalChannels[HostId]
		if !ok {
			c = make(chan models.Signal, 1024)
			models.SignalChannels[HostId] = c
		}

		// Start read routine
		go func() {
			defer ws.Close()
			for {
				_, bConfirm, err := ws.ReadMessage()
				if websocket.IsCloseError(err,
					websocket.CloseGoingAway) {
					beego.Info("Host", name, "is offline.")
					return
				} else if err != nil {
					beego.Warn("Error on reading:", err.Error())
					return
				}
				s := strings.Split(string(bConfirm), " ")
				if s[0] == ClientWebSocketReplyDone {
					models.DeleteSignal(HostId, s[1])
				}
			}
		}()

		for {
			select {
			case s := <-models.SignalChannels[HostId]:
				ws.WriteJSON(s)
			case <-ticker.C:
				beego.Debug("Websocket ping:", name)
				err := ws.WriteMessage(websocket.PingMessage, []byte{})
				if err != nil {
					beego.Warn("Got error on ping", err.Error())
					return
				}
			}
		}
	}
}
// ClientHandler handles all client interactions
func ClientHandler(conn *websocket.Conn) {
	var err error

	client := types.NewClient()
	client.Conn = conn
	client.User = new(types.User)
	// Set the UUID and initialize a username of "guest"
	client.User.ID, err = getUniqueID()
	if err != nil {
		logger.Error(err)
	}

	guests, err := dbClient.GetKeySet("user-guest-*-*")
	if err != nil {
		logger.Error(err)
	}

	// TODO give guests a numeric suffix, allow disabling guest connections.
	client.User.Username = "******" + strconv.Itoa(len(guests)+1)
	client.User.LoginName = client.User.Username
	client.User.Type = "guest"
	client.User.Connected = true

	clients[client.User.ID.String()] = client

	if config.AllowGuests {
		defgroup, err := GetGroup("#default")
		if err != nil {
			logger.Error(err)
		}
		defgroup.Users[client.User.ID.String()] = client.User
		client.User.Groups = append(client.User.Groups, "#default")
		room, err := GetRoom("#default", "#general")
		if err != nil {
			logger.Error(err)
		}
		client.User.Rooms = append(client.User.Rooms, "#default/#general")
		room.Users[client.User.ID.String()] = client.User

		dbClient.WriteUserData(client.User)
		dbClient.WriteGroupData(defgroup)
		dbClient.WriteRoomData(room)

		logger.Info("guest", client.User.ID.String(), "connected")
	} else {
		logger.Info("new client connected")
	}

	if err := client.Alert(types.OK, ""); err != nil {
		logger.Error(err)
	}

	/* TODO we may want to remove this later it's just for easy testing.
	 * to allow a client to get their UUID back from the server after
	 * connecting. */
	if config.AllowGuests {
		if err := client.Alert(types.GeneralNotice, string("Connected as guest with ID "+client.User.ID.String())); err != nil {
			logger.Error(err)
		}
	} else {
		if err := client.Alert(types.ImportantNotice, "No Guests Allowed : send authentication token to continue"); err != nil {
			logger.Error(err)
		}
	}

	/* Never return from this loop!
	 * Never break from this loop unless intending to disconnect the client. */
	for {
		_, rawmsg, err := client.Conn.ReadMessage()
		if err != nil {
			switch {
			case websocket.IsCloseError(err, websocket.CloseNormalClosure):
				if client.User != nil {
					logger.Info(client.User.Type, client.User.ID.String(), "disconnected")
				} else {
					logger.Info("client disconnected")
				}
				break
			// TODO handle these different cases appropriately.
			case websocket.IsCloseError(err, websocket.CloseGoingAway):
			case websocket.IsCloseError(err, websocket.CloseProtocolError, websocket.CloseUnsupportedData):
				// This should utilize the ban-score to combat possible spammers
			case websocket.IsCloseError(err, websocket.ClosePolicyViolation, websocket.CloseMessageTooBig):
				// These should also utilize the ban-score but with a higher ban
			default:
				logger.Info(err)
			}
			break
		}

		ban, err := ParseMessage(client, rawmsg)
		if err != nil {
			logger.Info(err)
		}
		if ban > 0 {
			// TODO handle ban-score
			break
		}
	}

	// We broke out of the loop so disconnect the client.
	client.Conn.Close()
	if client.User != nil {
		if client.User.Type == "guest" {
			if err := dbClient.DeleteUser(client.User); err != nil {
				logger.Error(err)
			}
		} else {
			client.User.Connected = false
			dbClient.WriteUserData(client.User)
		}
	}

	delete(clients, client.User.ID.String())
}
Exemple #12
0
					fakeDBContainer = db.Container{}
					containerDB.GetContainerReturns(fakeDBContainer, true, nil)

					fakeContainer = new(workerfakes.FakeContainer)
					fakeWorkerClient.LookupContainerReturns(fakeContainer, true, nil)
				})

				Context("when the call to lookup the container returns an error", func() {
					BeforeEach(func() {
						fakeWorkerClient.LookupContainerReturns(nil, false, errors.New("nope"))
					})

					It("closes the websocket connection with an error", func() {
						_, _, err := conn.ReadMessage()

						Expect(websocket.IsCloseError(err, 1011)).To(BeTrue()) // internal server error
						Expect(err).To(MatchError(ContainSubstring("failed to lookup container")))
					})
				})

				Context("when the container could not be found on the worker client", func() {
					BeforeEach(func() {
						fakeWorkerClient.LookupContainerReturns(nil, false, nil)
					})

					It("closes the websocket connection with an error", func() {
						_, _, err := conn.ReadMessage()

						Expect(websocket.IsCloseError(err, 1011)).To(BeTrue()) // internal server error
						Expect(err).To(MatchError(ContainSubstring("could not find container")))
					})