1/*
2 * dllfunc.c - wrapper functions
3 */
4
5/*
6 * Copyright (c) 2000,2002 Japan Network Information Center.
7 * All rights reserved.
8 *
9 * By using this file, you agree to the terms and conditions set forth bellow.
10 *
11 * 			LICENSE TERMS AND CONDITIONS
12 *
13 * The following License Terms and Conditions apply, unless a different
14 * license is obtained from Japan Network Information Center ("JPNIC"),
15 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda,
16 * Chiyoda-ku, Tokyo 101-0047, Japan.
17 *
18 * 1. Use, Modification and Redistribution (including distribution of any
19 *    modified or derived work) in source and/or binary forms is permitted
20 *    under this License Terms and Conditions.
21 *
22 * 2. Redistribution of source code must retain the copyright notices as they
23 *    appear in each source code file, this License Terms and Conditions.
24 *
25 * 3. Redistribution in binary form must reproduce the Copyright Notice,
26 *    this License Terms and Conditions, in the documentation and/or other
27 *    materials provided with the distribution.  For the purposes of binary
28 *    distribution the "Copyright Notice" refers to the following language:
29 *    "Copyright (c) 2000-2002 Japan Network Information Center.  All rights reserved."
30 *
31 * 4. The name of JPNIC may not be used to endorse or promote products
32 *    derived from this Software without specific prior written approval of
33 *    JPNIC.
34 *
35 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
36 *    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 *    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
38 *    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
39 *    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
40 *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
41 *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
42 *    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
43 *    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
44 *    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
45 *    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46 */
47
48#include <windows.h>
49#include <svcguid.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <string.h>
53#include <process.h>
54
55#include "dlldef.h"
56
57#ifndef EAI_MEMORY
58#define EAI_MEMORY	WSA_NOT_ENOUGH_MEMORY
59#endif
60#ifndef EAI_FAIL
61#define EAI_FAIL	WSANO_RECOVERY
62#endif
63
64static GUID guid_habn = SVCID_INET_HOSTADDRBYNAME;
65static GUID guid_habis = SVCID_INET_HOSTADDRBYINETSTRING;
66
67#define SVCID_IS_HABN(p) (memcmp(p, &guid_habn, sizeof(GUID)) == 0)
68#define SVCID_IS_HABIS(p) (memcmp(p, &guid_habis, sizeof(GUID)) == 0)
69
70/*
71 * Rename addrinfo to my_addrinfo for avoiding possible name conflict.
72 */
73struct my_addrinfo {
74	int     ai_flags;
75	int     ai_family;
76	int     ai_socktype;
77	int     ai_protocol;
78	size_t  ai_addrlen;
79	char   *ai_canonname;
80	struct sockaddr  *ai_addr;
81	struct my_addrinfo  *ai_next;
82};
83
84typedef struct obj_lock {
85	void *key;
86	struct obj_lock *next;
87} obj_lock_t;
88
89#define OBJLOCKHASH_SIZE	127
90static obj_lock_t *obj_lock_hash[OBJLOCKHASH_SIZE];
91
92static int	obj_hash(void *key);
93static int	obj_islocked(void *key);
94static void	obj_lock(void *key);
95static void	obj_unlock(void *key);
96static char	*decode_name_dynamic(const char *name, idn_resconf_t idnctx);
97static struct my_addrinfo
98		*copy_decode_addrinfo_dynamic(struct my_addrinfo *aip,
99					      idn_resconf_t idnctx);
100static void	free_copied_addrinfo(struct my_addrinfo *aip);
101
102WRAPPER_EXPORT int WSAAPI
103gethostname(char FAR * name, int namelen) {
104	int ret;
105
106	TRACE("ENTER gethostname\n");
107	ret = _org_gethostname(name, namelen);
108	TRACE("LEAVE gethostname %d <%-.100s>\n", ret, name);
109
110	return (ret);
111}
112
113WRAPPER_EXPORT struct hostent FAR * WSAAPI
114gethostbyname(const char FAR * name) {
115	struct hostent FAR *ret;
116	char    nbuff[256];
117	char    hbuff[256];
118	BOOL    stat;
119	idn_resconf_t	encodeCtx;
120
121	TRACE("ENTER gethostbyname <%-.100s>\n",
122	      (name != NULL ? name : "NULL"));
123
124	encodeCtx = idnGetContext();
125
126	if (encodeCtx == NULL || name == NULL) {
127		ret = _org_gethostbyname(name);
128	} else {
129		stat = idnConvReq(encodeCtx, name, nbuff, sizeof(nbuff));
130		if (stat == FALSE) {
131			TRACE("idnConvReq failed\n");
132			ret = NULL;
133		} else {
134			TRACE("Converted Name <%s>\n",
135			      dumpName(nbuff, hbuff, sizeof(hbuff)));
136			ret = _org_gethostbyname(nbuff);
137		}
138	}
139
140	if (ret != NULL && encodeCtx != NULL) {
141		TRACE("Resulting Name <%s>\n",
142		      dumpName(ret->h_name, hbuff, sizeof(hbuff)));
143		stat = idnConvRsp(encodeCtx, ret->h_name,
144				  nbuff, sizeof(nbuff));
145		if (stat == FALSE) {
146			TRACE("Decoding failed - return the name verbatim\n");
147		} else {
148			TRACE("Converted Back <%s>\n",
149			      dumpName(nbuff, hbuff, sizeof(hbuff)));
150			strcpy(ret->h_name, nbuff);
151		}
152	}
153
154	if (ret == NULL) {
155		TRACE("LEAVE gethostbyname NULL\n");
156	} else {
157		TRACE("LEAVE gethostbyname <%s>\n",
158		      dumpHost(ret, hbuff, sizeof(hbuff)));
159	}
160	return (ret);
161}
162
163WRAPPER_EXPORT struct hostent FAR * WSAAPI
164gethostbyaddr(const char FAR * addr, int len, int type) {
165	struct hostent FAR *ret;
166	char    nbuff[256];
167	char    abuff[256];
168	char    hbuff[256];
169	BOOL    stat;
170	idn_resconf_t	encodeCtx;
171
172	TRACE("ENTER gethostbyaddr <%s>\n",
173	      dumpAddr(addr, len, abuff, sizeof(abuff)));
174
175	encodeCtx = idnGetContext();
176
177	ret = _org_gethostbyaddr(addr, len, type);
178
179	if (ret != NULL && encodeCtx != NULL) {
180		TRACE("Resulting Name <%s>\n",
181		      dumpName(ret->h_name, hbuff, sizeof(hbuff)));
182		stat = idnConvRsp(encodeCtx, ret->h_name,
183				  nbuff, sizeof(nbuff));
184		if (stat == FALSE) {
185			TRACE("Decoding failed - return the name verbatim\n");
186		} else {
187			TRACE("Converted Back <%s>\n",
188			      dumpName(nbuff, hbuff, sizeof(hbuff)));
189			strcpy(ret->h_name, nbuff);
190		}
191	}
192
193	if (ret == NULL) {
194		TRACE("LEAVE gethostbyaddr NULL\n");
195	} else {
196		TRACE("LEAVE gethostbyaddr <%s>\n",
197		      dumpHost(ret, hbuff, sizeof(hbuff)));
198	}
199	return (ret);
200}
201
202WRAPPER_EXPORT HANDLE WSAAPI
203WSAAsyncGetHostByName(HWND hWnd, u_int wMsg,
204		      const char FAR * name, char FAR * buf, int buflen)
205{
206	HANDLE  ret;
207	char    nbuff[256];
208	char    hbuff[256];
209	idn_resconf_t	encodeCtx;
210
211	TRACE("ENTER WSAAsyncGetHostByName <%-.100s>\n", name);
212
213	encodeCtx = idnGetContext();
214
215	if (encodeCtx == NULL || name == NULL) {
216		ret = _org_WSAAsyncGetHostByName(hWnd, wMsg,
217						 name, buf, buflen);
218	} else {
219		idnHook(hWnd, wMsg, buf, encodeCtx);
220		idnConvReq(encodeCtx, name, nbuff, sizeof(nbuff));
221		TRACE("Converted Name <%s>\n",
222		      dumpName(nbuff, hbuff, sizeof(hbuff)));
223		ret = _org_WSAAsyncGetHostByName(hWnd, wMsg, nbuff,
224						 buf, buflen);
225	}
226
227	TRACE("LEAVE WSAAsyncGetHostByName HANDLE %08x\n", ret);
228
229	return (ret);
230}
231
232WRAPPER_EXPORT HANDLE WSAAPI
233WSAAsyncGetHostByAddr(HWND hWnd, u_int wMsg, const char FAR * addr,
234		      int len, int type, char FAR * buf, int buflen)
235{
236	HANDLE  ret;
237	char    abuff[256];
238	idn_resconf_t	encodeCtx;
239
240	encodeCtx = idnGetContext();
241
242	if (encodeCtx != NULL) {
243		idnHook(hWnd, wMsg, buf, encodeCtx);
244	}
245
246	TRACE("ENTER WSAAsyncGetHostByAddr <%s>\n",
247	      dumpAddr(addr, len, abuff, sizeof(abuff)));
248	ret = _org_WSAAsyncGetHostByAddr(hWnd, wMsg, addr, len, type,
249					 buf, buflen);
250	TRACE("LEAVE WSAAsyncGetHostByAddr HANDLE %08x\n", ret);
251
252	return (ret);
253}
254
255WRAPPER_EXPORT INT WSAAPI
256WSALookupServiceBeginA(LPWSAQUERYSETA lpqsRestrictions,
257		       DWORD dwControlFlags, LPHANDLE lphLookup)
258{
259	INT     ret;
260	char    nbuff[256];
261	char    hbuff[256];
262	LPSTR   name = lpqsRestrictions->lpszServiceInstanceName;
263	LPGUID  class = lpqsRestrictions->lpServiceClassId;
264	idn_resconf_t	encodeCtx;
265
266	TRACE("ENTER WSALookupServiceBeginA <%-.100s>\n",
267	      name == NULL ? "<NULL>" : name);
268
269	encodeCtx = idnGetContext();
270
271	if (name != NULL && encodeCtx != NULL && SVCID_IS_HABN(class) == 0) {
272		idnConvReq(encodeCtx, name, nbuff, sizeof(nbuff));
273		TRACE("Converted Name <%s>\n",
274		      dumpName(nbuff, hbuff, sizeof(hbuff)));
275		/* strcpy(lpqsRestrictions->lpszQueryString, nbuff); */
276		lpqsRestrictions->lpszServiceInstanceName = nbuff;
277	}
278	ret = _org_WSALookupServiceBeginA(lpqsRestrictions,
279					  dwControlFlags, lphLookup);
280	TRACE("LEAVE WSALookupServiceBeginA %d\n", ret);
281
282	return (ret);
283}
284
285WRAPPER_EXPORT INT WSAAPI
286WSALookupServiceNextA(HANDLE hLookup, DWORD dwControlFlags,
287		      LPDWORD lpdwBufferLength, LPWSAQUERYSETA lpqsResults)
288{
289	INT     ret;
290	char    nbuff[256];
291	char    hbuff[256];
292	LPGUID  class;
293	idn_resconf_t	encodeCtx;
294
295	TRACE("ENTER WSALookupServiceNextA\n");
296
297	encodeCtx = idnGetContext();
298
299	ret = _org_WSALookupServiceNextA(hLookup, dwControlFlags,
300					 lpdwBufferLength, lpqsResults);
301	class = lpqsResults->lpServiceClassId;
302
303	if (ret == 0 &&
304	    encodeCtx != NULL &&
305	    (dwControlFlags & LUP_RETURN_NAME) &&
306	    (SVCID_IS_HABN(class) || SVCID_IS_HABIS(class))) {
307		TRACE("Resulting Name <%s>\n",
308		      dumpName(lpqsResults->lpszServiceInstanceName,
309			       hbuff, sizeof(hbuff)));
310		if (idnConvRsp(encodeCtx,
311			       lpqsResults->lpszServiceInstanceName,
312			       nbuff, sizeof(nbuff)) == FALSE) {
313			TRACE("Decoding failed - return the name verbatim\n");
314		} else {
315			TRACE("Converted Back <%s>\n",
316			      dumpName(nbuff, hbuff, sizeof(hbuff)));
317			strcpy(lpqsResults->lpszServiceInstanceName, nbuff);
318		}
319	}
320	TRACE("LEAVE WSALookupServiceNextA %d <%s>\n", ret, nbuff);
321
322	return (ret);
323}
324
325WRAPPER_EXPORT INT WSAAPI
326WSALookupServiceBeginW(LPWSAQUERYSETW lpqsRestrictions,
327		       DWORD dwControlFlags, LPHANDLE lphLookup)
328{
329	INT     ret;
330
331	TRACE("ENTER WSALookupServiceBeginW\n");
332	ret = _org_WSALookupServiceBeginW(lpqsRestrictions,
333					  dwControlFlags,lphLookup);
334	TRACE("LEAVE WSALookupServiceBeginW %d\n", ret);
335
336	return (ret);
337}
338
339WRAPPER_EXPORT INT WSAAPI
340WSALookupServiceNextW(HANDLE hLookup, DWORD dwControlFlags,
341		      LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
342{
343	INT     ret;
344
345	TRACE("ENTER WSALookupServiceNextW\n");
346	ret = _org_WSALookupServiceNextW(hLookup, dwControlFlags,
347					 lpdwBufferLength, lpqsResults);
348	TRACE("LEAVE WSALookupServiceNextW %d\n", ret);
349
350	return (ret);
351}
352
353WRAPPER_EXPORT INT WSAAPI
354WSALookupServiceEnd(HANDLE  hLookup) {
355	INT     ret;
356
357	TRACE("ENTER WSALookupServiceEnd\n");
358	ret = _org_WSALookupServiceEnd(hLookup);
359	TRACE("LEAVE WSALookupServiceEnd %d\n", ret);
360
361	return (ret);
362}
363
364static int
365obj_hash(void *key) {
366	/*
367	 * Hash function for obj_*.
368	 * 'key' is supposed to be an address.
369	 */
370	unsigned long v = (unsigned long)key;
371
372	return ((v >> 3) % OBJLOCKHASH_SIZE);
373}
374
375static int
376obj_islocked(void *key)
377{
378	/*
379	 * Check if the object specified by 'key' is locked.
380	 * Return 1 if so, 0 otherwise.
381	 */
382	int h = obj_hash(key);
383	obj_lock_t *olp = obj_lock_hash[h];
384
385	while (olp != NULL) {
386		if (olp->key == key)
387			return (1);
388		olp = olp->next;
389	}
390	return (0);
391}
392
393static void
394obj_lock(void *key)
395{
396	/*
397	 * Lock an object specified by 'key'.
398	 */
399	int h = obj_hash(key);
400	obj_lock_t *olp;
401
402	olp = malloc(sizeof(obj_lock_t));
403	if (olp != NULL) {
404		olp->key = key;
405		olp->next = obj_lock_hash[h];
406		obj_lock_hash[h] = olp;
407	}
408}
409
410static void
411obj_unlock(void *key)
412{
413	/*
414	 * Unlock an object specified by 'key'.
415	 */
416	int h = obj_hash(key);
417	obj_lock_t *olp, *olp0;
418
419	olp = obj_lock_hash[h];
420	olp0 = NULL;
421	while (olp != NULL) {
422		if (olp->key == key) {
423			if (olp0 == NULL)
424				obj_lock_hash[h] = olp->next;
425			else
426				olp0->next = olp->next;
427			free(olp);
428			return;
429		}
430		olp0 = olp;
431		olp = olp->next;
432	}
433}
434
435static char *
436decode_name_dynamic(const char *name, idn_resconf_t idnctx) {
437	BOOL stat;
438	char buf[256], tmp[256];
439	char *s;
440
441	if (idnConvRsp(idnctx, name, buf, sizeof(buf)) == TRUE) {
442		TRACE("Converted Back <%s>\n",
443		      dumpName(buf, tmp, sizeof(tmp)));
444		name = buf;
445	} else {
446		TRACE("Decoding failed - return the name verbatim\n");
447	}
448	s = malloc(strlen(name) + 1);
449	if (s == NULL)
450		return (NULL);
451	else
452		return (strcpy(s, name));
453}
454
455static struct my_addrinfo *
456copy_decode_addrinfo_dynamic(struct my_addrinfo *aip, idn_resconf_t idnctx)
457{
458	struct my_addrinfo *newaip;
459
460	if (aip == NULL)
461		return (NULL);
462
463	newaip = malloc(sizeof(struct my_addrinfo) + aip->ai_addrlen);
464	if (newaip == NULL)
465		return (NULL);
466
467	*newaip = *aip;
468	newaip->ai_addr = (struct sockaddr *)(newaip + 1);
469	memcpy(newaip->ai_addr, aip->ai_addr, aip->ai_addrlen);
470
471	if (newaip->ai_canonname != NULL)
472		newaip->ai_canonname = decode_name_dynamic(aip->ai_canonname,
473							   idnctx);
474
475	newaip->ai_next = copy_decode_addrinfo_dynamic(aip->ai_next, idnctx);
476	return (newaip);
477}
478
479static void
480free_copied_addrinfo(struct my_addrinfo *aip) {
481	while (aip != NULL) {
482		struct my_addrinfo *next = aip->ai_next;
483
484		if (aip->ai_canonname != NULL)
485			free(aip->ai_canonname);
486		free(aip);
487		aip = next;
488	}
489}
490
491WRAPPER_EXPORT int WSAAPI
492getaddrinfo(const char *nodename, const char *servname,
493	    const struct my_addrinfo *hints, struct my_addrinfo **res)
494{
495	char namebuf[256];
496	BOOL stat;
497	struct my_addrinfo *aip;
498	int err;
499	idn_resconf_t	encodeCtx;
500
501	TRACE("ENTER getaddrinfo <%-.100s>\n", nodename ? nodename : "NULL");
502
503	encodeCtx = idnGetContext();
504
505	if (nodename == NULL || encodeCtx == NULL) {
506		TRACE("conversion unnecessary\n");
507		err = _org_getaddrinfo(nodename, servname, hints, res);
508	} else {
509		stat = idnConvReq(encodeCtx, nodename,
510				  namebuf, sizeof(namebuf));
511		if (stat == TRUE) {
512			nodename = namebuf;
513			TRACE("Converted Name <%-.100s>\n", namebuf);
514		}
515
516		err = _org_getaddrinfo(nodename, servname, hints, &aip);
517		if (err == 0 && aip != NULL) {
518			*res = copy_decode_addrinfo_dynamic(aip, encodeCtx);
519			if (*res == NULL)
520				err = EAI_FAIL;
521			else
522				obj_lock(*res);
523			if (aip != NULL)
524				_org_freeaddrinfo(aip);
525		}
526	}
527
528	TRACE("LEAVE getaddrinfo %d\n", err);
529	return (err);
530}
531
532WRAPPER_EXPORT void WSAAPI
533freeaddrinfo(struct my_addrinfo *aip) {
534	TRACE("ENTER freeaddrinfo aip=%p\n", (void *)aip);
535
536	if (obj_islocked(aip)) {
537		/*
538		 * We allocated the data.
539		 */
540		obj_unlock(aip);
541		free_copied_addrinfo(aip);
542	} else {
543		/*
544		 * It was allocated the original getaddrinfo().
545		 */
546		TRACE("Not allocated by the wrapper\n");
547		_org_freeaddrinfo(aip);
548	}
549	TRACE("LEAVE freeaddrinfo\n");
550}
551
552WRAPPER_EXPORT int WSAAPI
553getnameinfo(const struct sockaddr *sa, DWORD salen,
554	    char *host, DWORD hostlen, char *serv,
555	    DWORD servlen, int flags)
556{
557	char name[256];
558	size_t namelen = sizeof(name);
559	int code;
560	BOOL stat;
561	idn_resconf_t	encodeCtx;
562
563	TRACE("ENTER getnameinfo\n");
564
565	encodeCtx = idnGetContext();
566
567	if (host == NULL || hostlen == 0 || encodeCtx == NULL) {
568		TRACE("conversion unnecessary\n");
569		code = _org_getnameinfo(sa, salen, host, hostlen,
570					serv, servlen, flags);
571	} else {
572		code = _org_getnameinfo(sa, salen, name, namelen,
573					serv, servlen, flags);
574		if (code == 0 && name[0] != '\0') {
575			stat = idnConvRsp(encodeCtx, name, host, hostlen);
576			if (stat == FALSE) {
577				TRACE("Decoding failed - return the name verbatim\n");
578				if (strlen(name) >= hostlen) {
579					code = EAI_FAIL;
580				} else {
581					strcpy(host, name);
582				}
583			} else {
584				TRACE("Converted Back <%s>\n",
585				      dumpName(host, name, sizeof(name)));
586			}
587		}
588	}
589
590	TRACE("LEAVE getnameinfo %d\n", code);
591	return (code);
592}
593