mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-11 08:23:45 +00:00
feat(multiplayer): bound control-plane websocket traffic
This commit is contained in:
+31
-4
@@ -19,9 +19,12 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
maxWebSocketFrame = 64 << 10
|
||||
eventQueueCapacity = 32
|
||||
webSocketGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
maxWebSocketFrame = 64 << 10
|
||||
eventQueueCapacity = 32
|
||||
webSocketIdleLimit = 2 * time.Minute
|
||||
webSocketMessageLimit = 120
|
||||
webSocketMessageWindow = time.Minute
|
||||
)
|
||||
|
||||
// ControlPlaneEvent is the server-to-client envelope defined by the v1
|
||||
@@ -139,7 +142,7 @@ func (s *Service) controlPlaneEvent(w http.ResponseWriter, r *http.Request) {
|
||||
writeError(w, http.StatusMethodNotAllowed, "method_not_allowed")
|
||||
return
|
||||
}
|
||||
if !isWebSocketUpgrade(r) || !validWebSocketKey(r.Header.Get("Sec-WebSocket-Key")) {
|
||||
if !isWebSocketUpgrade(r) || r.Header.Get("Sec-WebSocket-Version") != "13" || !validWebSocketKey(r.Header.Get("Sec-WebSocket-Key")) {
|
||||
writeError(w, http.StatusBadRequest, "invalid_websocket_upgrade")
|
||||
return
|
||||
}
|
||||
@@ -250,11 +253,20 @@ func validWebSocketKey(key string) bool {
|
||||
|
||||
func readWebSocketFrames(connection net.Conn, writeMu *sync.Mutex) {
|
||||
reader := bufio.NewReader(connection)
|
||||
windowStarted := time.Now()
|
||||
messageCount := 0
|
||||
for {
|
||||
if err := connection.SetReadDeadline(time.Now().Add(webSocketIdleLimit)); err != nil {
|
||||
return
|
||||
}
|
||||
opcode, _, err := readWebSocketFrame(reader)
|
||||
if err != nil || opcode == 0x8 {
|
||||
return
|
||||
}
|
||||
now := time.Now()
|
||||
if !allowWebSocketMessage(now, &windowStarted, &messageCount) {
|
||||
return
|
||||
}
|
||||
if opcode == 0x9 {
|
||||
writeMu.Lock()
|
||||
_ = writeWebSocketFrame(connection, 0xA, nil)
|
||||
@@ -263,6 +275,21 @@ func readWebSocketFrames(connection net.Conn, writeMu *sync.Mutex) {
|
||||
}
|
||||
}
|
||||
|
||||
func allowWebSocketMessage(now time.Time, windowStarted *time.Time, count *int) bool {
|
||||
if windowStarted == nil || count == nil || now.IsZero() {
|
||||
return false
|
||||
}
|
||||
if !now.Before(windowStarted.Add(webSocketMessageWindow)) {
|
||||
*windowStarted = now
|
||||
*count = 0
|
||||
}
|
||||
if *count >= webSocketMessageLimit {
|
||||
return false
|
||||
}
|
||||
*count++
|
||||
return true
|
||||
}
|
||||
|
||||
func readWebSocketFrame(reader *bufio.Reader) (byte, []byte, error) {
|
||||
first, err := reader.ReadByte()
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user