factor/extra/io/unix/sockets/sockets.factor

199 lines
5.6 KiB
Factor
Raw Normal View History

2008-02-21 16:22:49 -05:00
! Copyright (C) 2004, 2008 Slava Pestov, Ivan Tikhonov.
2007-09-20 18:09:08 -04:00
! See http://factorcode.org/license.txt for BSD license.
! We need to fiddle with the exact search order here, since
! unix::accept shadows streams::accept.
2008-02-18 08:30:16 -05:00
USING: alien alien.c-types generic io kernel math namespaces
io.nonblocking parser threads unix sequences
byte-arrays io.sockets io.binary io.unix.backend
io.streams.duplex io.sockets.impl math.parser continuations libc
2008-04-11 17:08:40 -04:00
combinators io.backend io.files io.files.private system accessors ;
IN: io.unix.sockets
2007-09-20 18:09:08 -04:00
: pending-init-error ( port -- )
#! We close it here to avoid a resource leak; callers of
#! <client> don't set up error handlers until after <client>
#! returns (and if they did before, they wouldn't have
#! anything to close!)
dup port-error dup [ swap dispose throw ] [ 2drop ] if ;
2007-09-20 18:09:08 -04:00
: socket-fd ( domain type -- socket )
0 socket dup io-error dup init-handle ;
: sockopt ( fd level opt -- )
1 <int> "int" heap-size setsockopt io-error ;
2008-04-02 21:33:36 -04:00
M: unix addrinfo-error ( n -- )
2007-09-20 18:09:08 -04:00
dup zero? [ drop ] [ gai_strerror throw ] if ;
! Client sockets - TCP and Unix domain
: init-client-socket ( fd -- )
SOL_SOCKET SO_OOBINLINE sockopt ;
2008-04-11 13:47:49 -04:00
TUPLE: connect-task < output-task ;
2007-09-20 18:09:08 -04:00
2008-01-18 18:18:54 -05:00
: <connect-task> ( port continuation -- task )
2008-04-11 13:47:49 -04:00
connect-task <io-task> ;
2007-09-20 18:09:08 -04:00
M: connect-task do-io-task
io-task-port dup port-handle f 0 write
0 < [ defer-error ] [ drop t ] if ;
: wait-to-connect ( port -- )
2008-01-31 13:27:37 -05:00
[ <connect-task> add-io-task ] with-port-continuation drop ;
2007-09-20 18:09:08 -04:00
2008-04-11 17:08:40 -04:00
M: unix ((client)) ( addrspec -- client-in client-out )
dup make-sockaddr/size >r >r
2007-09-20 18:09:08 -04:00
protocol-family SOCK_STREAM socket-fd
dup r> r> connect
2007-09-20 18:09:08 -04:00
zero? err_no EINPROGRESS = or [
dup init-client-socket
dup <reader&writer>
2007-09-20 18:09:08 -04:00
dup wait-to-connect
dup pending-init-error
2007-09-20 18:09:08 -04:00
] [
dup close (io-error)
] if ;
! Server sockets - TCP and Unix domain
USE: unix
: init-server-socket ( fd -- )
SOL_SOCKET SO_REUSEADDR sockopt ;
2008-04-11 13:47:49 -04:00
TUPLE: accept-task < input-task ;
2007-09-20 18:09:08 -04:00
2008-01-18 18:18:54 -05:00
: <accept-task> ( port continuation -- task )
2008-04-11 13:47:49 -04:00
accept-task <io-task> ;
2007-09-20 18:09:08 -04:00
: accept-sockaddr ( port -- fd sockaddr )
dup port-handle swap server-port-addr sockaddr-type
dup <c-object> [ swap heap-size <int> accept ] keep ; inline
: do-accept ( port fd sockaddr -- )
rot
[ server-port-addr parse-sockaddr ] keep
[ set-server-port-client-addr ] keep
set-server-port-client ;
2007-09-20 18:09:08 -04:00
M: accept-task do-io-task
io-task-port dup accept-sockaddr
over 0 >= [ do-accept t ] [ 2drop defer-error ] if ;
: wait-to-accept ( server -- )
2008-01-31 13:27:37 -05:00
[ <accept-task> add-io-task ] with-port-continuation drop ;
2007-09-20 18:09:08 -04:00
USE: io.sockets
: server-fd ( addrspec type -- fd )
>r dup protocol-family r> socket-fd
dup init-server-socket
dup rot make-sockaddr/size bind
2007-09-20 18:09:08 -04:00
zero? [ dup close (io-error) ] unless ;
2008-04-02 21:33:36 -04:00
M: unix (server) ( addrspec -- handle )
SOCK_STREAM server-fd
dup 10 listen zero? [ dup close (io-error) ] unless ;
2007-09-20 18:09:08 -04:00
2008-04-02 21:33:36 -04:00
M: unix (accept) ( server -- addrspec handle )
2007-09-20 18:09:08 -04:00
#! Wait for a client connection.
2008-04-11 17:08:40 -04:00
check-server-port
[ wait-to-accept ]
[ pending-error ]
[ [ client-addr>> ] [ client>> ] bi ] tri ;
2007-09-20 18:09:08 -04:00
! Datagram sockets - UDP and Unix domain
2008-04-02 21:33:36 -04:00
M: unix <datagram>
2008-01-21 15:33:43 -05:00
[ SOCK_DGRAM server-fd ] keep <datagram-port> ;
2007-09-20 18:09:08 -04:00
SYMBOL: receive-buffer
: packet-size 65536 ; inline
packet-size <byte-array> receive-buffer set-global
: setup-receive ( port -- s buffer len flags from fromlen )
dup port-handle
swap datagram-port-addr sockaddr-type
dup <c-object> swap heap-size <int>
>r >r receive-buffer get-global packet-size 0 r> r> ;
: do-receive ( s buffer len flags from fromlen -- sockaddr data )
over >r recvfrom r>
over -1 = [
2drop f f
] [
receive-buffer get-global
rot head
] if ;
2008-04-11 13:47:49 -04:00
TUPLE: receive-task < input-task ;
2007-09-20 18:09:08 -04:00
2008-01-18 18:18:54 -05:00
: <receive-task> ( stream continuation -- task )
2008-04-11 13:47:49 -04:00
receive-task <io-task> ;
2007-09-20 18:09:08 -04:00
M: receive-task do-io-task
io-task-port
dup setup-receive do-receive dup [
pick set-datagram-port-packet
over datagram-port-addr parse-sockaddr
swap set-datagram-port-packet-addr
t
] [
2drop defer-error
] if ;
: wait-receive ( stream -- )
2008-01-31 13:27:37 -05:00
[ <receive-task> add-io-task ] with-port-continuation drop ;
2007-09-20 18:09:08 -04:00
2008-04-02 21:33:36 -04:00
M: unix receive ( datagram -- packet addrspec )
2008-04-11 17:08:40 -04:00
check-datagram-port
[ wait-receive ]
[ pending-error ]
[ [ packet>> ] [ packet-addr>> ] bi ] tri ;
2007-09-20 18:09:08 -04:00
: do-send ( socket data sockaddr len -- n )
>r >r dup length 0 r> r> sendto ;
2008-04-11 13:47:49 -04:00
TUPLE: send-task < output-task packet sockaddr len ;
2007-09-20 18:09:08 -04:00
2008-01-18 18:18:54 -05:00
: <send-task> ( packet sockaddr len stream continuation -- task )
2008-04-11 13:47:49 -04:00
send-task <io-task> [
2007-09-20 18:09:08 -04:00
{
set-send-task-packet
set-send-task-sockaddr
set-send-task-len
} set-slots
] keep ;
M: send-task do-io-task
[ io-task-port port-handle ] keep
[ send-task-packet ] keep
[ send-task-sockaddr ] keep
[ send-task-len do-send ] keep
swap 0 < [ io-task-port defer-error ] [ drop t ] if ;
: wait-send ( packet sockaddr len stream -- )
2008-01-31 13:27:37 -05:00
[ <send-task> add-io-task ] with-port-continuation
2drop 2drop ;
2007-09-20 18:09:08 -04:00
2008-04-02 21:33:36 -04:00
M: unix send ( packet addrspec datagram -- )
2008-04-11 17:08:40 -04:00
check-datagram-send
[ >r make-sockaddr/size r> wait-send ] keep
2007-09-20 18:09:08 -04:00
pending-error ;
M: local protocol-family drop PF_UNIX ;
M: local sockaddr-type drop "sockaddr-un" c-type ;
2007-09-20 18:09:08 -04:00
M: local make-sockaddr
2008-03-31 14:51:34 -04:00
local-path cwd prepend-path
2007-09-20 18:09:08 -04:00
dup length 1 + max-un-path > [ "Path too long" throw ] when
"sockaddr-un" <c-object>
AF_UNIX over set-sockaddr-un-family
dup sockaddr-un-path rot string>char-alien dup length memcpy ;
2007-09-20 18:09:08 -04:00
M: local parse-sockaddr
drop
sockaddr-un-path alien>char-string <local> ;