1 ! Copyright (C) 2007, 2009 Slava Pestov, Doug Coleman.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors alien alien.c-types alien.data classes.struct
4 combinators destructors io.backend io.files.windows io.ports
5 io.sockets io.sockets.icmp io.sockets.private kernel libc locals
6 math sequences system windows.errors windows.handles
7 windows.kernel32 windows.types windows.winsock ;
8 FROM: namespaces => get ;
11 : set-socket-option ( handle level opt -- )
12 [ handle>> ] 2dip 1 int <ref> dup byte-length setsockopt socket-error ;
14 : set-ioctl-socket ( handle cmd arg -- )
15 [ handle>> ] 2dip ulong <ref> ioctlsocket socket-error ;
17 M: windows addrinfo-error-string ( n -- string )
18 n>win32-error-string ;
20 M: windows sockaddr-of-family ( alien af -- addrspec )
22 { AF_INET [ sockaddr-in memory>struct ] }
23 { AF_INET6 [ sockaddr-in6 memory>struct ] }
27 M: windows addrspec-of-family ( af -- addrspec )
29 { AF_INET [ T{ ipv4 } ] }
30 { AF_INET6 [ T{ ipv6 } ] }
34 HOOK: WSASocket-flags io-backend ( -- DWORD )
36 TUPLE: win32-socket < win32-file ;
38 : <win32-socket> ( handle -- win32-socket )
39 win32-socket new-win32-handle ;
41 M: win32-socket dispose* ( stream -- )
42 handle>> closesocket socket-error* ;
44 : unspecific-sockaddr/size ( addrspec -- sockaddr len )
45 [ empty-sockaddr/size ] [ protocol-family ] bi pick family<< ;
47 : opened-socket ( handle -- win32-socket )
48 <win32-socket> |dispose add-completion ;
50 : open-socket ( addrspec type -- win32-socket )
51 [ drop protocol-family ] [ swap protocol ] 2bi
52 f 0 WSASocket-flags WSASocket
56 M: object (get-local-address) ( socket addrspec -- sockaddr )
57 [ handle>> ] dip empty-sockaddr/size int <ref>
58 [ getsockname socket-error ] 2keep drop ;
60 M: object (get-remote-address) ( socket addrspec -- sockaddr )
61 [ handle>> ] dip empty-sockaddr/size int <ref>
62 [ getpeername socket-error ] 2keep drop ;
64 : bind-socket ( win32-socket sockaddr len -- )
65 [ handle>> ] 2dip bind socket-error ;
67 M: object ((client)) ( addrspec -- handle )
68 [ SOCK_STREAM open-socket ] keep
70 bind-local-address get
71 [ nip make-sockaddr/size ]
72 [ unspecific-sockaddr/size ] if* bind-socket
75 : server-socket ( addrspec type -- fd )
76 [ open-socket ] [ drop ] 2bi
77 [ make-sockaddr/size bind-socket ] [ drop ] 2bi ;
79 ! http://support.microsoft.com/kb/127144
80 ! NOTE: Possibly tweak this because of SYN flood attacks
81 : listen-backlog ( -- n ) 0x7fffffff ; inline
83 M: object (server) ( addrspec -- handle )
85 SOCK_STREAM server-socket
86 dup handle>> listen-backlog listen winsock-return-check
89 M: windows (datagram) ( addrspec -- handle )
90 [ SOCK_DGRAM server-socket ] with-destructors ;
92 M: windows (raw) ( addrspec -- handle )
93 [ SOCK_RAW server-socket ] with-destructors ;
95 M: windows (broadcast) ( datagram -- datagram )
96 dup handle>> SOL_SOCKET SO_BROADCAST set-socket-option ;
98 : malloc-int ( n -- alien )
99 int <ref> malloc-byte-array ; inline
101 M: windows WSASocket-flags ( -- DWORD )
102 WSA_FLAG_OVERLAPPED ; inline
104 : get-ConnectEx-ptr ( socket -- void* )
105 SIO_GET_EXTENSION_FUNCTION_POINTER
114 WSAIoctl SOCKET_ERROR = [
115 maybe-winsock-exception throw
117 ] with-out-parameters ;
119 TUPLE: ConnectEx-args port
120 s name namelen lpSendBuffer dwSendDataLength
121 lpdwBytesSent lpOverlapped ptr ;
123 : wait-for-socket ( args -- count )
124 [ lpOverlapped>> ] [ port>> ] bi twiddle-thumbs ; inline
126 : <ConnectEx-args> ( sockaddr size -- ConnectEx )
133 (make-overlapped) >>lpOverlapped ; inline
135 : call-ConnectEx ( ConnectEx -- )
141 [ dwSendDataLength>> ]
147 { SOCKET void* int PVOID DWORD LPDWORD void* }
148 stdcall alien-indirect drop
149 winsock-error ; inline
151 M: object establish-connection ( client-out remote -- )
152 make-sockaddr/size <ConnectEx-args>
154 dup port>> handle>> handle>> >>s
155 dup s>> get-ConnectEx-ptr >>ptr
157 wait-for-socket drop ;
159 TUPLE: AcceptEx-args port
160 sListenSocket sAcceptSocket lpOutputBuffer dwReceiveDataLength
161 dwLocalAddressLength dwRemoteAddressLength lpdwBytesReceived lpOverlapped ;
163 : init-accept-buffer ( addr AcceptEx -- )
164 swap sockaddr-size 16 +
165 [ >>dwLocalAddressLength ] [ >>dwRemoteAddressLength ] bi
166 dup dwLocalAddressLength>> 2 * malloc &free >>lpOutputBuffer
169 : <AcceptEx-args> ( server addr -- AcceptEx )
171 2dup init-accept-buffer
172 swap SOCK_STREAM open-socket |dispose handle>> >>sAcceptSocket
173 over handle>> handle>> >>sListenSocket
175 0 >>dwReceiveDataLength
176 f >>lpdwBytesReceived
177 (make-overlapped) >>lpOverlapped ; inline
179 ! AcceptEx return value is useless
180 : call-AcceptEx ( AcceptEx -- )
185 [ dwReceiveDataLength>> ]
186 [ dwLocalAddressLength>> ]
187 [ dwRemoteAddressLength>> ]
188 [ lpdwBytesReceived>> ]
190 } cleave AcceptEx drop winsock-error ; inline
192 : (extract-remote-address) ( lpOutputBuffer dwReceiveDataLength dwLocalAddressLength dwRemoteAddressLength -- sockaddr )
193 f void* <ref> 0 int <ref> f void* <ref>
194 [ 0 int <ref> GetAcceptExSockaddrs ] keep void* deref ;
196 : extract-remote-address ( AcceptEx -- sockaddr )
200 [ dwReceiveDataLength>> ]
201 [ dwLocalAddressLength>> ]
202 [ dwRemoteAddressLength>> ]
204 (extract-remote-address)
205 ] [ port>> addr>> protocol-family ] bi
206 sockaddr-of-family ; inline
208 M: object (accept) ( server addr -- handle sockaddr )
213 [ wait-for-socket drop ]
214 [ sAcceptSocket>> <win32-socket> ]
215 [ extract-remote-address ]
219 TUPLE: WSARecvFrom-args port
220 s lpBuffers dwBufferCount lpNumberOfBytesRecvd
221 lpFlags lpFrom lpFromLen lpOverlapped lpCompletionRoutine ;
223 :: make-receive-buffer ( n buf -- buf' WSABUF )
224 buf >c-ptr pinned-alien?
225 [ buf ] [ n malloc &free [ buf n memcpy ] keep ] if :> buf'
227 WSABUF malloc-struct &free
231 :: <WSARecvFrom-args> ( n buf datagram -- buf buf' WSARecvFrom )
232 n buf make-receive-buffer :> ( buf' wsaBuf )
236 datagram handle>> handle>> >>s
237 datagram addr>> sockaddr-size
238 [ malloc &free >>lpFrom ]
239 [ malloc-int &free >>lpFromLen ] bi
242 0 malloc-int &free >>lpFlags
243 0 malloc-int &free >>lpNumberOfBytesRecvd
244 (make-overlapped) >>lpOverlapped ; inline
246 : call-WSARecvFrom ( WSARecvFrom -- )
251 [ lpNumberOfBytesRecvd>> ]
256 [ lpCompletionRoutine>> ]
257 } cleave WSARecvFrom socket-error* ; inline
259 :: finalize-buf ( buf buf' count -- )
260 buf buf' eq? [ buf buf' count memcpy ] unless ; inline
262 :: parse-WSARecvFrom ( buf buf' count wsaRecvFrom -- count sockaddr )
263 buf buf' count finalize-buf
265 [ port>> addr>> empty-sockaddr dup ]
267 [ lpFromLen>> int deref ]
270 M: windows (receive-unsafe) ( n buf datagram -- count addrspec )
275 [ parse-WSARecvFrom ]
279 TUPLE: WSASendTo-args port
280 s lpBuffers dwBufferCount lpNumberOfBytesSent
281 dwFlags lpTo iToLen lpOverlapped lpCompletionRoutine ;
283 : make-send-buffer ( packet -- WSABUF )
284 [ WSABUF malloc-struct &free ] dip
285 [ malloc-byte-array &free >>buf ]
286 [ length >>len ] bi ; inline
288 : <WSASendTo-args> ( packet addrspec datagram -- WSASendTo )
291 dup port>> handle>> handle>> >>s
292 swap make-sockaddr/size
293 [ malloc-byte-array &free ] dip
294 [ >>lpTo ] [ >>iToLen ] bi*
295 swap make-send-buffer >>lpBuffers
298 0 uint <ref> >>lpNumberOfBytesSent
299 (make-overlapped) >>lpOverlapped ; inline
301 : call-WSASendTo ( WSASendTo -- )
306 [ lpNumberOfBytesSent>> ]
311 [ lpCompletionRoutine>> ]
312 } cleave WSASendTo socket-error* ; inline
314 M: windows (send) ( packet addrspec datagram -- )
318 [ wait-for-socket drop ]