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).
37 #include "ws2_32_private.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(winsock
);
42 struct async_query_header
44 LPARAM (*func
)( struct async_query_header
*query
);
52 struct async_query_gethostbyname
54 struct async_query_header query
;
58 struct async_query_gethostbyaddr
60 struct async_query_header query
;
66 struct async_query_getprotobyname
68 struct async_query_header query
;
72 struct async_query_getprotobynumber
74 struct async_query_header query
;
78 struct async_query_getservbyname
80 struct async_query_header query
;
85 struct async_query_getservbyport
87 struct async_query_header query
;
93 /* ----------------------------------- helper functions - */
95 static int list_size(char** l
, int item_size
)
100 j
+= (item_size
) ? item_size
: strlen(l
[i
]) + 1;
101 j
+= (i
+ 1) * sizeof(char*); }
105 static int list_dup(char** l_src
, char* ref
, int item_size
)
108 char** l_to
= (char**)ref
;
111 for(j
=0;l_src
[j
];j
++) ;
112 p
+= (j
+ 1) * sizeof(char*);
115 k
= ( item_size
) ? item_size
: strlen(l_src
[i
]) + 1;
116 memcpy(p
, l_src
[i
], k
); p
+= k
; }
123 static LPARAM
copy_he(void *base
, int size
, const struct hostent
*he
)
127 struct hostent
*to
= base
;
129 if (!he
) return MAKELPARAM( 0, GetLastError() );
131 needed
= sizeof(struct hostent
) + strlen(he
->h_name
) + 1 +
132 list_size(he
->h_aliases
, 0) +
133 list_size(he
->h_addr_list
, he
->h_length
);
134 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
136 to
->h_addrtype
= he
->h_addrtype
;
137 to
->h_length
= he
->h_length
;
138 p
= (char *)(to
+ 1);
140 strcpy(p
, he
->h_name
); p
+= strlen(p
) + 1;
141 to
->h_aliases
= (char **)p
;
142 p
+= list_dup(he
->h_aliases
, p
, 0);
143 to
->h_addr_list
= (char **)p
;
144 list_dup(he
->h_addr_list
, p
, he
->h_length
);
145 return MAKELPARAM( needed
, 0 );
148 static LPARAM
async_gethostbyname( struct async_query_header
*query
)
150 struct async_query_gethostbyname
*aq
= CONTAINING_RECORD( query
, struct async_query_gethostbyname
, query
);
151 struct hostent
*he
= gethostbyname( aq
->host_name
);
153 return copy_he( query
->sbuf
, query
->sbuflen
, he
);
156 static LPARAM
async_gethostbyaddr( struct async_query_header
*query
)
158 struct async_query_gethostbyaddr
*aq
= CONTAINING_RECORD( query
, struct async_query_gethostbyaddr
, query
);
159 struct hostent
*he
= gethostbyaddr( aq
->host_addr
, aq
->host_len
, aq
->host_type
);
161 return copy_he( query
->sbuf
, query
->sbuflen
, he
);
166 static LPARAM
copy_pe( void *base
, int size
, const struct protoent
*pe
)
170 struct protoent
*to
= base
;
172 if (!pe
) return MAKELPARAM( 0, GetLastError() );
174 needed
= sizeof(struct protoent
) + strlen( pe
->p_name
) + 1 + list_size( pe
->p_aliases
, 0 );
175 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
177 to
->p_proto
= pe
->p_proto
;
178 p
= (char *)(to
+ 1);
180 strcpy(p
, pe
->p_name
); p
+= strlen(p
) + 1;
181 to
->p_aliases
= (char **)p
;
182 list_dup(pe
->p_aliases
, p
, 0);
183 return MAKELPARAM( needed
, 0 );
186 static LPARAM
async_getprotobyname( struct async_query_header
*query
)
188 struct async_query_getprotobyname
*aq
= CONTAINING_RECORD( query
, struct async_query_getprotobyname
, query
);
189 struct protoent
*pe
= getprotobyname( aq
->proto_name
);
191 return copy_pe( query
->sbuf
, query
->sbuflen
, pe
);
194 static LPARAM
async_getprotobynumber( struct async_query_header
*query
)
196 struct async_query_getprotobynumber
*aq
= CONTAINING_RECORD( query
, struct async_query_getprotobynumber
, query
);
197 struct protoent
*pe
= getprotobynumber( aq
->proto_number
);
199 return copy_pe( query
->sbuf
, query
->sbuflen
, pe
);
204 static LPARAM
copy_se( void *base
, int size
, const struct servent
*se
)
208 struct servent
*to
= base
;
210 if (!se
) return MAKELPARAM( 0, GetLastError() );
212 needed
= sizeof(struct servent
) + strlen( se
->s_proto
) + strlen( se
->s_name
) + 2 + list_size( se
->s_aliases
, 0 );
213 if (size
< needed
) return MAKELPARAM( needed
, WSAENOBUFS
);
215 to
->s_port
= se
->s_port
;
216 p
= (char *)(to
+ 1);
218 strcpy(p
, se
->s_name
); p
+= strlen(p
) + 1;
220 strcpy(p
, se
->s_proto
); p
+= strlen(p
) + 1;
221 to
->s_aliases
= (char **)p
;
222 list_dup(se
->s_aliases
, p
, 0);
223 return MAKELPARAM( needed
, 0 );
226 static LPARAM
async_getservbyname( struct async_query_header
*query
)
228 struct async_query_getservbyname
*aq
= CONTAINING_RECORD( query
, struct async_query_getservbyname
, query
);
229 struct servent
*se
= getservbyname( aq
->serv_name
, aq
->serv_proto
);
231 return copy_se( query
->sbuf
, query
->sbuflen
, se
);
234 static LPARAM
async_getservbyport( struct async_query_header
*query
)
236 struct async_query_getservbyport
*aq
= CONTAINING_RECORD( query
, struct async_query_getservbyport
, query
);
237 struct servent
*se
= getservbyport( aq
->serv_port
, aq
->serv_proto
);
239 return copy_se( query
->sbuf
, query
->sbuflen
, se
);
243 static void WINAPI
async_worker( TP_CALLBACK_INSTANCE
*instance
, void *context
)
245 struct async_query_header
*query
= context
;
246 LPARAM lparam
= query
->func( query
);
247 PostMessageW( query
->hWnd
, query
->uMsg
, (WPARAM
)query
->handle
, lparam
);
252 /****************************************************************************
253 * The main async help function.
255 * It either starts a thread or just calls the function directly for platforms
256 * with no thread support. This relies on the fact that PostMessage() does
257 * not actually call the windowproc before the function returns.
259 static HANDLE
run_query( HWND hWnd
, UINT uMsg
, LPARAM (*func
)(struct async_query_header
*),
260 struct async_query_header
*query
, void *sbuf
, INT sbuflen
)
262 static LONG next_handle
= 0xdead;
265 handle
= LOWORD( InterlockedIncrement( &next_handle
));
266 while (!handle
); /* avoid handle 0 */
271 query
->handle
= UlongToHandle( handle
);
273 query
->sbuflen
= sbuflen
;
275 if (!TrySubmitThreadpoolCallback( async_worker
, query
, NULL
))
277 SetLastError( WSAEWOULDBLOCK
);
281 return UlongToHandle( handle
);
285 /***********************************************************************
286 * WSAAsyncGetHostByAddr (WS2_32.102)
288 HANDLE WINAPI
WSAAsyncGetHostByAddr(HWND hWnd
, UINT uMsg
, LPCSTR addr
,
289 INT len
, INT type
, LPSTR sbuf
, INT buflen
)
291 struct async_query_gethostbyaddr
*aq
;
293 TRACE("hwnd %p, msg %04x, addr %p[%i]\n", hWnd
, uMsg
, addr
, len
);
295 if (!(aq
= malloc( sizeof(*aq
) + len
)))
297 SetLastError( WSAEWOULDBLOCK
);
300 aq
->host_addr
= (char *)(aq
+ 1);
302 aq
->host_type
= type
;
303 memcpy( aq
->host_addr
, addr
, len
);
304 return run_query( hWnd
, uMsg
, async_gethostbyaddr
, &aq
->query
, sbuf
, buflen
);
307 /***********************************************************************
308 * WSAAsyncGetHostByName (WS2_32.103)
310 HANDLE WINAPI
WSAAsyncGetHostByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
311 LPSTR sbuf
, INT buflen
)
313 struct async_query_gethostbyname
*aq
;
314 unsigned int len
= strlen(name
) + 1;
316 TRACE("hwnd %p, msg %04x, host %s, buffer %i\n", hWnd
, uMsg
, debugstr_a(name
), buflen
);
318 if (!(aq
= malloc( sizeof(*aq
) + len
)))
320 SetLastError( WSAEWOULDBLOCK
);
323 aq
->host_name
= (char *)(aq
+ 1);
324 strcpy( aq
->host_name
, name
);
325 return run_query( hWnd
, uMsg
, async_gethostbyname
, &aq
->query
, sbuf
, buflen
);
328 /***********************************************************************
329 * WSAAsyncGetProtoByName (WS2_32.105)
331 HANDLE WINAPI
WSAAsyncGetProtoByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
332 LPSTR sbuf
, INT buflen
)
334 struct async_query_getprotobyname
*aq
;
335 unsigned int len
= strlen(name
) + 1;
337 TRACE("hwnd %p, msg %04x, proto %s, buffer %i\n", hWnd
, uMsg
, debugstr_a(name
), buflen
);
339 if (!(aq
= malloc( sizeof(*aq
) + len
)))
341 SetLastError( WSAEWOULDBLOCK
);
344 aq
->proto_name
= (char *)(aq
+ 1);
345 strcpy( aq
->proto_name
, name
);
346 return run_query( hWnd
, uMsg
, async_getprotobyname
, &aq
->query
, sbuf
, buflen
);
350 /***********************************************************************
351 * WSAAsyncGetProtoByNumber (WS2_32.104)
353 HANDLE WINAPI
WSAAsyncGetProtoByNumber(HWND hWnd
, UINT uMsg
, INT number
,
354 LPSTR sbuf
, INT buflen
)
356 struct async_query_getprotobynumber
*aq
;
358 TRACE("hwnd %p, msg %04x, num %i\n", hWnd
, uMsg
, number
);
360 if (!(aq
= malloc( sizeof(*aq
) )))
362 SetLastError( WSAEWOULDBLOCK
);
365 aq
->proto_number
= number
;
366 return run_query( hWnd
, uMsg
, async_getprotobynumber
, &aq
->query
, sbuf
, buflen
);
369 /***********************************************************************
370 * WSAAsyncGetServByName (WS2_32.107)
372 HANDLE WINAPI
WSAAsyncGetServByName(HWND hWnd
, UINT uMsg
, LPCSTR name
,
373 LPCSTR proto
, LPSTR sbuf
, INT buflen
)
375 struct async_query_getservbyname
*aq
;
376 unsigned int len1
= strlen(name
) + 1;
377 unsigned int len2
= proto
? strlen(proto
) + 1 : 0;
379 TRACE("hwnd %p, msg %04x, name %s, proto %s\n", hWnd
, uMsg
, debugstr_a(name
), debugstr_a(proto
));
381 if (!(aq
= malloc( sizeof(*aq
) + len1
+ len2
)))
383 SetLastError( WSAEWOULDBLOCK
);
387 aq
->serv_name
= (char *)(aq
+ 1);
388 strcpy( aq
->serv_name
, name
);
392 aq
->serv_proto
= aq
->serv_name
+ len1
;
393 strcpy( aq
->serv_proto
, proto
);
396 aq
->serv_proto
= NULL
;
398 return run_query( hWnd
, uMsg
, async_getservbyname
, &aq
->query
, sbuf
, buflen
);
401 /***********************************************************************
402 * WSAAsyncGetServByPort (WS2_32.106)
404 HANDLE WINAPI
WSAAsyncGetServByPort(HWND hWnd
, UINT uMsg
, INT port
,
405 LPCSTR proto
, LPSTR sbuf
, INT buflen
)
407 struct async_query_getservbyport
*aq
;
408 unsigned int len
= proto
? strlen(proto
) + 1 : 0;
410 TRACE("hwnd %p, msg %04x, port %i, proto %s\n", hWnd
, uMsg
, port
, debugstr_a(proto
));
412 if (!(aq
= malloc( sizeof(*aq
) + len
)))
414 SetLastError( WSAEWOULDBLOCK
);
420 aq
->serv_proto
= (char *)(aq
+ 1);
421 strcpy( aq
->serv_proto
, proto
);
424 aq
->serv_proto
= NULL
;
426 aq
->serv_port
= port
;
428 return run_query( hWnd
, uMsg
, async_getservbyport
, &aq
->query
, sbuf
, buflen
);
431 /***********************************************************************
432 * WSACancelAsyncRequest (WS2_32.108)
434 INT WINAPI
WSACancelAsyncRequest(HANDLE hAsyncTaskHandle
)
436 FIXME("(%p),stub\n", hAsyncTaskHandle
);
440 /***********************************************************************
441 * WSApSetPostRoutine (WS2_32.24)
443 INT WINAPI
WSApSetPostRoutine(LPWPUPOSTMESSAGE lpPostRoutine
)
445 FIXME("(%p), stub !\n", lpPostRoutine
);
449 /***********************************************************************
450 * WPUCompleteOverlappedRequest (WS2_32.25)
452 WSAEVENT WINAPI
WPUCompleteOverlappedRequest(SOCKET s
, LPWSAOVERLAPPED overlapped
,
453 DWORD error
, DWORD transferred
, LPINT errcode
)
455 FIXME( "socket %#Ix, overlapped %p, error %lu, transferred %lu, errcode %p, stub!\n",
456 s
, overlapped
, error
, transferred
, errcode
);
459 *errcode
= WSAEINVAL
;