;; Copyright (c) 2012 Alex Shinn. All rights reserved. ;; BSD-style license: http://synthcode.com/license.txt (define default-max-requests 10000) (define (make-socket-listener-thunk listener port) (lambda () (let ((addr (get-address-info #f port))) (cond ((accept listener (address-info-address addr) (address-info-address-length addr)) => (lambda (sock) (list sock addr))) (else #f))))) (define (make-listener-thunk x) (cond ((integer? x) (make-socket-listener-thunk (make-listener-socket (get-address-info #f x)) x)) ((address-info? x) (make-socket-listener-thunk (make-listener-socket x) 80)) ((fileno? x) (make-socket-listener-thunk x 80)) ((procedure? x) x) (else (error "expected a listener socket, fileno or thunk" x)))) (define (run-net-server listener-or-addr handler . o) (let ((listener-thunk (make-listener-thunk listener-or-addr)) (max-requests (or (cond ((pair? o) (car o)) ((get-environment-variable "CHIBI_NET_SERVER_MAX_THREADS") => string->number) (else #f)) default-max-requests))) (define (run sock addr count) (log-debug "net-server: accepting request: " count " " (sockaddr-name (address-info-address addr))) (let ((ports (protect (exn (else (log-error "net-server: couldn't create port: " sock) (close-file-descriptor sock))) (cons (open-input-file-descriptor sock) (open-output-file-descriptor sock))))) (protect (exn (else (log-error "net-server: error in request: " count) (print-exception exn) (print-stack-trace exn) (close-input-port (car ports)) (close-output-port (cdr ports)) (close-file-descriptor sock))) (handler (car ports) (cdr ports) sock addr) (flush-output (cdr ports)) (close-input-port (car ports)) (close-output-port (cdr ports)) (close-file-descriptor sock))) (log-debug "net-server: finished: " count)) (let ((requests 0)) (let serve ((count 0)) (if (>= requests max-requests) (thread-yield!) (let ((sock+addr (listener-thunk))) (cond ((not sock+addr) (serve count)) ((= 1 max-requests) (run (car sock+addr) (cadr sock+addr) count) (serve (+ 1 count))) (else (thread-start! (make-thread (lambda () (set! requests (+ requests 1)) (run (car sock+addr) (cadr sock+addr) count) (set! requests (- requests 1))) (string-append "net-client-" (number->string count)))) (serve (+ 1 count))))))))))