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() } } }
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 } } }() }
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 }
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) } } }
// 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, ) }
// 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, ) }
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 } } } }
func isReadFromClosedConnError(err error) bool { return websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) }
// @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()) }
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"))) })