X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;f=8sync%2Fsystems%2Fwebsocket%2Fclient.scm;h=49866726ae6c802e1ebbb8535b995bb0fb08e833;hb=194f93884da7c0c03172fe27fff992f3c538eeae;hp=9f2b0f06807a1494e51e31c5c27113543885a6a6;hpb=715d98b09ba5745db5efc19e6d3de38e8eb38793;p=8sync.git diff --git a/8sync/systems/websocket/client.scm b/8sync/systems/websocket/client.scm index 9f2b0f0..4986672 100644 --- a/8sync/systems/websocket/client.scm +++ b/8sync/systems/websocket/client.scm @@ -150,6 +150,10 @@ (define-method (websocket-init (websocket ) message) (and=> (.url websocket) (cut websocket-open websocket message <>))) +(define-method (websocket-socket-open? (websocket )) + "Return #t if .SOCKET of WEBSOCKET is open." + (not (port-closed? (.socket websocket)))) + (define-method (websocket-loop (websocket ) message) (define (handle-data-frame type data) @@ -170,42 +174,56 @@ (let loop ((fragments '()) (type #f)) - (let* ((socket (.socket websocket)) - (frame (and (websocket-open? websocket) - (read-frame-maybe)))) - (cond - ;; EOF - port is closed. - ;; @@: Sometimes the eof object appears here as opposed to - ;; at lookahead, but I'm not sure why - ((or (not frame) (eof-object? frame)) - (close-down)) - ;; Per section 5.4, control frames may appear interspersed - ;; along with a fragmented message. - ((close-frame? frame) - ;; Per section 5.5.1, echo the close frame back to the - ;; socket before closing the socket. The socket may no - ;; longer be listening. - (false-if-exception - (write-frame (make-close-frame (frame-data frame)) socket)) - (close-down)) - ((ping-frame? frame) - ;; Per section 5.5.3, a pong frame must include the exact - ;; same data as the ping frame. - (write-frame (make-pong-frame (frame-data frame)) socket) - (loop fragments type)) - ((pong-frame? frame) ; silently ignore pongs - (loop fragments type)) - ((first-fragment-frame? frame) ; begin accumulating fragments - (loop (list frame) (frame-type frame))) - ((final-fragment-frame? frame) ; concatenate all fragments - (handle-data-frame type (frame-concatenate - (reverse (cons frame fragments)))) - (loop '() #f)) - ((fragment-frame? frame) ; add a fragment - (loop (cons frame fragments) type)) - ((data-frame? frame) ; unfragmented data frame - (handle-data-frame (frame-type frame) (frame-data frame)) - (loop '() #f)))))) + (catch #t ;expect: wrong-type-arg (open port), system-error + (lambda _ + (let* ((socket (.socket websocket)) + (frame (and (websocket-open? websocket) + (read-frame-maybe)))) + (cond + ;; EOF - port is closed. + ;; @@: Sometimes the eof object appears here as opposed to + ;; at lookahead, but I'm not sure why + ((or (not frame) (eof-object? frame)) + (close-down)) + ;; Per section 5.4, control frames may appear interspersed + ;; along with a fragmented message. + ((close-frame? frame) + ;; Per section 5.5.1, echo the close frame back to the + ;; socket before closing the socket. The socket may no + ;; longer be listening. + (false-if-exception + (write-frame (make-close-frame (frame-data frame)) socket)) + (close-down)) + ((ping-frame? frame) + ;; Per section 5.5.3, a pong frame must include the exact + ;; same data as the ping frame. + (write-frame (make-pong-frame (frame-data frame)) socket) + (loop fragments type)) + ((pong-frame? frame) ; silently ignore pongs + (loop fragments type)) + ((first-fragment-frame? frame) ; begin accumulating fragments + (loop (list frame) (frame-type frame))) + ((final-fragment-frame? frame) ; concatenate all fragments + (handle-data-frame type (frame-concatenate + (reverse (cons frame fragments)))) + (loop '() #f)) + ((fragment-frame? frame) ; add a fragment + (loop (cons frame fragments) type)) + ((data-frame? frame) ; unfragmented data frame + (handle-data-frame (frame-type frame) (frame-data frame)) + (loop '() #f))))) + (lambda (key . args) + (unless (and + (memq key '(system-error wrong-type-arg)) + (match args + (((or "get-u8" "get-bytevector-n" "lookahead-u8") arg ...) + #t) + (_ #f))) + (apply throw key args)) + (let ((message (format #f "~a: ~s" key args))) + ((.on-error websocket) websocket (format #f "read failed: ~s\n" websocket)) + (if (websocket-socket-open? websocket) (loop '() #f) + (websocket-close websocket message))))))) ;; See Section 3 - WebSocket URIs (define (encrypted-websocket-scheme? uri) @@ -313,9 +331,14 @@ KEY." (define (open-entropy-port) "Return an open input port to a reliable source of entropy for the current system." - ;; XXX: This works on GNU/Linux and OS X systems, but this isn't - ;; exactly portable. - (open-input-file "/dev/urandom")) + (if (file-exists? "/dev/urandom") + (open-input-file "/dev/urandom") + ;; XXX: This works as a fall back but this isn't exactly a + ;; reliable source of entropy. + (make-soft-port (vector (const #f) (const #f) (const #f) + (lambda _ (let ((r (random 256))) (integer->char r))) + (const #f) + (const #t)) "r"))) (define-method (websocket-close (websocket )) "Close the WebSocket connection for the client WEBSOCKET."