Beispiel #1
0
// Write received messages from a channel to the websocket client
func FrameServer(conn *websocket.Conn) {
	// Set the PayloadType to binary
	conn.PayloadType = websocket.BinaryFrame

	client := NewClient()

	registerClient <- client
	defer func() {
		unregisterClient <- client
	}()

	// Write the header as the first message to the client (MPEG size etc.)
	conn.SetWriteDeadline(time.Now().Add(ClientWriteTimeout * time.Second))
	if _, err := conn.Write(*headerMessage); err != nil {
		return
	}

	// Continuously read messages from the queue and write to the client, stop on error
	for msg := range client.queue {
		conn.SetWriteDeadline(time.Now().Add(ClientWriteTimeout * time.Second))
		if _, err := conn.Write(*msg); err != nil {
			return
		}
	}
}
Beispiel #2
0
func WsBuildServer(ws *websocket.Conn) {
	defer ws.Close()
	var err error
	clientMsg := new(Message)
	if err = websocket.JSON.Receive(ws, &clientMsg); err != nil {
		Debugf("read json error: %v", err)
		return
	}
	addr := clientMsg.Data
	name := ws.RemoteAddr().String()
	log.Println("handle request project:", addr, name)

	proj := NewProject(addr, name)
	defer proj.Close()

	firstMsg := &Message{
		Data: proj.BufferStr,
	}
	err = websocket.JSON.Send(ws, firstMsg)
	if err != nil {
		Debugf("send first msg error: %v", err)
		return
	}

	// send the rest outputs
	buf := make([]byte, 100)
	msg := new(Message)
	for {
		n, err := proj.Reader.Read(buf)
		if n > 0 {
			msg.Data = string(buf[:n])
			deadline := time.Now().Add(time.Second * 1)
			ws.SetWriteDeadline(deadline)
			if er := websocket.JSON.Send(ws, msg); er != nil {
				log.Println("write failed timeout, user logout")
				return
			}
		}
		if err != nil {
			return
		}
	}
	log.Println(addr, "loop ends")
}
Beispiel #3
0
func (t *Server) HandleWebsocket(conn *websocket.Conn) {
	defer conn.Close()

	log.Debug("turnpike: received websocket connection")

	tid, err := uuid.NewV4()
	if err != nil {
		log.Error("turnpike: could not create unique id, refusing client connection")
		return
	}
	id := tid.String()
	log.Info("turnpike: client connected: %s", id)

	arr, err := CreateWelcome(id, TURNPIKE_SERVER_IDENT)
	if err != nil {
		log.Error("turnpike: error encoding welcome message")
		return
	}
	log.Debug("turnpike: sending welcome message: %s", arr)
	err = websocket.Message.Send(conn, string(arr))
	if err != nil {
		log.Error("turnpike: error sending welcome message, aborting connection: %s", err)
		return
	}

	c := make(chan string, serverBacklog)
	t.clients[id] = c

	failures := 0
	go func() {
		for msg := range c {
			log.Trace("turnpike: sending message: %s", msg)
			conn.SetWriteDeadline(time.Now().Add(CLIENT_CONN_TIMEOUT * time.Second))
			err := websocket.Message.Send(conn, msg)
			if err != nil {
				if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) {
					log.Warn("Network error: %s", nErr)
					failures++
					if failures > CLIENT_MAX_FAILURES {
						break
					}
				} else {
					log.Error("turnpike: error sending message: %s", err)
					break
				}
			}
		}
		log.Info("Client %s disconnected", id)
		t.subLock.Lock()
		rooms := t.Rooms.FindClient(id)
		t.subLock.Unlock()
		for r := rooms.Front(); r != nil; r = r.Next() {
			room := r.Value.(*Room)
			room.RemoveClientByID(id)
			log.Debug("Removing client %s from room", id)
		}
		conn.Close()
	}()

	for {
		var rec string
		err := websocket.Message.Receive(conn, &rec)
		if err != nil {
			if err != io.EOF {
				log.Error("turnpike: error receiving message, aborting connection: %s", err)
			}
			break
		}
		log.Trace("turnpike: message received: %s", rec)

		data := []byte(rec)

		switch typ := ParseType(rec); typ {
		case PREFIX:
			var msg PrefixMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike: error unmarshalling prefix message: %s", err)
				continue
			}
			t.handlePrefix(id, msg)
		case CALL:
			var msg CallMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike: error unmarshalling call message: %s", err)
				continue
			}
			t.handleCall(id, msg)
		case SUBSCRIBE:
			var msg SubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike: error unmarshalling subscribe message: %s", err)
				continue
			}
			// Check access
			t.handleSubscribe(id, msg)
		case UNSUBSCRIBE:
			var msg UnsubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike: error unmarshalling unsubscribe message: %s", err)
				continue
			}
			t.handleUnsubscribe(id, msg)
		case PUBLISH:
			var msg PublishMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike: error unmarshalling publish message: %s", err)
				continue
			}
			// check master
			room, r := t.Rooms.Contains(msg.TopicURI)
			if !r {
				log.Error("turnpike: Room does not exist: %s", msg.TopicURI)
				return
			}
			if !room.IsMaster(id) {
				if room.Auth(id) {
					if !jsonDataCheck(msg.Event.(map[string]interface{}), "type", "echo") {
						log.Trace("NOT ECHO Message")
						continue
					}
					log.Debug("ECHO Message Sent from client %s", id)
				} else {
					log.Warn("Client %s not authenticated", id)
					continue
				}
			}
			t.handlePublish(id, msg)
		case AUTH:
			var msg AuthMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				log.Error("turnpike AUTH: error unmarshalling publish message: %s", err)
				continue
			}
			t.handleAuth(id, msg)
		case WELCOME, CALLRESULT, CALLERROR, EVENT:
			log.Error("turnpike: server -> client message received, ignored: %s", TypeString(typ))
		default:
			log.Error("turnpike: invalid message format, message dropped: %s", data)
		}
	}

	delete(t.clients, id)
	close(c)
}
Beispiel #4
0
// WSSendRecv is the handler for websocket client connections.  It loops
// forever (until disconnected), reading JSON-RPC requests and sending
// sending responses and notifications.
func (s *server) WSSendRecv(ws *websocket.Conn, remoteAddr string, authenticated bool) {
	// Clear the read deadline set before the websocket hijacked
	// the connection.
	ws.SetReadDeadline(time.Time{})

	// Add client context so notifications duplicated to each
	// client are received by this client.
	recvQuit := make(chan struct{})
	sendQuit := make(chan struct{})
	cc := clientContext{
		send: make(chan []byte, 1), // buffer size is number of initial notifications
		quit: make(chan struct{}),
	}
	go func() {
		select {
		case <-recvQuit:
		case <-sendQuit:
		}
		log.Infof("Disconnected websocket client %s", remoteAddr)
		close(cc.quit)
	}()
	log.Infof("New websocket client %s", remoteAddr)

	NotifyBtcdConnection(cc.send) // TODO(jrick): clients should explicitly request this.
	addClient <- cc

	// received passes all received messages from the currently connected
	// frontend to the for-select loop.  It is closed when reading a
	// message from the websocket connection fails (presumably due to
	// a disconnected client).
	recvQueueIn := make(chan string)

	// Receive messages from websocket and send across jsonMsgs until
	// connection is lost
	go func() {
		for {
			var m string
			if err := websocket.Message.Receive(ws, &m); err != nil {
				select {
				case <-sendQuit:
					// Do not log error.

				default:
					if err != io.EOF {
						log.Warnf("Websocket receive failed from client %s: %v",
							remoteAddr, err)
					}
				}
				close(recvQueueIn)
				close(recvQuit)
				return
			}
			recvQueueIn <- m
		}
	}()

	// Manage queue of received messages for LIFO processing.
	recvQueueOut := make(chan string)
	go stringQueue(recvQueueIn, recvQueueOut, cc.quit)

	badAuth := make(chan struct{})
	sendResp := make(chan []byte)
	go func() {
	out:
		for m := range recvQueueOut {
			resp, err := s.ReplyToFrontend([]byte(m), true, authenticated)
			if err == ErrBadAuth {
				select {
				case badAuth <- struct{}{}:
				case <-cc.quit:
				}
				break out
			}

			// Authentication passed.
			authenticated = true

			select {
			case sendResp <- resp:
			case <-cc.quit:
				break out
			}
		}
		close(sendResp)
	}()

	const deadline time.Duration = 2 * time.Second

out:
	for {
		var m []byte
		var ok bool

		select {
		case <-badAuth:
			// Bad auth. Disconnect.
			log.Warnf("Disconnecting unauthorized websocket client %s", remoteAddr)
			break out

		case m = <-cc.send: // sends from external writers.  never closes.
		case m, ok = <-sendResp:
			if !ok {
				// Nothing left to send.  Return so the handler exits.
				break out
			}
		case <-cc.quit:
			break out
		}

		err := ws.SetWriteDeadline(time.Now().Add(deadline))
		if err != nil {
			log.Errorf("Cannot set write deadline on client %s: %v", remoteAddr, err)
			break out
		}
		err = websocket.Message.Send(ws, string(m))
		if err != nil {
			log.Warnf("Websocket send failed to client %s: %v", remoteAddr, err)
			break out
		}
	}
	close(sendQuit)
	log.Tracef("Leaving function WSSendRecv")
}
Beispiel #5
0
// HandleWebsocket implements the go.net/websocket.Handler interface.
func (t *Server) HandleWebsocket(conn *websocket.Conn) {
	defer conn.Close()

	if debug {
		log.Print("turnpike: received websocket connection")
	}

	tid, err := uuid.NewV4()
	if err != nil {
		if debug {
			log.Print("turnpike: could not create unique id, refusing client connection")
		}
		return
	}
	id := tid.String()
	if debug {
		log.Printf("turnpike: client connected: %s", id)
	}

	arr, err := createWelcome(id, turnpikeServerIdent)
	if err != nil {
		if debug {
			log.Print("turnpike: error encoding welcome message")
		}
		return
	}
	if debug {
		log.Printf("turnpike: sending welcome message: %s", arr)
	}
	err = websocket.Message.Send(conn, string(arr))
	if err != nil {
		if debug {
			log.Printf("turnpike: error sending welcome message, aborting connection: %s", err)
		}
		return
	}

	c := make(chan string, serverBacklog)
	t.clients[id] = c

	if t.sessionOpenCallback != nil {
		t.sessionOpenCallback(id)
	}

	failures := 0
	go func() {
		for msg := range c {
			if debug {
				log.Printf("turnpike: sending message: %s", msg)
			}
			conn.SetWriteDeadline(time.Now().Add(clientConnTimeout * time.Second))
			err := websocket.Message.Send(conn, msg)
			if err != nil {
				if nErr, ok := err.(net.Error); ok && (nErr.Timeout() || nErr.Temporary()) {
					log.Printf("Network error: %s", nErr)
					failures++
					if failures > clientMaxFailures {
						break
					}
				} else {
					if debug {
						log.Printf("turnpike: error sending message: %s", err)
					}
					break
				}
			}
		}
		if debug {
			log.Printf("Client %s disconnected", id)
		}
		conn.Close()
	}()

	for {
		var rec string
		err := websocket.Message.Receive(conn, &rec)
		if err != nil {
			if err != io.EOF {
				if debug {
					log.Printf("turnpike: error receiving message, aborting connection: %s", err)
				}
			}
			break
		}
		if debug {
			log.Printf("turnpike: message received: %s", rec)
		}

		data := []byte(rec)

		switch typ := parseMessageType(rec); typ {
		case msgPrefix:
			var msg prefixMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling prefix message: %s", err)
				}
				continue
			}
			t.handlePrefix(id, msg)
		case msgCall:
			var msg callMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling call message: %s", err)
				}
				continue
			}
			t.handleCall(id, msg)
		case msgSubscribe:
			var msg subscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling subscribe message: %s", err)
				}
				continue
			}
			t.handleSubscribe(id, msg)
		case msgUnsubscribe:
			var msg unsubscribeMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling unsubscribe message: %s", err)
				}
				continue
			}
			t.handleUnsubscribe(id, msg)
		case msgPublish:
			var msg publishMsg
			err := json.Unmarshal(data, &msg)
			if err != nil {
				if debug {
					log.Printf("turnpike: error unmarshalling publish message: %s", err)
				}
				continue
			}
			t.handlePublish(id, msg)
		case msgWelcome, msgCallResult, msgCallError, msgEvent:
			if debug {
				log.Printf("turnpike: server -> client message received, ignored: %s", messageTypeString(typ))
			}
		default:
			if debug {
				log.Printf("turnpike: invalid message format, message dropped: %s", data)
			}
		}
	}

	delete(t.clients, id)
	close(c)
}