PageRenderTime 60ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/scheme/net/socket.scm

https://bitbucket.org/ebb/scheme48
Scheme | 348 lines | 282 code | 54 blank | 12 comment | 0 complexity | 5b419a5d21cf512dbfc9f405b97560ef MD5 | raw file
Possible License(s): BSD-3-Clause
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Sockets
  3. (define-record-type socket :socket
  4. (really-make-socket address-family type
  5. channel condvar
  6. input-port output-port)
  7. socket?
  8. (address-family socket-address-family)
  9. (type socket-socket-type)
  10. (channel socket-channel)
  11. (condvar socket-condvar) ; for blocking until a connection arrives
  12. (input-port socket-input-port set-socket-input-port!)
  13. (output-port socket-output-port set-socket-output-port!))
  14. (define-record-discloser :socket
  15. (lambda (s)
  16. (list 'socket
  17. (socket-address-family s)
  18. (socket-socket-type s)
  19. (socket-channel s))))
  20. (define (channel->socket family type channel)
  21. (really-make-socket family type
  22. channel
  23. (make-condvar) #f #f))
  24. (define (attach-socket-ports! socket output-channel)
  25. (let ((input-channel (socket-channel socket)))
  26. (set-socket-input-port!
  27. socket
  28. (input-channel+closer->port input-channel close-socket-input-channel))
  29. (set-socket-output-port!
  30. socket
  31. (output-channel+closer->port output-channel close-socket-output-channel))))
  32. (define make-socket
  33. (opt-lambda (family type (protocol 0)) ; ####
  34. (channel->socket family type
  35. (external-socket (address-family->raw family)
  36. (socket-type->raw type)
  37. protocol))))
  38. (import-lambda-definition-2 external-socket (family type protocol)
  39. "s48_socket")
  40. (define (dup-socket sock)
  41. (channel->socket (socket-address-family sock)
  42. (socket-socket-type sock)
  43. (external-dup-socket-channel (socket-channel sock))))
  44. (define make-socket-pair
  45. (opt-lambda (family type (protocol 0))
  46. (let ((p (external-socketpair (address-family->raw family)
  47. (socket-type->raw type)
  48. protocol)))
  49. (let ((s1 (channel->socket family type (car p)))
  50. (s2 (channel->socket family type (cdr p))))
  51. (attach-socket-ports! s1 (external-dup-socket-channel (car p)))
  52. (attach-socket-ports! s2 (external-dup-socket-channel (cdr p)))
  53. (values s1 s2)))))
  54. (import-lambda-definition-2 external-socketpair (family type protocol)
  55. "s48_socketpair")
  56. ; Close the channel, notifying any waiters that this has happened.
  57. (define (close-socket socket)
  58. (cond
  59. ((or (socket-input-port socket) (socket-output-port socket))
  60. (cond
  61. ((socket-input-port socket) => close-input-port)
  62. ((socket-output-port socket) => close-output-port)))
  63. (else
  64. (let ((channel (socket-channel socket)))
  65. (with-new-proposal (lose)
  66. (or (channel-maybe-commit-and-close channel close-channel)
  67. (lose)))))))
  68. (define (bind-socket socket address)
  69. (external-bind (socket-channel socket)
  70. (socket-address-raw address)))
  71. (import-lambda-definition-2 external-bind (channel address)
  72. "s48_bind")
  73. (define socket-listen
  74. (opt-lambda (socket (queue-size (max-socket-connection-count)))
  75. (external-listen (socket-channel socket)
  76. queue-size)))
  77. (import-lambda-definition-2 external-listen (channel queue-size)
  78. "s48_listen")
  79. (import-lambda-definition-2 max-socket-connection-count ()
  80. "s48_max_connection_count")
  81. ; FreeBSD's connect() behaves oddly. If you get told to wait, wait for select()
  82. ; to signal the all-clear, and then try to connect again, you get an `already
  83. ; connected' error. To handle this we pass in a RETRY? flag. If RETRY? is
  84. ; true the `already connected' error is ignored.
  85. (define (socket-connect socket address)
  86. (let ((channel (socket-channel socket))
  87. (raw-address (socket-address-raw address)))
  88. (let loop ((retry? #f))
  89. (disable-interrupts!)
  90. (let ((output-channel (external-connect channel raw-address retry?)))
  91. (cond ((channel? output-channel)
  92. (enable-interrupts!)
  93. (attach-socket-ports! socket output-channel))
  94. ((eq? output-channel #t)
  95. (assertion-violation 'socket-client
  96. "client socket already connected"
  97. socket address))
  98. (else
  99. (let ((condvar (make-condvar)))
  100. (wait-for-channel channel condvar)
  101. (with-new-proposal (lose)
  102. (maybe-commit-and-wait-for-condvar condvar))
  103. (enable-interrupts!)
  104. (loop #t))))))))
  105. (import-lambda-definition-2 external-connect (channel address retry?)
  106. "s48_connect")
  107. (define (socket-accept socket)
  108. (let* ((channel (blocking-socket-op socket external-accept))
  109. (newsock (channel->socket (socket-address-family socket)
  110. (socket-socket-type socket)
  111. channel)))
  112. (attach-socket-ports! newsock (external-dup-socket-channel channel))
  113. newsock))
  114. (import-lambda-definition-2 external-accept (channel retry?)
  115. "s48_accept")
  116. (import-lambda-definition-2 external-dup-socket-channel (channel)
  117. "s48_dup_socket_channel")
  118. ; Keep performing OP until it returns a non-#F value. In between attempts we
  119. ; block on the socket's channel.
  120. (define (blocking-socket-op socket op)
  121. (let ((channel (socket-channel socket))
  122. (condvar (socket-condvar socket)))
  123. (let loop ((retry? #f))
  124. (disable-interrupts!)
  125. (cond ((op channel retry?)
  126. => (lambda (result)
  127. (enable-interrupts!)
  128. result))
  129. (else
  130. (wait-for-channel channel condvar)
  131. (with-new-proposal (lose)
  132. (maybe-commit-and-wait-for-condvar condvar))
  133. (enable-interrupts!)
  134. (loop #t))))))
  135. ;----------------
  136. ; We need to explicitly close socket channels.
  137. (define-enumeration shutdown-option
  138. (read write read/write)
  139. shutdown-option-set)
  140. (define shutdown-option->raw (enum-set-indexer (shutdown-option-set)))
  141. (define (shutdown-socket socket how)
  142. (shutdown-socket-channel (socket-channel socket) how))
  143. (define (shutdown-socket-channel channel how)
  144. (external-shutdown channel (shutdown-option->raw how)))
  145. (import-lambda-definition-2 external-shutdown (channel how)
  146. "s48_shutdown")
  147. (define (close-socket-input-channel channel)
  148. (shutdown-socket-channel channel (shutdown-option read))
  149. (close-channel channel))
  150. (define (close-socket-output-channel channel)
  151. (shutdown-socket-channel channel (shutdown-option write))
  152. (close-channel channel))
  153. (define (socket-address socket)
  154. (raw->socket-address
  155. (external-getsockname (socket-channel socket))))
  156. (import-lambda-definition-2 external-getsockname (channel)
  157. "s48_getsockname")
  158. (define (socket-peer-address socket)
  159. (raw->socket-address
  160. (external-getpeername (socket-channel socket))))
  161. (import-lambda-definition-2 external-getpeername (channel)
  162. "s48_getpeername")
  163. (define-syntax define-socket-option-setter
  164. (syntax-rules ()
  165. ((define-socket-option-setter ?name ?external-name)
  166. (begin
  167. (define (?name socket val)
  168. (external-setsockopt (socket-channel socket) val))
  169. (import-lambda-definition-2 external-setsockopt (channel val)
  170. ?external-name)))))
  171. (define-syntax define-socket-option-getter
  172. (syntax-rules ()
  173. ((define-socket-option-getter ?name ?external-name)
  174. (begin
  175. (define (?name socket)
  176. (external-getsockopt (socket-channel socket)))
  177. (import-lambda-definition-2 external-getsockopt (channel)
  178. ?external-name)))))
  179. (define-socket-option-setter set-socket-debug?!
  180. "s48_setsockopt_SO_DEBUG")
  181. (define-socket-option-getter socket-debug?!
  182. "s48_getsockopt_SO_DEBUG")
  183. (define-socket-option-setter set-socket-accept-connections?!
  184. "s48_setsockopt_SO_ACCEPTCONN")
  185. (define-socket-option-getter socket-accept-connections?
  186. "s48_getsockopt_SO_ACCEPTCONN")
  187. (define-socket-option-setter set-socket-broadcast?!
  188. "s48_setsockopt_SO_BROADCAST")
  189. (define-socket-option-getter socket-broadcast?
  190. "s48_getsockopt_SO_BROADCAST")
  191. (define-socket-option-setter set-socket-reuse-address?!
  192. "s48_setsockopt_SO_REUSEADDR")
  193. (define-socket-option-getter socket-reuse-address?
  194. "s48_getsockopt_SO_REUSEADDR")
  195. (define-socket-option-setter set-socket-keepalive?!
  196. "s48_setsockopt_SO_KEEPALIVE")
  197. (define-socket-option-getter socket-keepalive?
  198. "s48_getsockopt_SO_KEEPALIVE")
  199. (define-socket-option-setter set-socket-oob-inline?!
  200. "s48_setsockopt_SO_OOBINLINE")
  201. (define-socket-option-getter socket-oob-inline?
  202. "s48_getsockopt_SO_OOBINLINE")
  203. (define-socket-option-setter set-socket-send-buffer-size!
  204. "s48_setsockopt_SO_SNDBUF")
  205. (define-socket-option-getter socket-send-buffer-size
  206. "s48_getsockopt_SO_SNDBUF")
  207. (define-socket-option-setter set-socket-receive-buffer-size!
  208. "s48_setsockopt_SO_RCVBUF")
  209. (define-socket-option-getter socket-receive-buffer-size
  210. "s48_getsockopt_SO_RCVBUF")
  211. (define-socket-option-getter socket-error
  212. "s48_getsockopt_SO_ERROR")
  213. (define-socket-option-setter set-socket-dontroute?!
  214. "s48_setsockopt_SO_DONTROUTE")
  215. (define-socket-option-getter socket-dontroute?
  216. "s48_getsockopt_SO_DONTROUTE")
  217. (define-socket-option-setter set-socket-minimum-receive-count!
  218. "s48_setsockopt_SO_RCVLOWAT")
  219. (define-socket-option-getter socket-minimum-receive-count
  220. "s48_getsockopt_SO_RCVLOWAT")
  221. (define-socket-option-setter set-socket-minimum-send-count!
  222. "s48_setsockopt_SO_SNDLOWAT")
  223. (define-socket-option-getter socket-minimum-send-count
  224. "s48_getsockopt_SO_SNDLOWAT")
  225. (define-socket-option-setter set-socket-ipv6-unicast-hops!
  226. "s48_setsockopt_IPV6_UNICAST_HOPS")
  227. (define-socket-option-getter socket-ipv6-unicast-hops
  228. "s48_getsockopt_IPV6_UNICAST_HOPS")
  229. (define-socket-option-setter set-socket-ipv6-multicast-interface!
  230. "s48_setsockopt_IPV6_MULTICAST_IF")
  231. (define-socket-option-getter socket-ipv6-multicast-interface
  232. "s48_getsockopt_IPV6_MULTICAST_IF")
  233. (define-socket-option-setter set-socket-ipv6-multicast-hops!
  234. "s48_setsockopt_IPV6_MULTICAST_HOPS")
  235. (define-socket-option-getter socket-ipv6-multicast-hops
  236. "s48_getsockopt_IPV6_MULTICAST_HOPS")
  237. (define-socket-option-setter set-socket-ipv6-multicast-loop?!
  238. "s48_setsockopt_IPV6_MULTICAST_LOOP")
  239. (define-socket-option-getter socket-ipv6-multicast-loop?
  240. "s48_getsockopt_IPV6_MULTICAST_LOOP")
  241. (define (socket-ipv6-join-group! socket address interface)
  242. (external-ipv6-socket-join-group (socket-channel socket)
  243. (socket-address-raw address)
  244. (interface-index interface)))
  245. (import-lambda-definition-2 external-ipv6-socket-join-group (channel address if-index)
  246. "s48_ipv6_socket_join_group")
  247. (define (socket-ipv6-leave-group! socket address interface)
  248. (external-ipv6-socket-leave-group (socket-channel socket)
  249. (socket-address-raw address)
  250. (interface-index interface)))
  251. (import-lambda-definition-2 external-ipv6-socket-leave-group (channel address if-index)
  252. "s48_ipv6_socket_leave_group")
  253. ; Messages
  254. (define-enumeration message-option
  255. (oob peek dontroute)
  256. message-options)
  257. (define socket-send
  258. (opt-lambda (socket
  259. buffer
  260. (start 0)
  261. (count (byte-vector-length buffer))
  262. (address (socket-peer-address socket)) ; cache this?
  263. (flags (message-options)))
  264. (blocking-socket-op socket
  265. (lambda (channel retry?)
  266. (external-sendto channel buffer start count
  267. (enum-set->integer flags)
  268. (socket-address-raw address)
  269. retry?)))))
  270. (import-lambda-definition-2 external-sendto (channel
  271. buffer start count flags address
  272. retry?)
  273. "s48_sendto")
  274. (define socket-receive
  275. (opt-lambda (socket
  276. buffer
  277. (start 0)
  278. (count (byte-vector-length buffer))
  279. (want-sender? #t)
  280. (flags (message-options)))
  281. (let ((got
  282. (blocking-socket-op socket
  283. (lambda (channel retry?)
  284. (external-recvfrom channel buffer start count
  285. (enum-set->integer flags)
  286. want-sender?
  287. retry?)))))
  288. (if want-sender?
  289. (values (car got) (raw->socket-address (cdr got)))
  290. got))))
  291. (import-lambda-definition-2 external-recvfrom (channel
  292. buffer start count flags
  293. want-sender? retry?)
  294. "s48_recvfrom")