PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/scheme/net/socket.scm

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