Shammer's Philosophy

My private adversaria

with-open-passive-socket 改 ver 20110703

with-open-passive-socket を自作 - Shammerismで作成した with-open-socket を改良した。毎回 0.0.0.0 で listen するようになっていたが、listen-address を指定できるように改良。もともとの実装にSBCLで文字列をドット表記のIPアドレスに変換する - Shammerismの内容を加えた感じだ。

(defun open-socket-server (addr port)
  (let ((interface (handler-case
		       (sb-bsd-sockets:make-inet-address addr)
		     (error (e)
		       (format t "~A was thrown. Use 0.0.0.0 as listen-address." (type-of e))
		       #(0 0 0 0)))))
    (handler-case
	(let ((server (make-instance 'sb-bsd-sockets:inet-socket
				     :type :stream
				     :protocol :tcp)))
	  (sb-bsd-sockets:socket-bind server interface port)
	  (sb-bsd-sockets:socket-listen server 400);400 is a backlog
	  server)
      (sb-bsd-sockets:address-in-use-error ()
	(format t "Address ~A:~A is already in use" interface port)
	(force-output)
	nil))))

(defmacro with-open-passive-socket (&rest body)
  (let ((server-symbol-value (caar body))
	(server-listen-addr (cadar body))
	(server-listen-port (caddar body)))
    `(let ((,server-symbol-value (open-socket-server ,server-listen-addr ,server-listen-port)))
       (unwind-protect
	    (when ,server-symbol-value
	      ,(cadr body))
	 (unless (null ,server-symbol-value)
	   (format t "Close server socket...~%")
	   (close-server-socket ,server-symbol-value))))))

使用する側は以下のような感じ。

(defun open-passive-server (addr port)
  (with-open-passive-socket (server addr port)
    (progn
      ...

(open-passive-server "0.0.0.0" 7001)

progn まで macro の方に組み込みたいが、、、それはまた別の機会に。