# HG changeset patch # User Steve Losh # Date 1489513574 0 # Node ID 15eabbd388eaac9f3a6dc6461a38b38ede98b41a # Parent eee835835b39fab07bba9d59e5152cdf1bad6a90 Add a restart for ports already in use diff -r eee835835b39 -r 15eabbd388ea src/server.lisp --- a/src/server.lisp Tue Mar 14 13:33:00 2017 +0000 +++ b/src/server.lisp Tue Mar 14 17:46:14 2017 +0000 @@ -66,6 +66,12 @@ ;;;; Server (defvar *server-thread* nil) +(define-condition port-error (error) + ((port :initarg :port)) + (:report (lambda (err stream) + (format stream "Port ~D is already in use" + (slot-value err 'port))))) + (defmacro run-in-thread (thread-name &rest body) "Run `body` in a thread called `name` (usually). Return the thread. @@ -78,6 +84,26 @@ (progn (funcall thunk) nil) (bt:make-thread thunk :name ,thread-name)))) +(defun socket-listen (address port) + (handler-case + (values (usocket:socket-listen + address port + :reuse-address t + ;; have to specify element-type here too because usocket+CCL + ;; fucks it up if you only specify it in socket-accept + :element-type '(unsigned-byte 8)) + port) + (usocket:address-in-use-error () + (restart-case (error 'port-error :port port) + (use-different-port (new-port) + :report (lambda (stream) + (format stream "Select a port other than ~D" port)) + :interactive (lambda () + (format *query-io* "~&Type a form to be evaluated:~%") + (finish-output *query-io*) + (list (read *query-io*))) + (socket-listen address new-port)))))) + (defun accept-connections (server-socket) "Accept connections to the server and spawn threads to handle each." @@ -98,12 +124,7 @@ (defun start-server (&key (address "127.0.0.1") (port 8675)) "Fire up a server thread that will listen for connections." (log-message "Starting server...~%") - (let ((socket (usocket:socket-listen - address port - :reuse-address t - ;; have to specify element-type here too because usocket+CCL - ;; fucks it up if you only specify it in socket-accept - :element-type '(unsigned-byte 8)))) + (multiple-value-bind (socket port) (socket-listen address port) (setf *server-thread* (run-in-thread (format nil "NREPL Server (~a/~a)" address port) (unwind-protect