@@ -28,6 +28,7 @@ const outChannelSize = 500
2828const defaultTimeout = 60 * time .Second
2929const unknownMethodLabel = "unknown"
3030const maxWebsocketMessageBytes int64 = 4 * 1024 * 1024
31+ const maxWebsocketPendingRequests = 48
3132const websocketLogPreviewBytes = 256
3233
3334// allRates is a special "currency" parameter that means all available currencies
@@ -44,6 +45,7 @@ type websocketChannel struct {
4445 id uint64
4546 conn * websocket.Conn
4647 out chan * WsRes
48+ pendingRequests chan struct {}
4749 ip string
4850 requestHeader http.Header
4951 alive bool
@@ -221,12 +223,13 @@ func (s *WebsocketServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
221223 }
222224 conn .SetReadLimit (maxWebsocketMessageBytes )
223225 c := & websocketChannel {
224- id : atomic .AddUint64 (& connectionCounter , 1 ),
225- conn : conn ,
226- out : make (chan * WsRes , outChannelSize ),
227- ip : getIP (r ),
228- requestHeader : r .Header ,
229- alive : true ,
226+ id : atomic .AddUint64 (& connectionCounter , 1 ),
227+ conn : conn ,
228+ out : make (chan * WsRes , outChannelSize ),
229+ pendingRequests : make (chan struct {}, maxWebsocketPendingRequests ),
230+ ip : getIP (r ),
231+ requestHeader : r .Header ,
232+ alive : true ,
230233 }
231234 if s .is .WsGetAccountInfoLimit > 0 {
232235 c .getAddressInfoDescriptors = make (map [string ]struct {})
@@ -290,6 +293,19 @@ func (c *websocketChannel) DataOut(data *WsRes) {
290293 }
291294}
292295
296+ func (c * websocketChannel ) acquireRequestSlot () bool {
297+ select {
298+ case c .pendingRequests <- struct {}{}:
299+ return true
300+ default :
301+ return false
302+ }
303+ }
304+
305+ func (c * websocketChannel ) releaseRequestSlot () {
306+ <- c .pendingRequests
307+ }
308+
293309func (s * WebsocketServer ) inputLoop (c * websocketChannel ) {
294310 defer func () {
295311 if r := recover (); r != nil {
@@ -313,7 +329,15 @@ func (s *WebsocketServer) inputLoop(c *websocketChannel) {
313329 s .closeChannel (c , "protocol_error" )
314330 return
315331 }
316- go s .onRequest (c , & req )
332+ if ! c .acquireRequestSlot () {
333+ glog .Warning ("Client " , c .id , " exceeded pending websocket request limit, " , c .ip )
334+ s .closeChannel (c , "pending_requests_limit" )
335+ return
336+ }
337+ go func (req WsReq ) {
338+ defer c .releaseRequestSlot ()
339+ s .onRequest (c , & req )
340+ }(req )
317341 case websocket .BinaryMessage :
318342 glog .Error ("Binary message received from " , c .id , ", " , c .ip )
319343 s .closeChannel (c , "protocol_error" )
0 commit comments