201 lines
5.6 KiB
Factor
Executable File
201 lines
5.6 KiB
Factor
Executable File
! Copyright (C) 2004, 2008 Slava Pestov, Ivan Tikhonov.
|
|
! 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.
|
|
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
|
|
|
|
: 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 ;
|
|
|
|
: 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 ;
|
|
|
|
: <connect-task> ( port continuation -- task )
|
|
connect-task <output-task> ;
|
|
|
|
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 -- )
|
|
[ <connect-task> add-io-task ] with-port-continuation drop ;
|
|
|
|
M: unix-io (client) ( addrspec -- stream )
|
|
dup make-sockaddr/size >r >r
|
|
protocol-family SOCK_STREAM socket-fd
|
|
dup r> r> connect
|
|
zero? err_no EINPROGRESS = or [
|
|
dup init-client-socket
|
|
dup <reader&writer>
|
|
dup wait-to-connect
|
|
dup pending-init-error
|
|
] [
|
|
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 ;
|
|
|
|
: <accept-task> ( port continuation -- task )
|
|
accept-task <input-task> ;
|
|
|
|
: 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>
|
|
] 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 -- )
|
|
[ <accept-task> add-io-task ] with-port-continuation drop ;
|
|
|
|
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
|
|
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 ;
|
|
|
|
M: unix-io (accept) ( server -- client-in client-out )
|
|
#! 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 ;
|
|
|
|
! Datagram sockets - UDP and Unix domain
|
|
M: unix-io <datagram>
|
|
[ SOCK_DGRAM server-fd ] keep <datagram-port> ;
|
|
|
|
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 ;
|
|
|
|
: <receive-task> ( stream continuation -- task )
|
|
receive-task <input-task> ;
|
|
|
|
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 -- )
|
|
[ <receive-task> add-io-task ] with-port-continuation drop ;
|
|
|
|
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 ;
|
|
|
|
: <send-task> ( packet sockaddr len stream continuation -- task )
|
|
send-task <output-task> [
|
|
{
|
|
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 -- )
|
|
[ <send-task> add-io-task ] with-port-continuation
|
|
2drop 2drop ;
|
|
|
|
M: unix-io send ( packet addrspec datagram -- )
|
|
3dup check-datagram-send
|
|
[ >r make-sockaddr/size r> wait-send ] keep
|
|
pending-error ;
|
|
|
|
M: local protocol-family drop PF_UNIX ;
|
|
|
|
M: local sockaddr-type drop "sockaddr-un" c-type ;
|
|
|
|
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 ;
|
|
|
|
M: local parse-sockaddr
|
|
drop
|
|
sockaddr-un-path alien>char-string <local> ;
|