ping-server.scm 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. ;;; Simple ping server implementation
  2. ;; Copyright (C) 2016 Free Software Foundation, Inc.
  3. ;; This library is free software; you can redistribute it and/or
  4. ;; modify it under the terms of the GNU Lesser General Public
  5. ;; License as published by the Free Software Foundation; either
  6. ;; version 3 of the License, or (at your option) any later version.
  7. ;;
  8. ;; This library is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;; Lesser General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU Lesser General Public
  14. ;; License along with this library; if not, write to the Free Software
  15. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. ;; 02110-1301 USA
  17. (use-modules (rnrs bytevectors)
  18. (fibers)
  19. (ice-9 textual-ports)
  20. (ice-9 rdelim)
  21. (ice-9 match))
  22. (define (make-default-socket family addr port)
  23. (let ((sock (socket PF_INET SOCK_STREAM 0)))
  24. (setsockopt sock SOL_SOCKET SO_REUSEADDR 1)
  25. (fcntl sock F_SETFD FD_CLOEXEC)
  26. (bind sock family addr port)
  27. (fcntl sock F_SETFL (logior O_NONBLOCK (fcntl sock F_GETFL)))
  28. sock))
  29. (define (client-loop port addr store)
  30. (setvbuf port 'block 1024)
  31. ;; Disable Nagle's algorithm. We buffer ourselves.
  32. (setsockopt port IPPROTO_TCP TCP_NODELAY 1)
  33. (let loop ()
  34. ;; TODO: Restrict read-line to 512 chars.
  35. (let ((line (read-line port)))
  36. (cond
  37. ((eof-object? line)
  38. (close-port port))
  39. (else
  40. (put-string port line)
  41. (put-char port #\newline)
  42. (force-output port)
  43. (loop))))))
  44. (define (socket-loop socket store)
  45. (let loop ()
  46. (match (accept socket SOCK_NONBLOCK)
  47. ((client . addr)
  48. (spawn-fiber (lambda () (client-loop client addr store))
  49. #:parallel? #t)
  50. (loop)))))
  51. (define* (run-ping-server #:key
  52. (host #f)
  53. (family AF_INET)
  54. (addr (if host
  55. (inet-pton family host)
  56. INADDR_LOOPBACK))
  57. (port 11211)
  58. (socket (make-default-socket family addr port)))
  59. (listen socket 1024)
  60. (sigaction SIGPIPE SIG_IGN)
  61. (socket-loop socket (make-hash-table)))
  62. (run-fibers run-ping-server)