1 /* Async WINSOCK DNS services
3 * Copyright (C) 1993,1994,1996,1997 John Brezak, Erik Bos, Alex Korobka.
4 * Copyright (C) 1999 Marcus Meissner
5 * Copyright (C) 2009 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * NOTE: If you make any changes to fix a particular app, make sure
22 * they don't break something else like Netscape or telnet and ftp
23 * clients and servers (www.winsite.com got a lot of those).
26 * - Add WSACancel* and correct handle management. (works rather well for
28 * - Verify & Check all calls for correctness
29 * (currently only WSAGetHostByName*, WSAGetServByPort* calls)
30 * - Check error returns.
31 * - mirc/mirc32 Finger @linux.kernel.org sometimes fails in threaded mode.
33 * - This implementation did ignore the "NOTE:" section above (since the
34 * whole stuff did not work anyway to other changes).
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(winsock
);
50 struct async_query_header
52 LPARAM (*func
)( struct async_query_header
*query
);
60 struct async_query_gethostbyname
62 struct async_query_header query
;
66 struct async_query_gethostbyaddr
68 struct async_query_header query
;
74 struct async_query_getprotobyname
76 struct async_query_header query
;
80 struct async_query_getprotobynumber
82 struct async_query_header query
;
86 struct async_query_getservbyname
88 struct async_query_header query
;
93 struct async_query_getservbyport
95 struct async_query_header query
;
101 /* ----------------------------------- helper functions - */
103 static int list_size(char** l
, int item_size
)
108 j
+= (item_size
) ? item_size
: strlen(l
[i
]) + 1;
109 j
+= (i
+ 1) * sizeof(char*); }
113 static int list_dup(char** l_src
, char* ref
, int item_size
)
116 char** l_to
= (char**)ref
;
119 for(j
=0;l_src
[j
];j
++) ;
120 p
+= (j
+ 1) * sizeof(char*);
123 k
= ( item_size
) ? item_size
: strlen(l_src
[i
]) + 1;
124 memcpy(p
, l_src
[i
], k
); p
+= k
; }
131 static LPARAM
copy_he(void *base
, int size
, const struct hostent
*he
)
135 struct hostent
*to
= base
;
137 if (!he
) return MAKELPARAM( 0, GetLastError() );
139 needed
= sizeof(struct hostent
) + strlen(he
->h_name
) + 1 +
140 list_size(he
->h_aliases
, 0) +
141 list_size(he
->h_addr_list
, he
->h_length
);
142 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
144 to
->h_addrtype
= he
->h_addrtype
;
145 to
->h_length
= he
->h_length
;
146 p
= (char *)(to
+ 1);
148 strcpy(p
, he
->h_name
); p
+= strlen(p
) + 1;
149 to
->h_aliases
= (char **)p
;
150 p
+= list_dup(he
->h_aliases
, p
, 0);
151 to
->h_addr_list
= (char **)p
;
152 list_dup(he
->h_addr_list
, p
, he
->h_length
);
153 return MAKELPARAM( needed
, 0 );
156 static LPARAM
async_gethostbyname( struct async_query_header
*query
)
158 struct async_query_gethostbyname
*aq
= CONTAINING_RECORD( query
, struct async_query_gethostbyname
, query
);
159 struct hostent
*he
= gethostbyname( aq
->host_name
);
161 return copy_he( query
->sbuf
, query
->sbuflen
, he
);
164 static LPARAM
async_gethostbyaddr( struct async_query_header
*query
)
166 struct async_query_gethostbyaddr
*aq
= CONTAINING_RECORD( query
, struct async_query_gethostbyaddr
, query
);
167 struct hostent
*he
= gethostbyaddr( aq
->host_addr
, aq
->host_len
, aq
->host_type
);
169 return copy_he( query
->sbuf
, query
->sbuflen
, he
);
174 static LPARAM
copy_pe( void *base
, int size
, const struct protoent
*pe
)
178 struct protoent
*to
= base
;
180 if (!pe
) return MAKELPARAM( 0, GetLastError() );
182 needed
= sizeof(struct protoent
) + strlen( pe
->p_name
) + 1 + list_size( pe
->p_aliases
, 0 );
183 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
185 to
->p_proto
= pe
->p_proto
;
186 p
= (char *)(to
+ 1);
188 strcpy(p
, pe
->p_name
); p
+= strlen(p
) + 1;
189 to
->p_aliases
= (char **)p
;
190 list_dup(pe
->p_aliases
, p
, 0);
191 return MAKELPARAM( needed
, 0 );
194 static LPARAM
async_getprotobyname( struct async_query_header
*query
)
196 struct async_query_getprotobyname
*aq
= CONTAINING_RECORD( query
, struct async_query_getprotobyname
, query
);
197 struct protoent
*pe
= getprotobyname( aq
->proto_name
);
199 return copy_pe( query
->sbuf
, query
->sbuflen
, pe
);
202 static LPARAM
async_getprotobynumber( struct async_query_header
*query
)
204 struct async_query_getprotobynumber
*aq
= CONTAINING_RECORD( query
, struct async_query_getprotobynumber
, query
);
205 struct protoent
*pe
= getprotobynumber( aq
->proto_number
);
207 return copy_pe( query
->sbuf
, query
->sbuflen
, pe
);
212 static LPARAM
copy_se( void *base
, int size
, const struct servent
*se
)
216 struct servent
*to
= base
;
218 if (!se
) return MAKELPARAM( 0, GetLastError() );
220 needed
= sizeof(struct servent
) + strlen( se
->s_proto
) + strlen( se
->s_name
) + 2 + list_size( se
->s_aliases
, 0 );
221 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
223 to
->s_port
= se
->s_port
;
224 p
= (char *)(to
+ 1);
226 strcpy(p
, se
->s_name
); p
+= strlen(p
) + 1;
228 strcpy(p
, se
->s_proto
); p
+= strlen(p
) + 1;
229 to
->s_aliases
= (char **)p
;
230 list_dup(se
->s_aliases
, p
, 0);
231 return MAKELPARAM( needed
, 0 );
234 static LPARAM
async_getservbyname( struct async_query_header
*query
)
236 struct async_query_getservbyname
*aq
= CONTAINING_RECORD( query
, struct async_query_getservbyname
, query
);
237 struct servent
*se
= getservbyname( aq
->serv_name
, aq
->serv_proto
);
239 return copy_se( query
->sbuf
, query
->sbuflen
, se
);
242 static LPARAM
async_getservbyport( struct async_query_header
*query
)
244 struct async_query_getservbyport
*aq
= CONTAINING_RECORD( query
, struct async_query_getservbyport
, query
);
245 struct servent
*se
= getservbyport( aq
->serv_port
, aq
->serv_proto
);
247 return copy_se( query
->sbuf
, query
->sbuflen
, se
);
251 static void WINAPI
async_worker( TP_CALLBACK_INSTANCE
*instance
, void *context
)
253 struct async_query_header
*query
= context
;
254 LPARAM lparam
= query
->func( query
);
255 PostMessageW( query
->hWnd
, query
->uMsg
, (WPARAM
)query
->handle
, lparam
);
256 HeapFree( GetProcessHeap(), 0, query
);
260 /****************************************************************************
261 * The main async help function.
263 * It either starts a thread or just calls the function directly for platforms
264 * with no thread support. This relies on the fact that PostMessage() does
265 * not actually call the windowproc before the function returns.
267 static HANDLE
run_query( HWND hWnd
, UINT uMsg
, LPARAM (*func
)(struct async_query_header
*),
268 struct async_query_header
*query
, void *sbuf
, INT sbuflen
)
270 static LONG next_handle
= 0xdead;
273 handle
= LOWORD( InterlockedIncrement( &next_handle
));
274 while (!handle
); /* avoid handle 0 */
279 query
->handle
= UlongToHandle( handle
);
281 query
->sbuflen
= sbuflen
;
283 if (!TrySubmitThreadpoolCallback( async_worker
, query
, NULL
))
285 SetLastError( WSAEWOULDBLOCK
);
286 HeapFree( GetProcessHeap(), 0, query
);
289 return UlongToHandle( handle
);
293 /***********************************************************************
294 * WSAAsyncGetHostByAddr (WS2_32.102)
296 HANDLE WINAPI
WSAAsyncGetHostByAddr(HWND hWnd
, UINT uMsg
, LPCSTR addr
,
297 INT len
, INT type
, LPSTR sbuf
, INT buflen
)
299 struct async_query_gethostbyaddr
*aq
;
301 TRACE("hwnd %p, msg %04x, addr %p[%i]\n", hWnd
, uMsg
, addr
, len
);
303 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) + len
)))
305 SetLastError( WSAEWOULDBLOCK
);
308 aq
->host_addr
= (char *)(aq
+ 1);
310 aq
->host_type
= type
;
311 memcpy( aq
->host_addr
, addr
, len
);
312 return run_query( hWnd
, uMsg
, async_gethostbyaddr
, &aq
->query
, sbuf
, buflen
);
315 /***********************************************************************
316 * WSAAsyncGetHostByName (WS2_32.103)
318 HANDLE WINAPI
WSAAsyncGetHostByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
319 LPSTR sbuf
, INT buflen
)
321 struct async_query_gethostbyname
*aq
;
322 unsigned int len
= strlen(name
) + 1;
324 TRACE("hwnd %p, msg %04x, host %s, buffer %i\n", hWnd
, uMsg
, debugstr_a(name
), buflen
);
326 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) + len
)))
328 SetLastError( WSAEWOULDBLOCK
);
331 aq
->host_name
= (char *)(aq
+ 1);
332 strcpy( aq
->host_name
, name
);
333 return run_query( hWnd
, uMsg
, async_gethostbyname
, &aq
->query
, sbuf
, buflen
);
336 /***********************************************************************
337 * WSAAsyncGetProtoByName (WS2_32.105)
339 HANDLE WINAPI
WSAAsyncGetProtoByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
340 LPSTR sbuf
, INT buflen
)
342 struct async_query_getprotobyname
*aq
;
343 unsigned int len
= strlen(name
) + 1;
345 TRACE("hwnd %p, msg %04x, proto %s, buffer %i\n", hWnd
, uMsg
, debugstr_a(name
), buflen
);
347 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) + len
)))
349 SetLastError( WSAEWOULDBLOCK
);
352 aq
->proto_name
= (char *)(aq
+ 1);
353 strcpy( aq
->proto_name
, name
);
354 return run_query( hWnd
, uMsg
, async_getprotobyname
, &aq
->query
, sbuf
, buflen
);
358 /***********************************************************************
359 * WSAAsyncGetProtoByNumber (WS2_32.104)
361 HANDLE WINAPI
WSAAsyncGetProtoByNumber(HWND hWnd
, UINT uMsg
, INT number
,
362 LPSTR sbuf
, INT buflen
)
364 struct async_query_getprotobynumber
*aq
;
366 TRACE("hwnd %p, msg %04x, num %i\n", hWnd
, uMsg
, number
);
368 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) )))
370 SetLastError( WSAEWOULDBLOCK
);
373 aq
->proto_number
= number
;
374 return run_query( hWnd
, uMsg
, async_getprotobynumber
, &aq
->query
, sbuf
, buflen
);
377 /***********************************************************************
378 * WSAAsyncGetServByName (WS2_32.107)
380 HANDLE WINAPI
WSAAsyncGetServByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
381 LPCSTR proto
, LPSTR sbuf
, INT buflen
)
383 struct async_query_getservbyname
*aq
;
384 unsigned int len1
= strlen(name
) + 1;
385 unsigned int len2
= proto
? strlen(proto
) + 1 : 0;
387 TRACE("hwnd %p, msg %04x, name %s, proto %s\n", hWnd
, uMsg
, debugstr_a(name
), debugstr_a(proto
));
389 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) + len1
+ len2
)))
391 SetLastError( WSAEWOULDBLOCK
);
395 aq
->serv_name
= (char *)(aq
+ 1);
396 strcpy( aq
->serv_name
, name
);
400 aq
->serv_proto
= aq
->serv_name
+ len1
;
401 strcpy( aq
->serv_proto
, proto
);
404 aq
->serv_proto
= NULL
;
406 return run_query( hWnd
, uMsg
, async_getservbyname
, &aq
->query
, sbuf
, buflen
);
409 /***********************************************************************
410 * WSAAsyncGetServByPort (WS2_32.106)
412 HANDLE WINAPI
WSAAsyncGetServByPort(HWND hWnd
, UINT uMsg
, INT port
,
413 LPCSTR proto
, LPSTR sbuf
, INT buflen
)
415 struct async_query_getservbyport
*aq
;
416 unsigned int len
= proto
? strlen(proto
) + 1 : 0;
418 TRACE("hwnd %p, msg %04x, port %i, proto %s\n", hWnd
, uMsg
, port
, debugstr_a(proto
));
420 if (!(aq
= HeapAlloc( GetProcessHeap(), 0, sizeof(*aq
) + len
)))
422 SetLastError( WSAEWOULDBLOCK
);
428 aq
->serv_proto
= (char *)(aq
+ 1);
429 strcpy( aq
->serv_proto
, proto
);
432 aq
->serv_proto
= NULL
;
434 aq
->serv_port
= port
;
436 return run_query( hWnd
, uMsg
, async_getservbyport
, &aq
->query
, sbuf
, buflen
);
439 /***********************************************************************
440 * WSACancelAsyncRequest (WS2_32.108)
442 INT WINAPI
WSACancelAsyncRequest(HANDLE hAsyncTaskHandle
)
444 FIXME("(%p),stub\n", hAsyncTaskHandle
);
448 /***********************************************************************
449 * WSApSetPostRoutine (WS2_32.24)
451 INT WINAPI
WSApSetPostRoutine(LPWPUPOSTMESSAGE lpPostRoutine
)
453 FIXME("(%p), stub !\n", lpPostRoutine
);
457 /***********************************************************************
458 * WPUCompleteOverlappedRequest (WS2_32.25)
460 WSAEVENT WINAPI
WPUCompleteOverlappedRequest(SOCKET s
, LPWSAOVERLAPPED overlapped
,
461 DWORD error
, DWORD transferred
, LPINT errcode
)
463 FIXME("(0x%08lx,%p,0x%08x,0x%08x,%p), stub !\n", s
, overlapped
, error
, transferred
, errcode
);
466 *errcode
= WSAEINVAL
;