/common-lisp/3rd-party/usocket/backend/mcl.lisp

https://bitbucket.org/hwo2014/hwo2014-team-876 · Lisp · 267 lines · 217 code · 39 blank · 11 comment · 4 complexity · fe401a60fbc64af1d594023bb25a8f08 MD5 · raw file

  1. ;;;; $Id: mcl.lisp 721 2013-06-21 03:46:37Z ctian $
  2. ;;;; $URL: svn://common-lisp.net/project/usocket/svn/usocket/tags/0.6.1/backend/mcl.lisp $
  3. ;; MCL backend for USOCKET 0.4.1
  4. ;; Terje Norderhaug <terje@in-progress.com>, January 1, 2009
  5. (in-package :usocket)
  6. (defun handle-condition (condition &optional socket)
  7. ; incomplete, needs to handle additional conditions
  8. (flet ((raise-error (&optional socket-condition)
  9. (if socket-condition
  10. (error socket-condition :socket socket)
  11. (error 'unknown-error :socket socket :real-error condition))))
  12. (typecase condition
  13. (ccl:host-stopped-responding
  14. (raise-error 'host-down-error))
  15. (ccl:host-not-responding
  16. (raise-error 'host-unreachable-error))
  17. (ccl:connection-reset
  18. (raise-error 'connection-reset-error))
  19. (ccl:connection-timed-out
  20. (raise-error 'timeout-error))
  21. (ccl:opentransport-protocol-error
  22. (raise-error 'protocol-not-supported-error))
  23. (otherwise
  24. (raise-error)))))
  25. (defun socket-connect (host port &key (element-type 'character) timeout deadline nodelay
  26. local-host local-port (protocol :stream))
  27. (when (eq nodelay :if-supported)
  28. (setf nodelay t))
  29. (ecase protocol
  30. (:stream
  31. (with-mapped-conditions ()
  32. (let* ((socket
  33. (make-instance 'active-socket
  34. :remote-host (when host (host-to-hostname host))
  35. :remote-port port
  36. :local-host (when local-host (host-to-hostname local-host))
  37. :local-port local-port
  38. :deadline deadline
  39. :nodelay nodelay
  40. :connect-timeout (and timeout (round (* timeout 60)))
  41. :element-type element-type))
  42. (stream (socket-open-stream socket)))
  43. (make-stream-socket :socket socket :stream stream))))
  44. (:datagram
  45. (with-mapped-conditions ()
  46. (make-datagram-socket
  47. (ccl::open-udp-socket :local-address (and local-host (host-to-hbo local-host))
  48. :local-port local-port))))))
  49. (defun socket-listen (host port
  50. &key reuseaddress
  51. (reuse-address nil reuse-address-supplied-p)
  52. (backlog 5)
  53. (element-type 'character))
  54. (let* ((reuseaddress (if reuse-address-supplied-p reuse-address reuseaddress))
  55. (socket (with-mapped-conditions ()
  56. (make-instance 'passive-socket
  57. :local-port port
  58. :local-host (host-to-hbo host)
  59. :reuse-address reuseaddress
  60. :backlog backlog))))
  61. (make-stream-server-socket socket :element-type element-type)))
  62. (defmethod socket-accept ((usocket stream-server-usocket) &key element-type)
  63. (let* ((socket (socket usocket))
  64. (stream (with-mapped-conditions (usocket)
  65. (socket-accept socket :element-type element-type))))
  66. (make-stream-socket :socket socket :stream stream)))
  67. (defmethod socket-close ((usocket usocket))
  68. (with-mapped-conditions (usocket)
  69. (socket-close (socket usocket))))
  70. (defmethod ccl::stream-close ((usocket usocket))
  71. (socket-close usocket))
  72. (defun get-hosts-by-name (name)
  73. (with-mapped-conditions ()
  74. (list (hbo-to-vector-quad (ccl::get-host-address
  75. (host-to-hostname name))))))
  76. (defun get-host-by-address (address)
  77. (with-mapped-conditions ()
  78. (ccl::inet-host-name (host-to-hbo address))))
  79. (defmethod get-local-name ((usocket usocket))
  80. (values (get-local-address usocket)
  81. (get-local-port usocket)))
  82. (defmethod get-peer-name ((usocket stream-usocket))
  83. (values (get-peer-address usocket)
  84. (get-peer-port usocket)))
  85. (defmethod get-local-address ((usocket usocket))
  86. (hbo-to-vector-quad (ccl::get-host-address (or (local-host (socket usocket)) ""))))
  87. (defmethod get-local-port ((usocket usocket))
  88. (local-port (socket usocket)))
  89. (defmethod get-peer-address ((usocket stream-usocket))
  90. (hbo-to-vector-quad (ccl::get-host-address (remote-host (socket usocket)))))
  91. (defmethod get-peer-port ((usocket stream-usocket))
  92. (remote-port (socket usocket)))
  93. (defun %setup-wait-list (wait-list)
  94. (declare (ignore wait-list)))
  95. (defun %add-waiter (wait-list waiter)
  96. (declare (ignore wait-list waiter)))
  97. (defun %remove-waiter (wait-list waiter)
  98. (declare (ignore wait-list waiter)))
  99. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  100. ;; BASIC MCL SOCKET IMPLEMENTATION
  101. (defclass socket ()
  102. ((local-port :reader local-port :initarg :local-port)
  103. (local-host :reader local-host :initarg :local-host)
  104. (element-type :reader element-type :initform 'ccl::base-character :initarg :element-type)))
  105. (defclass active-socket (socket)
  106. ((remote-host :reader remote-host :initarg :remote-host)
  107. (remote-port :reader remote-port :initarg :remote-port)
  108. (deadline :initarg :deadline)
  109. (nodelay :initarg :nodelay)
  110. (connect-timeout :reader connect-timeout :initform NIL :initarg :connect-timeout
  111. :type (or null fixnum) :documentation "ticks (60th of a second)")))
  112. (defmethod socket-open-stream ((socket active-socket))
  113. (ccl::open-tcp-stream (or (remote-host socket)(ccl::local-interface-ip-address)) (remote-port socket)
  114. :element-type (if (subtypep (element-type socket) 'character) 'ccl::base-character 'unsigned-byte)
  115. :connect-timeout (connect-timeout socket)))
  116. (defmethod socket-close ((socket active-socket))
  117. NIL)
  118. (defclass passive-socket (socket)
  119. ((streams :accessor socket-streams :type list :initform NIL
  120. :documentation "Circular list of streams with first element the next to open")
  121. (reuse-address :reader reuse-address :initarg :reuse-address)
  122. (lock :reader socket-lock :initform (ccl:make-lock "Socket"))))
  123. (defmethod initialize-instance :after ((socket passive-socket) &key backlog)
  124. (loop repeat backlog
  125. collect (socket-open-listener socket) into streams
  126. finally (setf (socket-streams socket)
  127. (cdr (rplacd (last streams) streams))))
  128. (when (zerop (local-port socket))
  129. (setf (slot-value socket 'local-port)
  130. (or (ccl::process-wait-with-timeout "binding port" (* 10 60)
  131. #'ccl::stream-local-port (car (socket-streams socket)))
  132. (error "timeout")))))
  133. (defmethod socket-accept ((socket passive-socket) &key element-type &aux (lock (socket-lock socket)))
  134. (flet ((connection-established-p (stream)
  135. (ccl::with-io-buffer-locked ((ccl::stream-io-buffer stream nil))
  136. (let ((state (ccl::opentransport-stream-connection-state stream)))
  137. (not (eq :unbnd state))))))
  138. (with-mapped-conditions ()
  139. (ccl:with-lock-grabbed (lock nil "Socket Lock")
  140. (let ((connection (shiftf (car (socket-streams socket))
  141. (socket-open-listener socket element-type))))
  142. (pop (socket-streams socket))
  143. (ccl:process-wait "Accepting" #'connection-established-p connection)
  144. connection)))))
  145. (defmethod socket-close ((socket passive-socket))
  146. (loop
  147. with streams = (socket-streams socket)
  148. for (stream tail) on streams
  149. do (close stream :abort T)
  150. until (eq tail streams)
  151. finally (setf (socket-streams socket) NIL)))
  152. (defmethod socket-open-listener (socket &optional element-type)
  153. ; see http://code.google.com/p/mcl/issues/detail?id=28
  154. (let* ((ccl::*passive-interface-address* (local-host socket))
  155. (new (ccl::open-tcp-stream NIL (or (local-port socket) #$kOTAnyInetAddress)
  156. :reuse-local-port-p (reuse-address socket)
  157. :element-type (if (subtypep (or element-type (element-type socket))
  158. 'character)
  159. 'ccl::base-character
  160. 'unsigned-byte))))
  161. (declare (special ccl::*passive-interface-address*))
  162. new))
  163. (defmethod input-available-p ((stream ccl::opentransport-stream))
  164. (macrolet ((when-io-buffer-lock-grabbed ((lock &optional multiple-value-p) &body body)
  165. "Evaluates the body if and only if the lock is successfully grabbed"
  166. ;; like with-io-buffer-lock-grabbed but returns immediately instead of polling the lock
  167. (let ((needs-unlocking-p (gensym))
  168. (lock-var (gensym)))
  169. `(let* ((,lock-var ,lock)
  170. (ccl::*grabbed-io-buffer-locks* (cons ,lock-var ccl::*grabbed-io-buffer-locks*))
  171. (,needs-unlocking-p (needs-unlocking-p ,lock-var)))
  172. (declare (dynamic-extent ccl::*grabbed-io-buffer-locks*))
  173. (when ,needs-unlocking-p
  174. (,(if multiple-value-p 'multiple-value-prog1 'prog1)
  175. (progn ,@body)
  176. (ccl::%release-io-buffer-lock ,lock-var)))))))
  177. (labels ((needs-unlocking-p (lock)
  178. (declare (type ccl::lock lock))
  179. ;; crucial - clears bogus lock.value as in grab-io-buffer-lock-out-of-line:
  180. (ccl::%io-buffer-lock-really-grabbed-p lock)
  181. (ccl:store-conditional lock nil ccl:*current-process*)))
  182. "similar to stream-listen on buffered-input-stream-mixin but without waiting for lock"
  183. (let ((io-buffer (ccl::stream-io-buffer stream)))
  184. (or (not (eql 0 (ccl::io-buffer-incount io-buffer)))
  185. (ccl::io-buffer-untyi-char io-buffer)
  186. (locally (declare (optimize (speed 3) (safety 0)))
  187. (when-io-buffer-lock-grabbed ((ccl::io-buffer-lock io-buffer))
  188. (funcall (ccl::io-buffer-listen-function io-buffer) stream io-buffer))))))))
  189. (defmethod connection-established-p ((stream ccl::opentransport-stream))
  190. (ccl::with-io-buffer-locked ((ccl::stream-io-buffer stream nil))
  191. (let ((state (ccl::opentransport-stream-connection-state stream)))
  192. (not (eq :unbnd state)))))
  193. (defun wait-for-input-internal (wait-list &key timeout &aux result)
  194. (labels ((ready-sockets (sockets)
  195. (dolist (sock sockets result)
  196. (when (cond ((stream-usocket-p sock)
  197. (input-available-p (socket-stream sock)))
  198. ((stream-server-usocket-p sock)
  199. (let ((ot-stream (first (socket-streams (socket sock)))))
  200. (or (input-available-p ot-stream)
  201. (connection-established-p ot-stream)))))
  202. (push sock result)))))
  203. (with-mapped-conditions ()
  204. (ccl:process-wait-with-timeout
  205. "socket input"
  206. (when timeout (truncate (* timeout 60)))
  207. #'ready-sockets
  208. (wait-list-waiters wait-list)))
  209. (nreverse result)))
  210. ;;; datagram socket methods
  211. (defmethod initialize-instance :after ((usocket datagram-usocket) &key)
  212. (with-slots (socket send-buffer recv-buffer) usocket
  213. (setq send-buffer
  214. (ccl::make-TUnitData (ccl::ot-conn-endpoint socket)))
  215. (setq recv-buffer
  216. (ccl::make-TUnitData (ccl::ot-conn-endpoint socket)))))
  217. (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0))
  218. (with-mapped-conditions (usocket)
  219. (with-slots (socket send-buffer) usocket
  220. (unless (and host port)
  221. (unsupported 'host 'socket-send))
  222. (ccl::send-message socket send-buffer buffer size host port offset))))
  223. (defmethod socket-receive ((usocket datagram-usocket) buffer length &key)
  224. (with-mapped-conditions (usocket)
  225. (with-slots (socket recv-buffer) usocket
  226. (ccl::receive-message socket recv-buffer buffer length))))
  227. (defmethod socket-close ((socket datagram-usocket))
  228. nil) ; TODO