PageRenderTime 58ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/src/sockets/socket-methods.lisp

https://bitbucket.org/sionescu/iolib
Lisp | 589 lines | 453 code | 86 blank | 50 comment | 1 complexity | c3880e03df145e31cebb9e8763b2613e MD5 | raw file
  1. ;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
  2. ;;;
  3. ;;; --- Various socket methods.
  4. ;;;
  5. (in-package :iolib/sockets)
  6. ;;;-------------------------------------------------------------------------
  7. ;;; Shared Initialization
  8. ;;;-------------------------------------------------------------------------
  9. (defun translate-make-socket-keywords-to-constants (address-family type protocol)
  10. (let ((sf (ecase address-family
  11. (:ipv4 af-inet)
  12. (:ipv6 af-inet6)
  13. (:local af-local)
  14. #+linux
  15. (:netlink af-netlink)))
  16. (st (ecase type
  17. (:stream sock-stream)
  18. (:datagram sock-dgram)
  19. (:raw sock-raw)))
  20. (sp (etypecase protocol
  21. ((eql :default) 0)
  22. (integer protocol))))
  23. (values sf st sp)))
  24. (defmethod socket-os-fd ((socket socket))
  25. (fd-of socket))
  26. (defmethod shared-initialize :after
  27. ((socket socket) slot-names
  28. &key file-descriptor (dup t) address-family type protocol)
  29. (declare (ignore slot-names))
  30. (with-accessors ((fd fd-of) (fam socket-address-family) (proto socket-protocol))
  31. socket
  32. (setf fd (or (and file-descriptor (if dup
  33. (isys:dup file-descriptor)
  34. file-descriptor))
  35. (multiple-value-call #'%socket
  36. (translate-make-socket-keywords-to-constants
  37. address-family type protocol))))
  38. (setf fam address-family
  39. proto protocol)))
  40. (defmethod (setf external-format-of) (external-format (socket passive-socket))
  41. (setf (slot-value socket 'external-format)
  42. (babel:ensure-external-format (or external-format :default))))
  43. (defmethod shared-initialize :after ((socket passive-socket) slot-names
  44. &key external-format
  45. input-buffer-size output-buffer-size)
  46. ;; Makes CREATE-SOCKET simpler
  47. (declare (ignore slot-names input-buffer-size output-buffer-size))
  48. (setf (external-format-of socket) (or external-format :default)))
  49. ;;;-------------------------------------------------------------------------
  50. ;;; Misc
  51. ;;;-------------------------------------------------------------------------
  52. (defmethod socket-type ((socket stream-socket))
  53. :stream)
  54. (defmethod socket-type ((socket datagram-socket))
  55. :datagram)
  56. (defun socket-ipv6-p (socket)
  57. "Return T if SOCKET is an AF_INET6 socket."
  58. (eql :ipv6 (socket-address-family socket)))
  59. (defun ipv6-socket-p (&rest args)
  60. (apply #'socket-ipv6-p args))
  61. (defobsolete ipv6-socket-p socket-ipv6-p)
  62. ;;;-------------------------------------------------------------------------
  63. ;;; PRINT-OBJECT
  64. ;;;-------------------------------------------------------------------------
  65. (defun sock-fam (socket)
  66. (ecase (socket-address-family socket)
  67. (:ipv4 "IPv4")
  68. (:ipv6 "IPv6")))
  69. (defmethod print-object ((socket socket-stream-internet-active) stream)
  70. (print-unreadable-object (socket stream :identity t)
  71. (format stream "active ~A stream socket" (sock-fam socket))
  72. (if (socket-connected-p socket)
  73. (multiple-value-bind (host port) (remote-name socket)
  74. (format stream " connected to ~A/~A"
  75. (address-to-string host) port))
  76. (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
  77. (defmethod print-object ((socket socket-stream-internet-passive) stream)
  78. (print-unreadable-object (socket stream :identity t)
  79. (format stream "passive ~A stream socket" (sock-fam socket))
  80. (if (socket-bound-p socket)
  81. (multiple-value-bind (host port) (local-name socket)
  82. (format stream " ~:[bound to~;waiting @~] ~A/~A"
  83. (socket-listening-p socket)
  84. (address-to-string host) port))
  85. (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
  86. (defmethod print-object ((socket socket-stream-local-active) stream)
  87. (print-unreadable-object (socket stream :identity t)
  88. (format stream "active local stream socket")
  89. (if (socket-connected-p socket)
  90. (format stream " connected to ~S"
  91. (address-to-string (remote-filename socket)))
  92. (format stream ", ~:[closed~;unconnected~]" (fd-of socket)))))
  93. (defmethod print-object ((socket socket-stream-local-passive) stream)
  94. (print-unreadable-object (socket stream :identity t)
  95. (format stream "passive local stream socket")
  96. (if (socket-bound-p socket)
  97. (format stream " ~:[bound to~;waiting @~] ~A"
  98. (socket-listening-p socket)
  99. (address-to-string (local-filename socket)))
  100. (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
  101. (defmethod print-object ((socket socket-datagram-local) stream)
  102. (print-unreadable-object (socket stream :identity t)
  103. (format stream "local datagram socket")
  104. (if (socket-connected-p socket)
  105. (format stream " connected to ~S"
  106. (address-to-string (remote-filename socket)))
  107. (if (fd-of socket)
  108. (format stream " waiting @ ~S" (address-to-string (local-filename socket)))
  109. (format stream ", closed" )))))
  110. (defmethod print-object ((socket socket-datagram-internet) stream)
  111. (print-unreadable-object (socket stream :identity t)
  112. (format stream "~A datagram socket" (sock-fam socket))
  113. (if (socket-connected-p socket)
  114. (multiple-value-bind (host port) (remote-name socket)
  115. (format stream " connected to ~A/~A"
  116. (address-to-string host) port))
  117. (if (fd-of socket)
  118. (multiple-value-bind (host port) (local-name socket)
  119. (format stream " waiting @ ~A/~A"
  120. (address-to-string host) port))
  121. (format stream ", closed" )))))
  122. #+linux
  123. (defmethod print-object ((socket socket-raw-netlink) stream)
  124. (print-unreadable-object (socket stream :identity t)
  125. (format stream "netlink socket")
  126. (if (socket-bound-p socket)
  127. (multiple-value-bind (address port)
  128. (local-name socket)
  129. (format stream " bound to ~A@~A"
  130. port (address-to-string address)))
  131. (format stream ", ~:[closed~;unbound~]" (fd-of socket)))))
  132. ;;;-------------------------------------------------------------------------
  133. ;;; CLOSE
  134. ;;;-------------------------------------------------------------------------
  135. (defmethod close :before ((socket socket) &key abort)
  136. (declare (ignore abort))
  137. (setf (slot-value socket 'bound) nil))
  138. (defmethod close ((socket socket) &key abort)
  139. (declare (ignore abort))
  140. (when (next-method-p)
  141. (call-next-method))
  142. (socket-open-p socket))
  143. (defmethod close :before ((socket passive-socket) &key abort)
  144. (declare (ignore abort))
  145. (setf (slot-value socket 'listening) nil))
  146. (defmethod socket-open-p ((socket socket))
  147. (if (null (fd-of socket))
  148. nil
  149. (with-sockaddr-storage-and-socklen (ss size)
  150. (handler-case
  151. (%getsockname (fd-of socket) ss size)
  152. (isys:ebadf () nil)
  153. (socket-connection-reset-error () nil)
  154. (:no-error (_) (declare (ignore _)) t)))))
  155. ;;;-------------------------------------------------------------------------
  156. ;;; GETSOCKNAME
  157. ;;;-------------------------------------------------------------------------
  158. (defun %local-name (socket)
  159. (with-sockaddr-storage-and-socklen (ss size)
  160. (%getsockname (fd-of socket) ss size)
  161. (sockaddr-storage->sockaddr ss)))
  162. (defmethod local-name ((socket socket))
  163. (%local-name socket))
  164. (defmethod local-host ((socket internet-socket))
  165. (nth-value 0 (%local-name socket)))
  166. (defmethod local-port ((socket internet-socket))
  167. (nth-value 1 (%local-name socket)))
  168. #+linux
  169. (defmethod local-port ((socket netlink-socket))
  170. (nth-value 1 (%local-name socket)))
  171. (defmethod local-filename ((socket local-socket))
  172. (%local-name socket))
  173. ;;;-------------------------------------------------------------------------
  174. ;;; GETPEERNAME
  175. ;;;-------------------------------------------------------------------------
  176. (defun %remote-name (socket)
  177. (with-sockaddr-storage-and-socklen (ss size)
  178. (%getpeername (fd-of socket) ss size)
  179. (sockaddr-storage->sockaddr ss)))
  180. (defmethod remote-name ((socket socket))
  181. (%remote-name socket))
  182. (defmethod remote-host ((socket internet-socket))
  183. (nth-value 0 (%remote-name socket)))
  184. (defmethod remote-port ((socket internet-socket))
  185. (nth-value 1 (%remote-name socket)))
  186. (defmethod remote-filename ((socket local-socket))
  187. (%remote-name socket))
  188. ;;;-------------------------------------------------------------------------
  189. ;;; BIND
  190. ;;;-------------------------------------------------------------------------
  191. (defmethod bind-address :before ((socket internet-socket) address
  192. &key (reuse-address t))
  193. (declare (ignore address))
  194. (when reuse-address
  195. (setf (socket-option socket :reuse-address) t)))
  196. (defun bind-ipv4-address (fd address port)
  197. (with-sockaddr-in (sin address port)
  198. (%bind fd sin (isys:sizeof 'sockaddr-in))))
  199. (defun bind-ipv6-address (fd address port)
  200. (with-sockaddr-in6 (sin6 address port)
  201. (%bind fd sin6 (isys:sizeof 'sockaddr-in6))))
  202. (defmethod bind-address ((socket internet-socket) (address ipv4-address)
  203. &key (port 0))
  204. (let ((port (ensure-numerical-service port)))
  205. (if (socket-ipv6-p socket)
  206. (bind-ipv6-address (fd-of socket)
  207. (map-ipv4-vector-to-ipv6 (address-name address))
  208. port)
  209. (bind-ipv4-address (fd-of socket) (address-name address) port)))
  210. (values socket))
  211. (defmethod bind-address ((socket internet-socket) (address ipv6-address)
  212. &key (port 0))
  213. (bind-ipv6-address (fd-of socket)
  214. (address-name address)
  215. (ensure-numerical-service port))
  216. (values socket))
  217. (defmethod bind-address ((socket local-socket) (address local-address) &key)
  218. (with-sockaddr-un (sun (address-name address) (abstract-address-p address))
  219. (%bind (fd-of socket) sun (actual-size-of-sockaddr-un sun)))
  220. (values socket))
  221. #+linux
  222. (defmethod bind-address ((socket netlink-socket) (address netlink-address)
  223. &key (port 0))
  224. (with-sockaddr-nl (snl (netlink-address-multicast-groups address) port)
  225. (%bind (fd-of socket) snl (isys:sizeof 'sockaddr-nl)))
  226. (values socket))
  227. (defmethod bind-address :after ((socket socket) (address address) &key)
  228. (setf (slot-value socket 'bound) t))
  229. ;;;-------------------------------------------------------------------------
  230. ;;; LISTEN
  231. ;;;-------------------------------------------------------------------------
  232. (defmethod listen-on ((socket socket) &key backlog)
  233. (unless backlog (setf backlog (min *default-backlog-size*
  234. +max-backlog-size+)))
  235. (check-type backlog unsigned-byte "a non-negative integer")
  236. (%listen (fd-of socket) backlog)
  237. (setf (slot-value socket 'listening) t)
  238. (values socket))
  239. ;;;-------------------------------------------------------------------------
  240. ;;; ACCEPT
  241. ;;;-------------------------------------------------------------------------
  242. (defmethod accept-connection ((socket passive-socket) &key external-format
  243. input-buffer-size output-buffer-size (wait t))
  244. (check-type wait timeout-designator)
  245. (flet ((make-client-socket (fd)
  246. (make-instance (active-class socket)
  247. :address-family (socket-address-family socket)
  248. :file-descriptor fd :dup nil
  249. :external-format (or external-format
  250. (external-format-of socket))
  251. :input-buffer-size input-buffer-size
  252. :output-buffer-size output-buffer-size)))
  253. (ignore-some-conditions (isys:ewouldblock iomux:poll-timeout)
  254. (iomux:wait-until-fd-ready (fd-of socket) :input (wait->timeout wait) t)
  255. (with-sockaddr-storage-and-socklen (ss size)
  256. (multiple-value-call #'values
  257. (make-client-socket (%accept (fd-of socket) ss size))
  258. (sockaddr-storage->sockaddr ss))))))
  259. ;;;-------------------------------------------------------------------------
  260. ;;; CONNECT
  261. ;;;-------------------------------------------------------------------------
  262. (defun ipv4-connect (fd address port)
  263. (with-sockaddr-in (sin address port)
  264. (%connect fd sin (isys:sizeof 'sockaddr-in))))
  265. (defun ipv6-connect (fd address port)
  266. (with-sockaddr-in6 (sin6 address port)
  267. (%connect fd sin6 (isys:sizeof 'sockaddr-in6))))
  268. (defun call-with-socket-to-wait-connect (socket thunk wait)
  269. (check-type wait timeout-designator)
  270. (let ((timeout (wait->timeout wait)))
  271. (flet
  272. ((wait-connect ()
  273. (when (or (null timeout)
  274. (plusp timeout))
  275. (handler-case
  276. (iomux:wait-until-fd-ready (fd-of socket) :output timeout t)
  277. (iomux:poll-error ()
  278. (let ((errcode (socket-option socket :error)))
  279. (if (zerop errcode)
  280. (bug "Polling socket signalled an error but SO_ERROR is 0")
  281. (signal-socket-error errcode "connect" (fd-of socket)))))))))
  282. (ignore-some-conditions (iomux:poll-timeout)
  283. (handler-case
  284. (funcall thunk)
  285. ((or isys:ewouldblock
  286. isys:einprogress) ()
  287. (wait-connect)))))))
  288. (defmacro with-socket-to-wait-connect ((socket wait) &body body)
  289. `(call-with-socket-to-wait-connect ,socket (lambda () ,@body) ,wait))
  290. (defmethod connect ((socket internet-socket) (address inet-address)
  291. &key (port 0) (wait t))
  292. (let ((name (address-name address))
  293. (port (ensure-numerical-service port)))
  294. (with-socket-to-wait-connect (socket wait)
  295. (cond
  296. ((socket-ipv6-p socket)
  297. (when (ipv4-address-p address)
  298. (setf name (map-ipv4-vector-to-ipv6 name)))
  299. (ipv6-connect (fd-of socket) name port))
  300. (t (ipv4-connect (fd-of socket) name port)))))
  301. (values socket))
  302. (defmethod connect ((socket local-socket) (address local-address) &key (wait t))
  303. (with-socket-to-wait-connect (socket wait)
  304. (with-sockaddr-un (sun (address-name address) (abstract-address-p address))
  305. (%connect (fd-of socket) sun (actual-size-of-sockaddr-un sun))))
  306. (values socket))
  307. (defmethod socket-connected-p ((socket socket))
  308. (if (fd-of socket)
  309. (with-sockaddr-storage-and-socklen (ss size)
  310. (handler-case
  311. (%getpeername (fd-of socket) ss size)
  312. ((or isys:enotconn isys:einval) () nil)
  313. (:no-error (_) (declare (ignore _)) t)))
  314. nil))
  315. ;;;-------------------------------------------------------------------------
  316. ;;; DISCONNECT
  317. ;;;-------------------------------------------------------------------------
  318. (defmethod disconnect ((socket datagram-socket))
  319. (with-foreign-object (sin 'sockaddr-in)
  320. (isys:bzero sin (isys:sizeof 'sockaddr-in))
  321. (setf (foreign-slot-value sin 'sockaddr-in 'addr) af-unspec)
  322. (%connect (fd-of socket) sin (isys:sizeof 'sockaddr-in))
  323. (values socket)))
  324. ;;;-------------------------------------------------------------------------
  325. ;;; SHUTDOWN
  326. ;;;-------------------------------------------------------------------------
  327. (defmethod shutdown ((socket socket) &key read write)
  328. (assert (or read write) (read write)
  329. "You must select at least one direction to shut down.")
  330. (%shutdown (fd-of socket)
  331. (multiple-value-case ((read write))
  332. ((* nil) shut-rd)
  333. ((nil *) shut-wr)
  334. (t shut-rdwr)))
  335. (values socket))
  336. ;;;-------------------------------------------------------------------------
  337. ;;; Socket flag definition
  338. ;;;-------------------------------------------------------------------------
  339. (defmacro define-socket-flag (place name value platform)
  340. (let ((val (cond ((or (not platform)
  341. (featurep platform)) value)
  342. ((not (featurep platform)) 0))))
  343. `(pushnew (cons ,name ,val) ,place)))
  344. (defmacro define-socket-flags (place &body definitions)
  345. (flet ((dflag (form)
  346. (destructuring-bind (name value &optional platform) form
  347. `(define-socket-flag ,place ,name ,value ,platform))))
  348. `(progn
  349. ,@(mapcar #'dflag definitions))))
  350. ;;;-------------------------------------------------------------------------
  351. ;;; SENDTO
  352. ;;;-------------------------------------------------------------------------
  353. (defvar *sendto-flags* ())
  354. (define-socket-flags *sendto-flags*
  355. (:dont-route msg-dontroute)
  356. (:dont-wait msg-dontwait (:not :windows))
  357. (:out-of-band msg-oob)
  358. (:more msg-more :linux)
  359. (:confirm msg-confirm :linux))
  360. (defun %%send-to (fd ss got-peer buff-sap start length flags)
  361. (incf-pointer buff-sap start)
  362. (loop
  363. (restart-case
  364. (return*
  365. (%sendto fd buff-sap length flags
  366. (if got-peer ss (null-pointer))
  367. (if got-peer (sockaddr-size ss) 0)))
  368. (ignore-syscall-error ()
  369. :report "Ignore this socket condition"
  370. :test isys:syscall-error-p
  371. (return* 0))
  372. (retry-syscall (&optional (timeout 15.0d0))
  373. :report "Try to send data again"
  374. :test isys:syscall-error-p
  375. (when (plusp timeout)
  376. (iomux:wait-until-fd-ready fd :output timeout nil))))))
  377. (defun %send-to (fd ss got-peer buffer start end flags)
  378. (etypecase buffer
  379. (ub8-sarray
  380. (check-bounds buffer start end)
  381. (with-pointer-to-vector-data (buff-sap buffer)
  382. (%%send-to fd ss got-peer buff-sap start (- end start) flags)))
  383. ((or ub8-vector (vector t))
  384. (check-bounds buffer start end)
  385. (with-pointer-to-vector-data (buff-sap (coerce buffer 'ub8-sarray))
  386. (%%send-to fd ss got-peer buff-sap start (- end start) flags)))
  387. (foreign-pointer
  388. (check-type start unsigned-byte)
  389. (check-type end unsigned-byte)
  390. (%%send-to fd ss got-peer buffer start (- end start) flags))))
  391. (defmethod send-to ((socket internet-socket) buffer &rest args
  392. &key (start 0) end remote-host (remote-port 0) flags (ipv6 *ipv6*))
  393. (let ((*ipv6* ipv6))
  394. (with-sockaddr-storage (ss)
  395. (when remote-host
  396. (sockaddr->sockaddr-storage ss (ensure-hostname remote-host)
  397. (ensure-numerical-service remote-port)))
  398. (%send-to (fd-of socket) ss (if remote-host t) buffer start end
  399. (or flags (compute-flags *sendto-flags* args))))))
  400. (defmethod send-to ((socket local-socket) buffer &rest args
  401. &key (start 0) end remote-filename flags)
  402. (with-sockaddr-storage (ss)
  403. (when remote-filename
  404. (sockaddr->sockaddr-storage ss (ensure-address remote-filename :family :local) 0))
  405. (%send-to (fd-of socket) ss (if remote-filename t) buffer start end
  406. (or flags (compute-flags *sendto-flags* args)))))
  407. (define-compiler-macro send-to (&whole form &environment env socket buffer &rest args
  408. &key (start 0) end (remote-host nil host-p) (remote-port 0 port-p)
  409. (remote-filename nil file-p) flags (ipv6 '*ipv6* ipv6-p) &allow-other-keys)
  410. (let ((flags-val (compute-flags *sendto-flags* args env)))
  411. (cond
  412. ((and (not flags) flags-val)
  413. (append
  414. `(send-to ,socket ,buffer :start ,start :end ,end :flags ,flags-val)
  415. (when host-p `(:remote-host ,remote-host))
  416. (when port-p `(:remote-port ,remote-port))
  417. (when ipv6-p `(:ipv6 ,ipv6))
  418. (when file-p `(:remote-filename ,remote-filename))))
  419. (t
  420. form))))
  421. ;;;-------------------------------------------------------------------------
  422. ;;; RECVFROM
  423. ;;;-------------------------------------------------------------------------
  424. (defvar *recvfrom-flags* ())
  425. (define-socket-flags *recvfrom-flags*
  426. (:out-of-band msg-oob)
  427. (:peek msg-peek)
  428. (:wait-all msg-waitall (:not :windows))
  429. (:dont-wait msg-dontwait (:not :windows)))
  430. (defun %%receive-from (fd ss size buffer start length flags)
  431. (with-pointer-to-vector-data (buff-sap buffer)
  432. (incf-pointer buff-sap start)
  433. (loop
  434. (restart-case
  435. (return* (%recvfrom fd buff-sap length flags ss size))
  436. (ignore-syscall-error ()
  437. :report "Ignore this socket condition"
  438. :test isys:syscall-error-p
  439. (return* 0))
  440. (retry-syscall (&optional (timeout 15.0d0))
  441. :report "Try to receive data again"
  442. :test isys:syscall-error-p
  443. (when (plusp timeout)
  444. (iomux:wait-until-fd-ready fd :input timeout nil)))))))
  445. (defun %receive-from (fd ss size buffer start end flags)
  446. (check-bounds buffer start end)
  447. (flet ((%do-recvfrom (buff start length)
  448. (%%receive-from fd ss size buff start length flags)))
  449. (let (nbytes)
  450. (etypecase buffer
  451. (ub8-sarray
  452. (setf nbytes (%do-recvfrom buffer start (- end start))))
  453. ((or ub8-vector (vector t))
  454. (let ((tmpbuff (make-array (- end start) :element-type 'ub8)))
  455. (setf nbytes (%do-recvfrom tmpbuff 0 (- end start)))
  456. (replace buffer tmpbuff :start1 start :end1 end :start2 0 :end2 nbytes))))
  457. (values nbytes))))
  458. (defmethod receive-from :around ((socket socket) &rest args
  459. &key buffer size (start 0) end flags &allow-other-keys)
  460. (let ((flags-val (or flags (compute-flags *recvfrom-flags* args))))
  461. (cond
  462. (buffer
  463. (call-next-method socket :buffer buffer :start start :end end :flags flags-val))
  464. (t
  465. (check-type size unsigned-byte "a non-negative integer")
  466. (call-next-method socket :buffer (make-array size :element-type 'ub8)
  467. :start 0 :end size :flags flags-val)))))
  468. (defmethod receive-from ((socket stream-socket) &key buffer start end flags)
  469. (with-sockaddr-storage-and-socklen (ss size)
  470. (let ((nbytes (%receive-from (fd-of socket) ss size buffer start end flags)))
  471. (values buffer nbytes))))
  472. (defmethod receive-from ((socket raw-socket) &key buffer start end flags)
  473. (with-sockaddr-storage-and-socklen (ss size)
  474. (let ((nbytes (%receive-from (fd-of socket) ss size buffer start end flags)))
  475. (values buffer nbytes))))
  476. (defmethod receive-from ((socket datagram-socket) &key buffer start end flags)
  477. (with-sockaddr-storage-and-socklen (ss size)
  478. (let ((nbytes (%receive-from (fd-of socket) ss size buffer start end flags)))
  479. (multiple-value-call #'values buffer nbytes
  480. (sockaddr-storage->sockaddr ss)))))
  481. (define-compiler-macro receive-from (&whole form &environment env socket &rest args
  482. &key buffer size (start 0) end flags &allow-other-keys)
  483. (let ((flags-val (compute-flags *recvfrom-flags* args env)))
  484. (cond
  485. ((and (not flags) flags-val)
  486. `(receive-from ,socket :buffer ,buffer :start ,start :end ,end
  487. :size ,size :flags ,flags-val))
  488. (t
  489. form))))