1 ! Copyright (C) 2007, 2009 Slava Pestov, Doug Coleman.
\r
2 ! See http://factorcode.org/license.txt for BSD license.
\r
3 USING: accessors alien alien.c-types alien.data classes.struct
\r
4 combinators destructors io.backend io.files.windows io.ports
\r
5 io.sockets io.sockets.icmp io.sockets.private kernel libc math
\r
6 sequences system windows.handles windows.kernel32 windows.types
\r
7 windows.winsock locals ;
\r
8 FROM: namespaces => get ;
\r
9 IN: io.sockets.windows
\r
11 : set-socket-option ( handle level opt -- )
\r
12 [ handle>> ] 2dip 1 int <ref> dup byte-length setsockopt socket-error ;
\r
14 M: windows addrinfo-error ( n -- )
\r
15 winsock-return-check ;
\r
17 M: windows sockaddr-of-family ( alien af -- addrspec )
\r
19 { AF_INET [ sockaddr-in memory>struct ] }
\r
20 { AF_INET6 [ sockaddr-in6 memory>struct ] }
\r
24 M: windows addrspec-of-family ( af -- addrspec )
\r
26 { AF_INET [ T{ ipv4 } ] }
\r
27 { AF_INET6 [ T{ ipv6 } ] }
\r
31 HOOK: WSASocket-flags io-backend ( -- DWORD )
\r
33 TUPLE: win32-socket < win32-file ;
\r
35 : <win32-socket> ( handle -- win32-socket )
\r
36 win32-socket new-win32-handle ;
\r
38 M: win32-socket dispose* ( stream -- )
\r
39 handle>> closesocket socket-error* ;
\r
41 : unspecific-sockaddr/size ( addrspec -- sockaddr len )
\r
42 [ empty-sockaddr/size ] [ protocol-family ] bi pick family<< ;
\r
44 : opened-socket ( handle -- win32-socket )
\r
45 <win32-socket> |dispose add-completion ;
\r
47 : open-socket ( addrspec type -- win32-socket )
\r
48 [ drop protocol-family ] [ swap protocol ] 2bi
\r
49 f 0 WSASocket-flags WSASocket
\r
53 M: object (get-local-address) ( socket addrspec -- sockaddr )
\r
54 [ handle>> ] dip empty-sockaddr/size int <ref>
\r
55 [ getsockname socket-error ] 2keep drop ;
\r
57 M: object (get-remote-address) ( socket addrspec -- sockaddr )
\r
58 [ handle>> ] dip empty-sockaddr/size int <ref>
\r
59 [ getpeername socket-error ] 2keep drop ;
\r
61 : bind-socket ( win32-socket sockaddr len -- )
\r
62 [ handle>> ] 2dip bind socket-error ;
\r
64 M: object ((client)) ( addrspec -- handle )
\r
65 [ SOCK_STREAM open-socket ] keep
\r
67 bind-local-address get
\r
68 [ nip make-sockaddr/size ]
\r
69 [ unspecific-sockaddr/size ] if* bind-socket
\r
72 : server-socket ( addrspec type -- fd )
\r
73 [ open-socket ] [ drop ] 2bi
\r
74 [ make-sockaddr/size bind-socket ] [ drop ] 2bi ;
\r
76 ! http://support.microsoft.com/kb/127144
\r
77 ! NOTE: Possibly tweak this because of SYN flood attacks
\r
78 : listen-backlog ( -- n ) 0x7fffffff ; inline
\r
80 M: object (server) ( addrspec -- handle )
\r
82 SOCK_STREAM server-socket
\r
83 dup handle>> listen-backlog listen winsock-return-check
\r
84 ] with-destructors ;
\r
86 M: windows (datagram) ( addrspec -- handle )
\r
87 [ SOCK_DGRAM server-socket ] with-destructors ;
\r
89 M: windows (raw) ( addrspec -- handle )
\r
90 [ SOCK_RAW server-socket ] with-destructors ;
\r
92 M: windows (broadcast) ( datagram -- datagram )
\r
93 dup handle>> SOL_SOCKET SO_BROADCAST set-socket-option ;
\r
95 : malloc-int ( n -- alien )
\r
96 int <ref> malloc-byte-array ; inline
\r
98 M: windows WSASocket-flags ( -- DWORD )
\r
99 WSA_FLAG_OVERLAPPED ; inline
\r
101 : get-ConnectEx-ptr ( socket -- void* )
\r
102 SIO_GET_EXTENSION_FUNCTION_POINTER
\r
111 WSAIoctl SOCKET_ERROR = [
\r
112 maybe-winsock-exception throw
\r
114 ] with-out-parameters ;
\r
116 TUPLE: ConnectEx-args port
\r
117 s name namelen lpSendBuffer dwSendDataLength
\r
118 lpdwBytesSent lpOverlapped ptr ;
\r
120 : wait-for-socket ( args -- count )
\r
121 [ lpOverlapped>> ] [ port>> ] bi twiddle-thumbs ; inline
\r
123 : <ConnectEx-args> ( sockaddr size -- ConnectEx )
\r
128 0 >>dwSendDataLength
\r
130 (make-overlapped) >>lpOverlapped ; inline
\r
132 : call-ConnectEx ( ConnectEx -- )
\r
138 [ dwSendDataLength>> ]
\r
139 [ lpdwBytesSent>> ]
\r
144 { SOCKET void* int PVOID DWORD LPDWORD void* }
\r
145 stdcall alien-indirect drop
\r
146 winsock-error ; inline
\r
148 M: object establish-connection ( client-out remote -- )
\r
149 make-sockaddr/size <ConnectEx-args>
\r
151 dup port>> handle>> handle>> >>s
\r
152 dup s>> get-ConnectEx-ptr >>ptr
\r
154 wait-for-socket drop ;
\r
156 TUPLE: AcceptEx-args port
\r
157 sListenSocket sAcceptSocket lpOutputBuffer dwReceiveDataLength
\r
158 dwLocalAddressLength dwRemoteAddressLength lpdwBytesReceived lpOverlapped ;
\r
160 : init-accept-buffer ( addr AcceptEx -- )
\r
161 swap sockaddr-size 16 +
\r
162 [ >>dwLocalAddressLength ] [ >>dwRemoteAddressLength ] bi
\r
163 dup dwLocalAddressLength>> 2 * malloc &free >>lpOutputBuffer
\r
166 : <AcceptEx-args> ( server addr -- AcceptEx )
\r
168 2dup init-accept-buffer
\r
169 swap SOCK_STREAM open-socket |dispose handle>> >>sAcceptSocket
\r
170 over handle>> handle>> >>sListenSocket
\r
172 0 >>dwReceiveDataLength
\r
173 f >>lpdwBytesReceived
\r
174 (make-overlapped) >>lpOverlapped ; inline
\r
176 ! AcceptEx return value is useless
\r
177 : call-AcceptEx ( AcceptEx -- )
\r
179 [ sListenSocket>> ]
\r
180 [ sAcceptSocket>> ]
\r
181 [ lpOutputBuffer>> ]
\r
182 [ dwReceiveDataLength>> ]
\r
183 [ dwLocalAddressLength>> ]
\r
184 [ dwRemoteAddressLength>> ]
\r
185 [ lpdwBytesReceived>> ]
\r
187 } cleave AcceptEx drop winsock-error ; inline
\r
189 : (extract-remote-address) ( lpOutputBuffer dwReceiveDataLength dwLocalAddressLength dwRemoteAddressLength -- sockaddr )
\r
190 f void* <ref> 0 int <ref> f void* <ref>
\r
191 [ 0 int <ref> GetAcceptExSockaddrs ] keep void* deref ;
\r
193 : extract-remote-address ( AcceptEx -- sockaddr )
\r
196 [ lpOutputBuffer>> ]
\r
197 [ dwReceiveDataLength>> ]
\r
198 [ dwLocalAddressLength>> ]
\r
199 [ dwRemoteAddressLength>> ]
\r
201 (extract-remote-address)
\r
202 ] [ port>> addr>> protocol-family ] bi
\r
203 sockaddr-of-family ; inline
\r
205 M: object (accept) ( server addr -- handle sockaddr )
\r
210 [ wait-for-socket drop ]
\r
211 [ sAcceptSocket>> <win32-socket> ]
\r
212 [ extract-remote-address ]
\r
214 ] with-destructors ;
\r
216 TUPLE: WSARecvFrom-args port
\r
217 s lpBuffers dwBufferCount lpNumberOfBytesRecvd
\r
218 lpFlags lpFrom lpFromLen lpOverlapped lpCompletionRoutine ;
\r
220 :: make-receive-buffer ( n buf -- buf' WSABUF )
\r
221 buf >c-ptr pinned-alien?
\r
222 [ buf ] [ n malloc &free [ buf n memcpy ] keep ] if :> buf'
\r
224 WSABUF malloc-struct &free
\r
226 buf' >>buf ; inline
\r
228 :: <WSARecvFrom-args> ( n buf datagram -- buf buf' WSARecvFrom )
\r
229 n buf make-receive-buffer :> ( buf' wsaBuf )
\r
231 WSARecvFrom-args new
\r
233 datagram handle>> handle>> >>s
\r
234 datagram addr>> sockaddr-size
\r
235 [ malloc &free >>lpFrom ]
\r
236 [ malloc-int &free >>lpFromLen ] bi
\r
239 0 malloc-int &free >>lpFlags
\r
240 0 malloc-int &free >>lpNumberOfBytesRecvd
\r
241 (make-overlapped) >>lpOverlapped ; inline
\r
243 : call-WSARecvFrom ( WSARecvFrom -- )
\r
247 [ dwBufferCount>> ]
\r
248 [ lpNumberOfBytesRecvd>> ]
\r
253 [ lpCompletionRoutine>> ]
\r
254 } cleave WSARecvFrom socket-error* ; inline
\r
256 :: finalize-buf ( buf buf' count -- )
\r
257 buf buf' eq? [ buf buf' count memcpy ] unless ; inline
\r
259 :: parse-WSARecvFrom ( buf buf' count wsaRecvFrom -- count sockaddr )
\r
260 buf buf' count finalize-buf
\r
262 [ port>> addr>> empty-sockaddr dup ]
\r
264 [ lpFromLen>> int deref ]
\r
265 tri memcpy ; inline
\r
267 M: windows (receive-unsafe) ( n buf datagram -- count addrspec )
\r
270 [ call-WSARecvFrom ]
\r
271 [ wait-for-socket ]
\r
272 [ parse-WSARecvFrom ]
\r
274 ] with-destructors ;
\r
276 TUPLE: WSASendTo-args port
\r
277 s lpBuffers dwBufferCount lpNumberOfBytesSent
\r
278 dwFlags lpTo iToLen lpOverlapped lpCompletionRoutine ;
\r
280 : make-send-buffer ( packet -- WSABUF )
\r
281 [ WSABUF malloc-struct &free ] dip
\r
282 [ malloc-byte-array &free >>buf ]
\r
283 [ length >>len ] bi ; inline
\r
285 : <WSASendTo-args> ( packet addrspec datagram -- WSASendTo )
\r
288 dup port>> handle>> handle>> >>s
\r
289 swap make-sockaddr/size
\r
290 [ malloc-byte-array &free ] dip
\r
291 [ >>lpTo ] [ >>iToLen ] bi*
\r
292 swap make-send-buffer >>lpBuffers
\r
295 0 uint <ref> >>lpNumberOfBytesSent
\r
296 (make-overlapped) >>lpOverlapped ; inline
\r
298 : call-WSASendTo ( WSASendTo -- )
\r
302 [ dwBufferCount>> ]
\r
303 [ lpNumberOfBytesSent>> ]
\r
308 [ lpCompletionRoutine>> ]
\r
309 } cleave WSASendTo socket-error* ; inline
\r
311 M: windows (send) ( packet addrspec datagram -- )
\r
315 [ wait-for-socket drop ]
\r
317 ] with-destructors ;
\r