! Copyright (C) 2007, 2009 Slava Pestov, Doug Coleman. ! See http://factorcode.org/license.txt for BSD license. USING: accessors alien alien.c-types alien.data classes.struct combinators destructors io.backend io.files.windows io.ports io.sockets io.sockets.icmp io.sockets.private kernel libc math sequences system windows.handles windows.kernel32 windows.types windows.winsock ; FROM: namespaces => get ; IN: io.sockets.windows M: windows addrinfo-error ( n -- ) winsock-return-check ; M: windows sockaddr-of-family ( alien af -- addrspec ) { { AF_INET [ sockaddr-in memory>struct ] } { AF_INET6 [ sockaddr-in6 memory>struct ] } [ 2drop f ] } case ; M: windows addrspec-of-family ( af -- addrspec ) { { AF_INET [ T{ ipv4 } ] } { AF_INET6 [ T{ ipv6 } ] } [ drop f ] } case ; HOOK: WSASocket-flags io-backend ( -- DWORD ) TUPLE: win32-socket < win32-file ; : ( handle -- win32-socket ) win32-socket new-win32-handle ; M: win32-socket dispose* ( stream -- ) handle>> closesocket socket-error* ; : unspecific-sockaddr/size ( addrspec -- sockaddr len ) [ empty-sockaddr/size ] [ protocol-family ] bi pick family<< ; : opened-socket ( handle -- win32-socket ) |dispose add-completion ; : open-socket ( addrspec type -- win32-socket ) [ drop protocol-family ] [ swap protocol ] 2bi f 0 WSASocket-flags WSASocket dup socket-error opened-socket ; M: object (get-local-address) ( socket addrspec -- sockaddr ) [ handle>> ] dip empty-sockaddr/size [ getsockname socket-error ] 2keep drop ; M: object (get-remote-address) ( socket addrspec -- sockaddr ) [ handle>> ] dip empty-sockaddr/size [ getpeername socket-error ] 2keep drop ; : bind-socket ( win32-socket sockaddr len -- ) [ handle>> ] 2dip bind socket-error ; M: object ((client)) ( addrspec -- handle ) [ SOCK_STREAM open-socket ] keep [ bind-local-address get [ nip make-sockaddr/size ] [ unspecific-sockaddr/size ] if* bind-socket ] [ drop ] 2bi ; : server-socket ( addrspec type -- fd ) [ open-socket ] [ drop ] 2bi [ make-sockaddr/size bind-socket ] [ drop ] 2bi ; ! http://support.microsoft.com/kb/127144 ! NOTE: Possibly tweak this because of SYN flood attacks : listen-backlog ( -- n ) HEX: 7fffffff ; inline M: object (server) ( addrspec -- handle ) [ SOCK_STREAM server-socket dup handle>> listen-backlog listen winsock-return-check ] with-destructors ; M: windows (datagram) ( addrspec -- handle ) [ SOCK_DGRAM server-socket ] with-destructors ; M: windows (raw) ( addrspec -- handle ) [ SOCK_RAW server-socket ] with-destructors ; : malloc-int ( n -- alien ) malloc-byte-array ; inline M: winnt WSASocket-flags ( -- DWORD ) WSA_FLAG_OVERLAPPED ; : get-ConnectEx-ptr ( socket -- void* ) SIO_GET_EXTENSION_FUNCTION_POINTER WSAID_CONNECTEX GUID heap-size { void* } [ void* heap-size DWORD f f WSAIoctl SOCKET_ERROR = [ maybe-winsock-exception throw ] when ] with-out-parameters ; TUPLE: ConnectEx-args port s name namelen lpSendBuffer dwSendDataLength lpdwBytesSent lpOverlapped ptr ; : wait-for-socket ( args -- n ) [ lpOverlapped>> ] [ port>> ] bi twiddle-thumbs ; inline : ( sockaddr size -- ConnectEx ) ConnectEx-args new swap >>namelen swap >>name f >>lpSendBuffer 0 >>dwSendDataLength f >>lpdwBytesSent (make-overlapped) >>lpOverlapped ; inline : call-ConnectEx ( ConnectEx -- ) { [ s>> ] [ name>> ] [ namelen>> ] [ lpSendBuffer>> ] [ dwSendDataLength>> ] [ lpdwBytesSent>> ] [ lpOverlapped>> ] [ ptr>> ] } cleave int { SOCKET void* int PVOID DWORD LPDWORD void* } stdcall alien-indirect drop winsock-error ; inline M: object establish-connection ( client-out remote -- ) make-sockaddr/size swap >>port dup port>> handle>> handle>> >>s dup s>> get-ConnectEx-ptr >>ptr dup call-ConnectEx wait-for-socket drop ; TUPLE: AcceptEx-args port sListenSocket sAcceptSocket lpOutputBuffer dwReceiveDataLength dwLocalAddressLength dwRemoteAddressLength lpdwBytesReceived lpOverlapped ; : init-accept-buffer ( addr AcceptEx -- ) swap sockaddr-size 16 + [ >>dwLocalAddressLength ] [ >>dwRemoteAddressLength ] bi dup dwLocalAddressLength>> 2 * malloc &free >>lpOutputBuffer drop ; inline : ( server addr -- AcceptEx ) AcceptEx-args new 2dup init-accept-buffer swap SOCK_STREAM open-socket |dispose handle>> >>sAcceptSocket over handle>> handle>> >>sListenSocket swap >>port 0 >>dwReceiveDataLength f >>lpdwBytesReceived (make-overlapped) >>lpOverlapped ; inline ! AcceptEx return value is useless : call-AcceptEx ( AcceptEx -- ) { [ sListenSocket>> ] [ sAcceptSocket>> ] [ lpOutputBuffer>> ] [ dwReceiveDataLength>> ] [ dwLocalAddressLength>> ] [ dwRemoteAddressLength>> ] [ lpdwBytesReceived>> ] [ lpOverlapped>> ] } cleave AcceptEx drop winsock-error ; inline : (extract-remote-address) ( lpOutputBuffer dwReceiveDataLength dwLocalAddressLength dwRemoteAddressLength -- sockaddr ) f 0 f [ 0 GetAcceptExSockaddrs ] keep *void* ; : extract-remote-address ( AcceptEx -- sockaddr ) [ { [ lpOutputBuffer>> ] [ dwReceiveDataLength>> ] [ dwLocalAddressLength>> ] [ dwRemoteAddressLength>> ] } cleave (extract-remote-address) ] [ port>> addr>> protocol-family ] bi sockaddr-of-family ; inline M: object (accept) ( server addr -- handle sockaddr ) [ { [ call-AcceptEx ] [ wait-for-socket drop ] [ sAcceptSocket>> ] [ extract-remote-address ] } cleave ] with-destructors ; TUPLE: WSARecvFrom-args port s lpBuffers dwBufferCount lpNumberOfBytesRecvd lpFlags lpFrom lpFromLen lpOverlapped lpCompletionRoutine ; : make-receive-buffer ( -- WSABUF ) WSABUF malloc-struct &free default-buffer-size get [ >>len ] [ malloc &free >>buf ] bi ; inline : ( datagram -- WSARecvFrom ) WSARecvFrom-args new swap >>port dup port>> handle>> handle>> >>s dup port>> addr>> sockaddr-size [ malloc &free >>lpFrom ] [ malloc-int &free >>lpFromLen ] bi make-receive-buffer >>lpBuffers 1 >>dwBufferCount 0 malloc-int &free >>lpFlags 0 malloc-int &free >>lpNumberOfBytesRecvd (make-overlapped) >>lpOverlapped ; inline : call-WSARecvFrom ( WSARecvFrom -- ) { [ s>> ] [ lpBuffers>> ] [ dwBufferCount>> ] [ lpNumberOfBytesRecvd>> ] [ lpFlags>> ] [ lpFrom>> ] [ lpFromLen>> ] [ lpOverlapped>> ] [ lpCompletionRoutine>> ] } cleave WSARecvFrom socket-error* ; inline : parse-WSARecvFrom ( n WSARecvFrom -- packet sockaddr ) [ lpBuffers>> buf>> swap memory>byte-array ] [ [ port>> addr>> empty-sockaddr dup ] [ lpFrom>> ] [ lpFromLen>> *int ] tri memcpy ] bi ; inline M: winnt (receive) ( datagram -- packet addrspec ) [ [ call-WSARecvFrom ] [ wait-for-socket ] [ parse-WSARecvFrom ] tri ] with-destructors ; TUPLE: WSASendTo-args port s lpBuffers dwBufferCount lpNumberOfBytesSent dwFlags lpTo iToLen lpOverlapped lpCompletionRoutine ; : make-send-buffer ( packet -- WSABUF ) [ WSABUF malloc-struct &free ] dip [ malloc-byte-array &free >>buf ] [ length >>len ] bi ; inline : ( packet addrspec datagram -- WSASendTo ) WSASendTo-args new swap >>port dup port>> handle>> handle>> >>s swap make-sockaddr/size [ malloc-byte-array &free ] dip [ >>lpTo ] [ >>iToLen ] bi* swap make-send-buffer >>lpBuffers 1 >>dwBufferCount 0 >>dwFlags 0 >>lpNumberOfBytesSent (make-overlapped) >>lpOverlapped ; inline : call-WSASendTo ( WSASendTo -- ) { [ s>> ] [ lpBuffers>> ] [ dwBufferCount>> ] [ lpNumberOfBytesSent>> ] [ dwFlags>> ] [ lpTo>> ] [ iToLen>> ] [ lpOverlapped>> ] [ lpCompletionRoutine>> ] } cleave WSASendTo socket-error* ; inline M: winnt (send) ( packet addrspec datagram -- ) [ [ call-WSASendTo ] [ wait-for-socket drop ] bi ] with-destructors ;