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

201 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
combinators ;
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 ;
M: unix-io addrinfo-error ( n -- )
dup zero? [ drop ] [ gai_strerror throw ] if ;
! Client sockets - TCP and Unix domain
: init-client-socket ( fd -- )
SOL_SOCKET SO_OOBINLINE sockopt ;
TUPLE: connect-task ;
2008-01-18 18:18:54 -05:00
: <connect-task> ( port continuation -- task )
2008-01-21 15:33:43 -05:00
connect-task <output-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
M: unix-io (client) ( addrspec -- stream )
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 ;
TUPLE: accept-task ;
2008-01-18 18:18:54 -05:00
: <accept-task> ( port continuation -- task )
2008-01-21 15:33:43 -05:00
accept-task <input-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
swap dup <reader&writer> <duplex-stream> <client-stream>
2007-09-20 18:09:08 -04:00
] keep set-server-port-client ;
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 ;
M: unix-io (server) ( addrspec -- handle )
SOCK_STREAM server-fd
dup 10 listen zero? [ dup close (io-error) ] unless ;
2007-09-20 18:09:08 -04:00
M: unix-io (accept) ( server -- client-in client-out )
2007-09-20 18:09:08 -04:00
#! Wait for a client connection.
dup check-server-port
dup wait-to-accept
dup pending-error
server-port-client
{ duplex-stream-in duplex-stream-out } get-slots ;
2007-09-20 18:09:08 -04:00
! Datagram sockets - UDP and Unix domain
M: unix-io <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 ;
TUPLE: receive-task ;
2008-01-18 18:18:54 -05:00
: <receive-task> ( stream continuation -- task )
2008-01-21 15:33:43 -05:00
receive-task <input-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
M: unix-io receive ( datagram -- packet addrspec )
dup check-datagram-port
dup wait-receive
dup pending-error
dup datagram-port-packet
swap datagram-port-packet-addr ;
: do-send ( socket data sockaddr len -- n )
>r >r dup length 0 r> r> sendto ;
TUPLE: send-task packet sockaddr len ;
2008-01-18 18:18:54 -05:00
: <send-task> ( packet sockaddr len stream continuation -- task )
2008-01-21 15:33:43 -05:00
send-task <output-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
M: unix-io send ( packet addrspec datagram -- )
3dup 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
local-path
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> ;