PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/hwo2014/hwo2014-team-876
Lisp | 699 lines | 601 code | 72 blank | 26 comment | 0 complexity | 6a734c50c17df7d2e8d1422ac9ae9bb5 MD5 | raw file
Possible License(s): Apache-2.0
  1. ;;;; $Id: clisp.lisp 696 2012-11-10 15:24:33Z ctian $
  2. ;;;; $URL: svn://common-lisp.net/project/usocket/svn/usocket/tags/0.6.1/backend/clisp.lisp $
  3. ;;;; See LICENSE for licensing information.
  4. (in-package :usocket)
  5. (eval-when (:compile-toplevel :load-toplevel :execute)
  6. #-ffi
  7. (warn "This image doesn't contain FFI package, GET-HOST-NAME won't work.")
  8. #-(or ffi rawsock)
  9. (warn "This image doesn't contain either FFI or RAWSOCK package, no UDP support."))
  10. ;; utility routine for looking up the current host name
  11. #+ffi
  12. (ffi:def-call-out get-host-name-internal
  13. (:name "gethostname")
  14. (:arguments (name (FFI:C-PTR (FFI:C-ARRAY-MAX ffi:character 256))
  15. :OUT :ALLOCA)
  16. (len ffi:int))
  17. #+win32 (:library "WS2_32")
  18. #-win32 (:library :default)
  19. (:language #-win32 :stdc
  20. #+win32 :stdc-stdcall)
  21. (:return-type ffi:int))
  22. (defun get-host-name ()
  23. #+ffi
  24. (multiple-value-bind (retcode name)
  25. (get-host-name-internal 256)
  26. (when (= retcode 0)
  27. name))
  28. #-ffi
  29. "localhost")
  30. (defun get-host-by-address (address)
  31. (with-mapped-conditions ()
  32. (let ((hostent (posix:resolve-host-ipaddr (host-to-hostname address))))
  33. (posix:hostent-name hostent))))
  34. (defun get-hosts-by-name (name)
  35. (with-mapped-conditions ()
  36. (let ((hostent (posix:resolve-host-ipaddr name)))
  37. (mapcar #'host-to-vector-quad
  38. (posix:hostent-addr-list hostent)))))
  39. ;; Format: ((UNIX Windows) . CONDITION)
  40. (defparameter +clisp-error-map+
  41. #-win32
  42. `((:EADDRINUSE . address-in-use-error)
  43. (:EADDRNOTAVAIL . address-not-available-error)
  44. (:EBADF . bad-file-descriptor-error)
  45. (:ECONNREFUSED . connection-refused-error)
  46. (:ECONNRESET . connection-reset-error)
  47. (:ECONNABORTED . connection-aborted-error)
  48. (:EINVAL . invalid-argument-error)
  49. (:ENOBUFS . no-buffers-error)
  50. (:ENOMEM . out-of-memory-error)
  51. (:ENOTSUP . operation-not-supported-error)
  52. (:EPERM . operation-not-permitted-error)
  53. (:EPROTONOSUPPORT . protocol-not-supported-error)
  54. (:ESOCKTNOSUPPORT . socket-type-not-supported-error)
  55. (:ENETUNREACH . network-unreachable-error)
  56. (:ENETDOWN . network-down-error)
  57. (:ENETRESET . network-reset-error)
  58. (:ESHUTDOWN . already-shutdown-error)
  59. (:ETIMEDOUT . timeout-error)
  60. (:EHOSTDOWN . host-down-error)
  61. (:EHOSTUNREACH . host-unreachable-error))
  62. #+win32
  63. `((:WSAEADDRINUSE . address-in-use-error)
  64. (:WSAEADDRNOTAVAIL . address-not-available-error)
  65. (:WSAEBADF . bad-file-descriptor-error)
  66. (:WSAECONNREFUSED . connection-refused-error)
  67. (:WSAECONNRESET . connection-reset-error)
  68. (:WSAECONNABORTED . connection-aborted-error)
  69. (:WSAEINVAL . invalid-argument-error)
  70. (:WSAENOBUFS . no-buffers-error)
  71. (:WSAENOMEM . out-of-memory-error)
  72. (:WSAENOTSUP . operation-not-supported-error)
  73. (:WSAEPERM . operation-not-permitted-error)
  74. (:WSAEPROTONOSUPPORT . protocol-not-supported-error)
  75. (:WSAESOCKTNOSUPPORT . socket-type-not-supported-error)
  76. (:WSAENETUNREACH . network-unreachable-error)
  77. (:WSAENETDOWN . network-down-error)
  78. (:WSAENETRESET . network-reset-error)
  79. (:WSAESHUTDOWN . already-shutdown-error)
  80. (:WSAETIMEDOUT . timeout-error)
  81. (:WSAEHOSTDOWN . host-down-error)
  82. (:WSAEHOSTUNREACH . host-unreachable-error)))
  83. (defun handle-condition (condition &optional (socket nil))
  84. "Dispatch correct usocket condition."
  85. (let (error-keyword error-string)
  86. (typecase condition
  87. (ext:os-error
  88. (let ((errno (car (simple-condition-format-arguments condition))))
  89. #+ffi
  90. (setq error-keyword (os:errno errno)
  91. error-string (os:strerror errno))))
  92. (simple-error
  93. (let ((keyword
  94. (car (simple-condition-format-arguments condition))))
  95. (setq error-keyword keyword)
  96. #+ffi
  97. (setq error-string (os:strerror keyword))))
  98. (error (error 'unknown-error :real-error condition))
  99. (condition (signal 'unknown-condition :real-condition condition)))
  100. (when error-keyword
  101. (let ((usocket-error
  102. (cdr (assoc error-keyword +clisp-error-map+ :test #'eq))))
  103. (if usocket-error
  104. (if (subtypep usocket-error 'error)
  105. (error usocket-error :socket socket)
  106. (signal usocket-error :socket socket))
  107. (error "Unknown OS error: ~A (~A)" error-string error-keyword))))))
  108. (defun socket-connect (host port &key (protocol :stream) (element-type 'character)
  109. timeout deadline (nodelay t nodelay-specified)
  110. local-host local-port)
  111. (declare (ignorable timeout local-host local-port))
  112. (when deadline (unsupported 'deadline 'socket-connect))
  113. (when (and nodelay-specified
  114. (not (eq nodelay :if-supported)))
  115. (unsupported 'nodelay 'socket-connect))
  116. (case protocol
  117. (:stream
  118. (let ((socket)
  119. (hostname (host-to-hostname host)))
  120. (with-mapped-conditions (socket)
  121. (setf socket
  122. (if timeout
  123. (socket:socket-connect port hostname
  124. :element-type element-type
  125. :buffered t
  126. :timeout timeout)
  127. (socket:socket-connect port hostname
  128. :element-type element-type
  129. :buffered t))))
  130. (make-stream-socket :socket socket
  131. :stream socket))) ;; the socket is a stream too
  132. (:datagram
  133. #+(or rawsock ffi)
  134. (socket-create-datagram (or local-port *auto-port*)
  135. :local-host (or local-host *wildcard-host*)
  136. :remote-host (and host (host-to-vector-quad host))
  137. :remote-port port)
  138. #-(or rawsock ffi)
  139. (unsupported '(protocol :datagram) 'socket-connect))))
  140. (defun socket-listen (host port
  141. &key reuseaddress
  142. (reuse-address nil reuse-address-supplied-p)
  143. (backlog 5)
  144. (element-type 'character))
  145. ;; clisp 2.39 sets SO_REUSEADDRESS to 1 by default; no need to
  146. ;; to explicitly turn it on; unfortunately, there's no way to turn it off...
  147. (declare (ignore reuseaddress reuse-address reuse-address-supplied-p))
  148. (let ((sock (apply #'socket:socket-server
  149. (append (list port
  150. :backlog backlog)
  151. (when (ip/= host *wildcard-host*)
  152. (list :interface host))))))
  153. (with-mapped-conditions ()
  154. (make-stream-server-socket sock :element-type element-type))))
  155. (defmethod socket-accept ((socket stream-server-usocket) &key element-type)
  156. (let ((stream
  157. (with-mapped-conditions (socket)
  158. (socket:socket-accept (socket socket)
  159. :element-type (or element-type
  160. (element-type socket))))))
  161. (make-stream-socket :socket stream
  162. :stream stream)))
  163. ;; Only one close method required:
  164. ;; sockets and their associated streams
  165. ;; are the same object
  166. (defmethod socket-close ((usocket usocket))
  167. "Close socket."
  168. (when (wait-list usocket)
  169. (remove-waiter (wait-list usocket) usocket))
  170. (with-mapped-conditions (usocket)
  171. (close (socket usocket))))
  172. (defmethod socket-close ((usocket stream-server-usocket))
  173. (when (wait-list usocket)
  174. (remove-waiter (wait-list usocket) usocket))
  175. (socket:socket-server-close (socket usocket)))
  176. (defmethod get-local-name ((usocket stream-usocket))
  177. (multiple-value-bind
  178. (address port)
  179. (socket:socket-stream-local (socket usocket) t)
  180. (values (dotted-quad-to-vector-quad address) port)))
  181. (defmethod get-local-name ((usocket stream-server-usocket))
  182. (values (get-local-address usocket)
  183. (get-local-port usocket)))
  184. (defmethod get-peer-name ((usocket stream-usocket))
  185. (multiple-value-bind
  186. (address port)
  187. (socket:socket-stream-peer (socket usocket) t)
  188. (values (dotted-quad-to-vector-quad address) port)))
  189. (defmethod get-local-address ((usocket usocket))
  190. (nth-value 0 (get-local-name usocket)))
  191. (defmethod get-local-address ((usocket stream-server-usocket))
  192. (dotted-quad-to-vector-quad
  193. (socket:socket-server-host (socket usocket))))
  194. (defmethod get-peer-address ((usocket usocket))
  195. (nth-value 0 (get-peer-name usocket)))
  196. (defmethod get-local-port ((usocket usocket))
  197. (nth-value 1 (get-local-name usocket)))
  198. (defmethod get-local-port ((usocket stream-server-usocket))
  199. (socket:socket-server-port (socket usocket)))
  200. (defmethod get-peer-port ((usocket usocket))
  201. (nth-value 1 (get-peer-name usocket)))
  202. (defun %setup-wait-list (wait-list)
  203. (declare (ignore wait-list)))
  204. (defun %add-waiter (wait-list waiter)
  205. (push (cons (socket waiter) NIL) (wait-list-%wait wait-list)))
  206. (defun %remove-waiter (wait-list waiter)
  207. (setf (wait-list-%wait wait-list)
  208. (remove (socket waiter) (wait-list-%wait wait-list) :key #'car)))
  209. (defmethod wait-for-input-internal (wait-list &key timeout)
  210. (with-mapped-conditions ()
  211. (multiple-value-bind
  212. (secs musecs)
  213. (split-timeout (or timeout 1))
  214. (dolist (x (wait-list-%wait wait-list))
  215. (setf (cdr x) :INPUT))
  216. (let* ((request-list (wait-list-%wait wait-list))
  217. (status-list (if timeout
  218. (socket:socket-status request-list secs musecs)
  219. (socket:socket-status request-list)))
  220. (sockets (wait-list-waiters wait-list)))
  221. (do* ((x (pop sockets) (pop sockets))
  222. (y (cdr (pop status-list)) (cdr (pop status-list))))
  223. ((null x))
  224. (when (member y '(T :INPUT))
  225. (setf (state x) :READ)))
  226. wait-list))))
  227. ;;;
  228. ;;; UDP/Datagram sockets (RAWSOCK version)
  229. ;;;
  230. #+rawsock
  231. (progn
  232. (defun make-sockaddr_in ()
  233. (make-array 16 :element-type '(unsigned-byte 8) :initial-element 0))
  234. (declaim (inline fill-sockaddr_in))
  235. (defun fill-sockaddr_in (sockaddr_in ip port)
  236. (port-to-octet-buffer port sockaddr_in)
  237. (ip-to-octet-buffer ip sockaddr_in :start 2)
  238. sockaddr_in)
  239. (defun socket-create-datagram (local-port
  240. &key (local-host *wildcard-host*)
  241. remote-host
  242. remote-port)
  243. (let ((sock (rawsock:socket :inet :dgram 0))
  244. (lsock_addr (fill-sockaddr_in (make-sockaddr_in)
  245. local-host local-port))
  246. (rsock_addr (when remote-host
  247. (fill-sockaddr_in (make-sockaddr_in)
  248. remote-host (or remote-port
  249. local-port)))))
  250. (rawsock:bind sock (rawsock:make-sockaddr :inet lsock_addr))
  251. (when rsock_addr
  252. (rawsock:connect sock (rawsock:make-sockaddr :inet rsock_addr)))
  253. (make-datagram-socket sock :connected-p (if rsock_addr t nil))))
  254. (defmethod socket-receive ((socket datagram-usocket) buffer length &key)
  255. "Returns the buffer, the number of octets copied into the buffer (received)
  256. and the address of the sender as values."
  257. (let* ((sock (socket socket))
  258. (sockaddr (rawsock:make-sockaddr :inet))
  259. (real-length (or length +max-datagram-packet-size+))
  260. (real-buffer (or buffer
  261. (make-array real-length
  262. :element-type '(unsigned-byte 8)))))
  263. (let ((rv (rawsock:recvfrom sock real-buffer sockaddr
  264. :start 0 :end real-length))
  265. (host 0) (port 0))
  266. (unless (connected-p socket)
  267. (let ((data (rawsock:sockaddr-data sockaddr)))
  268. (setq host (ip-from-octet-buffer data :start 4)
  269. port (port-from-octet-buffer data :start 2))))
  270. (values (if buffer real-buffer (subseq real-buffer 0 rv))
  271. rv
  272. host
  273. port))))
  274. (defmethod socket-send ((socket datagram-usocket) buffer size &key host port (offset 0))
  275. "Returns the number of octets sent."
  276. (let* ((sock (socket socket))
  277. (sockaddr (when (and host port)
  278. (rawsock:make-sockaddr :inet
  279. (fill-sockaddr_in
  280. (make-sockaddr_in)
  281. (host-byte-order host)
  282. port))))
  283. (real-size (min size +max-datagram-packet-size+))
  284. (real-buffer (if (typep buffer '(simple-array (unsigned-byte 8) (*)))
  285. buffer
  286. (make-array real-size
  287. :element-type '(unsigned-byte 8)
  288. :initial-contents (subseq buffer 0 real-size))))
  289. (rv (if (and host port)
  290. (rawsock:sendto sock real-buffer sockaddr
  291. :start offset
  292. :end (+ offset real-size))
  293. (rawsock:send sock real-buffer
  294. :start offset
  295. :end (+ offset real-size)))))
  296. rv))
  297. (defmethod socket-close ((usocket datagram-usocket))
  298. (when (wait-list usocket)
  299. (remove-waiter (wait-list usocket) usocket))
  300. (rawsock:sock-close (socket usocket)))
  301. (declaim (inline get-socket-name))
  302. (defun get-socket-name (socket function)
  303. (let ((sockaddr (rawsock:make-sockaddr :inet (make-sockaddr_in))))
  304. (funcall function socket sockaddr)
  305. (let ((data (rawsock:sockaddr-data sockaddr)))
  306. (values (hbo-to-vector-quad (ip-from-octet-buffer data :start 2))
  307. (port-from-octet-buffer data :start 0)))))
  308. (defmethod get-local-name ((usocket datagram-usocket))
  309. (get-socket-name (socket usocket) 'rawsock:getsockname))
  310. (defmethod get-peer-name ((usocket datagram-usocket))
  311. (get-socket-name (socket usocket) 'rawsock:getpeername))
  312. ) ; progn
  313. ;;;
  314. ;;; UDP/Datagram sockets (FFI version)
  315. ;;;
  316. #+(and ffi (not rawsock))
  317. (progn
  318. ;; C primitive types
  319. (ffi:def-c-type socklen_t ffi:uint32)
  320. ;; C structures
  321. (ffi:def-c-struct sockaddr
  322. #+macos (sa_len ffi:uint8)
  323. (sa_family #-macos ffi:ushort
  324. #+macos ffi:uint8)
  325. (sa_data (ffi:c-array ffi:char 14)))
  326. (ffi:def-c-struct sockaddr_in
  327. #+macos (sin_len ffi:uint8)
  328. (sin_family #-macos ffi:short
  329. #+macos ffi:uint8)
  330. (sin_port #-macos ffi:ushort
  331. #+macos ffi:uint16)
  332. (sin_addr ffi:uint32)
  333. (sin_zero (ffi:c-array ffi:char 8)))
  334. (ffi:def-c-struct timeval
  335. (tv_sec ffi:long)
  336. (tv_usec ffi:long))
  337. ;; foreign functions
  338. (ffi:def-call-out %sendto (:name "sendto")
  339. (:arguments (socket ffi:int)
  340. (buffer ffi:c-pointer)
  341. (length ffi:int)
  342. (flags ffi:int)
  343. (address (ffi:c-ptr sockaddr))
  344. (address-len ffi:int))
  345. #+win32 (:library "WS2_32")
  346. #-win32 (:library :default)
  347. (:language #-win32 :stdc
  348. #+win32 :stdc-stdcall)
  349. (:return-type ffi:int))
  350. (ffi:def-call-out %send (:name "send")
  351. (:arguments (socket ffi:int)
  352. (buffer ffi:c-pointer)
  353. (length ffi:int)
  354. (flags ffi:int))
  355. #+win32 (:library "WS2_32")
  356. #-win32 (:library :default)
  357. (:language #-win32 :stdc
  358. #+win32 :stdc-stdcall)
  359. (:return-type ffi:int))
  360. (ffi:def-call-out %recvfrom (:name "recvfrom")
  361. (:arguments (socket ffi:int)
  362. (buffer ffi:c-pointer)
  363. (length ffi:int)
  364. (flags ffi:int)
  365. (address (ffi:c-ptr sockaddr) :in-out)
  366. (address-len (ffi:c-ptr ffi:int) :in-out))
  367. #+win32 (:library "WS2_32")
  368. #-win32 (:library :default)
  369. (:language #-win32 :stdc
  370. #+win32 :stdc-stdcall)
  371. (:return-type ffi:int))
  372. (ffi:def-call-out %socket (:name "socket")
  373. (:arguments (family ffi:int)
  374. (type ffi:int)
  375. (protocol ffi:int))
  376. #+win32 (:library "WS2_32")
  377. #-win32 (:library :default)
  378. (:language #-win32 :stdc
  379. #+win32 :stdc-stdcall)
  380. (:return-type ffi:int))
  381. (ffi:def-call-out %connect (:name "connect")
  382. (:arguments (socket ffi:int)
  383. (address (ffi:c-ptr sockaddr) :in)
  384. (address_len socklen_t))
  385. #+win32 (:library "WS2_32")
  386. #-win32 (:library :default)
  387. (:language #-win32 :stdc
  388. #+win32 :stdc-stdcall)
  389. (:return-type ffi:int))
  390. (ffi:def-call-out %bind (:name "bind")
  391. (:arguments (socket ffi:int)
  392. (address (ffi:c-ptr sockaddr) :in)
  393. (address_len socklen_t))
  394. #+win32 (:library "WS2_32")
  395. #-win32 (:library :default)
  396. (:language #-win32 :stdc
  397. #+win32 :stdc-stdcall)
  398. (:return-type ffi:int))
  399. (ffi:def-call-out %close (:name #-win32 "close" #+win32 "closesocket")
  400. (:arguments (socket ffi:int))
  401. #+win32 (:library "WS2_32")
  402. #-win32 (:library :default)
  403. (:language #-win32 :stdc
  404. #+win32 :stdc-stdcall)
  405. (:return-type ffi:int))
  406. (ffi:def-call-out %getsockopt (:name "getsockopt")
  407. (:arguments (sockfd ffi:int)
  408. (level ffi:int)
  409. (optname ffi:int)
  410. (optval ffi:c-pointer)
  411. (optlen (ffi:c-ptr socklen_t) :out))
  412. #+win32 (:library "WS2_32")
  413. #-win32 (:library :default)
  414. (:language #-win32 :stdc
  415. #+win32 :stdc-stdcall)
  416. (:return-type ffi:int))
  417. (ffi:def-call-out %setsockopt (:name "setsockopt")
  418. (:arguments (sockfd ffi:int)
  419. (level ffi:int)
  420. (optname ffi:int)
  421. (optval ffi:c-pointer)
  422. (optlen socklen_t))
  423. #+win32 (:library "WS2_32")
  424. #-win32 (:library :default)
  425. (:language #-win32 :stdc
  426. #+win32 :stdc-stdcall)
  427. (:return-type ffi:int))
  428. (ffi:def-call-out %htonl (:name "htonl")
  429. (:arguments (hostlong ffi:uint32))
  430. #+win32 (:library "WS2_32")
  431. #-win32 (:library :default)
  432. (:language #-win32 :stdc
  433. #+win32 :stdc-stdcall)
  434. (:return-type ffi:uint32))
  435. (ffi:def-call-out %htons (:name "htons")
  436. (:arguments (hostshort ffi:uint16))
  437. #+win32 (:library "WS2_32")
  438. #-win32 (:library :default)
  439. (:language #-win32 :stdc
  440. #+win32 :stdc-stdcall)
  441. (:return-type ffi:uint16))
  442. (ffi:def-call-out %ntohl (:name "ntohl")
  443. (:arguments (netlong ffi:uint32))
  444. #+win32 (:library "WS2_32")
  445. #-win32 (:library :default)
  446. (:language #-win32 :stdc
  447. #+win32 :stdc-stdcall)
  448. (:return-type ffi:uint32))
  449. (ffi:def-call-out %ntohs (:name "ntohs")
  450. (:arguments (netshort ffi:uint16))
  451. #+win32 (:library "WS2_32")
  452. #-win32 (:library :default)
  453. (:language #-win32 :stdc
  454. #+win32 :stdc-stdcall)
  455. (:return-type ffi:uint16))
  456. (ffi:def-call-out %getsockname (:name "getsockname")
  457. (:arguments (sockfd ffi:int)
  458. (localaddr (ffi:c-ptr sockaddr) :in-out)
  459. (addrlen (ffi:c-ptr socklen_t) :in-out))
  460. #+win32 (:library "WS2_32")
  461. #-win32 (:library :default)
  462. (:language #-win32 :stdc
  463. #+win32 :stdc-stdcall)
  464. (:return-type ffi:int))
  465. (ffi:def-call-out %getpeername (:name "getpeername")
  466. (:arguments (sockfd ffi:int)
  467. (peeraddr (ffi:c-ptr sockaddr) :in-out)
  468. (addrlen (ffi:c-ptr socklen_t) :in-out))
  469. #+win32 (:library "WS2_32")
  470. #-win32 (:library :default)
  471. (:language #-win32 :stdc
  472. #+win32 :stdc-stdcall)
  473. (:return-type ffi:int))
  474. ;; socket constants
  475. (defconstant +socket-af-inet+ 2)
  476. (defconstant +socket-sock-dgram+ 2)
  477. (defconstant +socket-ip-proto-udp+ 17)
  478. (defconstant +sockopt-so-rcvtimeo+ #-linux #x1006 #+linux 20 "Socket receive timeout")
  479. (defparameter *length-of-sockaddr_in* (ffi:sizeof 'sockaddr_in))
  480. (declaim (inline fill-sockaddr_in))
  481. (defun fill-sockaddr_in (sockaddr host port)
  482. (let ((hbo (host-to-hbo host)))
  483. (ffi:with-c-place (place sockaddr)
  484. #+macos
  485. (setf (ffi:slot place 'sin_len) *length-of-sockaddr_in*)
  486. (setf (ffi:slot place 'sin_family) +socket-af-inet+
  487. (ffi:slot place 'sin_port) (%htons port)
  488. (ffi:slot place 'sin_addr) (%htonl hbo)))
  489. sockaddr))
  490. (defun socket-create-datagram (local-port
  491. &key (local-host *wildcard-host*)
  492. remote-host
  493. remote-port)
  494. (let ((sock (%socket +socket-af-inet+ +socket-sock-dgram+ +socket-ip-proto-udp+))
  495. (lsock_addr (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in)
  496. local-host local-port))
  497. (rsock_addr (when remote-host
  498. (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in)
  499. remote-host (or remote-port local-port)))))
  500. (unless (plusp sock)
  501. (error "SOCKET-CREATE-DATAGRAM ERROR (socket): ~A" (os:errno)))
  502. (unwind-protect
  503. (let ((rv (%bind sock (ffi:cast (ffi:foreign-value lsock_addr) 'sockaddr)
  504. *length-of-sockaddr_in*)))
  505. (unless (zerop rv)
  506. (error "SOCKET-CREATE-DATAGRAM ERROR (bind): ~A" (os:errno)))
  507. (when rsock_addr
  508. (let ((rv (%connect sock
  509. (ffi:cast (ffi:foreign-value rsock_addr) 'sockaddr)
  510. *length-of-sockaddr_in*)))
  511. (unless (zerop rv)
  512. (error "SOCKET-CREATE-DATAGRAM ERROR (connect): ~A" (os:errno))))))
  513. (ffi:foreign-free lsock_addr)
  514. (when remote-host
  515. (ffi:foreign-free rsock_addr)))
  516. (make-datagram-socket sock :connected-p (if rsock_addr t nil))))
  517. (defun finalize-datagram-usocket (object)
  518. (when (datagram-usocket-p object)
  519. (socket-close object)))
  520. (defmethod initialize-instance :after ((usocket datagram-usocket) &key)
  521. (setf (slot-value usocket 'recv-buffer)
  522. (ffi:allocate-shallow 'ffi:uint8 :count +max-datagram-packet-size+))
  523. ;; finalize the object
  524. (ext:finalize usocket 'finalize-datagram-usocket))
  525. (defmethod socket-close ((usocket datagram-usocket))
  526. (when (wait-list usocket)
  527. (remove-waiter (wait-list usocket) usocket))
  528. (with-slots (recv-buffer socket) usocket
  529. (ffi:foreign-free recv-buffer)
  530. (zerop (%close socket))))
  531. (defmethod socket-receive ((usocket datagram-usocket) buffer length &key)
  532. (let ((remote-address (ffi:allocate-shallow 'sockaddr_in))
  533. (remote-address-length (ffi:allocate-shallow 'ffi:int))
  534. nbytes (host 0) (port 0))
  535. (setf (ffi:foreign-value remote-address-length)
  536. *length-of-sockaddr_in*)
  537. (unwind-protect
  538. (multiple-value-bind (n address address-length)
  539. (%recvfrom (socket usocket)
  540. (ffi:foreign-address (slot-value usocket 'recv-buffer))
  541. +max-datagram-packet-size+
  542. 0 ; flags
  543. (ffi:cast (ffi:foreign-value remote-address) 'sockaddr)
  544. (ffi:foreign-value remote-address-length))
  545. (when (minusp n)
  546. (error "SOCKET-RECEIVE ERROR: ~A" (os:errno)))
  547. (setq nbytes n)
  548. (when (= address-length *length-of-sockaddr_in*)
  549. (let ((data (sockaddr-sa_data address)))
  550. (setq host (ip-from-octet-buffer data :start 2)
  551. port (port-from-octet-buffer data))))
  552. (cond ((plusp n)
  553. (let ((return-buffer (ffi:foreign-value (slot-value usocket 'recv-buffer))))
  554. (if buffer ; replace exist buffer of create new return buffer
  555. (let ((end-1 (min (or length (length buffer)) +max-datagram-packet-size+))
  556. (end-2 (min n +max-datagram-packet-size+)))
  557. (replace buffer return-buffer :end1 end-1 :end2 end-2))
  558. (setq buffer (subseq return-buffer 0 (min n +max-datagram-packet-size+))))))
  559. ((zerop n))))
  560. (ffi:foreign-free remote-address)
  561. (ffi:foreign-free remote-address-length))
  562. (values buffer nbytes host port)))
  563. ;; implementation note: different from socket-receive, we know how many bytes we want to send everytime,
  564. ;; so, a send buffer will not needed, and if there is a buffer, it's hard to fill its content like those
  565. ;; in LispWorks. So, we allocate new foreign buffer for holding data (unknown sequence subtype) every time.
  566. ;;
  567. ;; I don't know if anyone is watching my coding work, but I think this design is reasonable for CLISP.
  568. (defmethod socket-send ((usocket datagram-usocket) buffer size &key host port (offset 0))
  569. (declare (type sequence buffer)
  570. (type (integer 0 *) size offset))
  571. (let ((remote-address
  572. (when (and host port)
  573. (fill-sockaddr_in (ffi:allocate-shallow 'sockaddr_in) host port)))
  574. (send-buffer
  575. (ffi:allocate-deep 'ffi:uint8
  576. (if (zerop offset)
  577. buffer
  578. (subseq buffer offset (+ offset size)))
  579. :count size :read-only t))
  580. (real-size (min size +max-datagram-packet-size+))
  581. (nbytes 0))
  582. (unwind-protect
  583. (let ((n (if remote-address
  584. (%sendto (socket usocket)
  585. (ffi:foreign-address send-buffer)
  586. real-size
  587. 0 ; flags
  588. (ffi:cast (ffi:foreign-value remote-address) 'sockaddr)
  589. *length-of-sockaddr_in*)
  590. (%send (socket usocket)
  591. (ffi:foreign-address send-buffer)
  592. real-size
  593. 0))))
  594. (cond ((plusp n)
  595. (setq nbytes n))
  596. ((zerop n)
  597. (setq nbytes n))
  598. (t (error "SOCKET-SEND ERROR: ~A" (os:errno)))))
  599. (ffi:foreign-free send-buffer)
  600. (when remote-address
  601. (ffi:foreign-free remote-address))
  602. nbytes)))
  603. (declaim (inline get-socket-name))
  604. (defun get-socket-name (socket function)
  605. (let ((address (ffi:allocate-shallow 'sockaddr_in))
  606. (address-length (ffi:allocate-shallow 'ffi:int))
  607. (host 0) (port 0))
  608. (setf (ffi:foreign-value address-length) *length-of-sockaddr_in*)
  609. (unwind-protect
  610. (multiple-value-bind (rv return-address return-address-length)
  611. (funcall function socket
  612. (ffi:cast (ffi:foreign-value address) 'sockaddr)
  613. (ffi:foreign-value address-length))
  614. (declare (ignore return-address-length))
  615. (if (zerop rv)
  616. (let ((data (sockaddr-sa_data return-address)))
  617. (setq host (ip-from-octet-buffer data :start 2)
  618. port (port-from-octet-buffer data)))
  619. (error "GET-SOCKET-NAME ERROR: ~A" (os:errno))))
  620. (ffi:foreign-free address)
  621. (ffi:foreign-free address-length))
  622. (values (hbo-to-vector-quad host) port)))
  623. (defmethod get-local-name ((usocket datagram-usocket))
  624. (get-socket-name (socket usocket) '%getsockname))
  625. (defmethod get-peer-name ((usocket datagram-usocket))
  626. (get-socket-name (socket usocket) '%getpeername))
  627. ) ; progn