9737c75029cf489f8abc7a453775371950e64a09
[oweals/gnunet.git] / src / gns / w32nsp.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gns/w32nsp.c
22  * @brief W32 integration for GNS
23  * @author LRN
24  */
25 /* This code is partially based upon samples from the book
26  * "Network Programming For Microsoft Windows, 2Nd Edition".
27  */
28
29 #include <stdint.h>
30 #include <ws2tcpip.h>
31 #include <ws2spi.h>
32 #include <windows.h>
33 #include <nspapi.h>
34
35 #if 1
36 #  define DEBUGLOG(s, ...)
37 #endif
38 #if 0
39 #  define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)
40 #endif
41
42 #define WINDOWS 1
43 #define MINGW 1
44 #ifndef __BYTE_ORDER
45 #ifdef _BYTE_ORDER
46 #define __BYTE_ORDER _BYTE_ORDER
47 #else
48 #ifdef BYTE_ORDER
49 #define __BYTE_ORDER BYTE_ORDER
50 #endif
51 #endif
52 #endif
53 #ifndef __BIG_ENDIAN
54 #ifdef _BIG_ENDIAN
55 #define __BIG_ENDIAN _BIG_ENDIAN
56 #else
57 #ifdef BIG_ENDIAN
58 #define __BIG_ENDIAN BIG_ENDIAN
59 #endif
60 #endif
61 #endif
62 #ifndef __LITTLE_ENDIAN
63 #ifdef _LITTLE_ENDIAN
64 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
65 #else
66 #ifdef LITTLE_ENDIAN
67 #define __LITTLE_ENDIAN LITTLE_ENDIAN
68 #endif
69 #endif
70 #endif
71 #include "w32resolver.h"
72 #define INITGUID
73 #include "gnunet_w32nsp_lib.h"
74 #undef INITGUID
75
76 #define NSPAPI_VERSION_MAJOR 4
77 #define NSPAPI_VERSION_MINOR 4
78
79 #define REPLY_LIFETIME 60*5
80
81 #define STATE_BEGIN  0x01
82 #define STATE_END    0x02
83 #define STATE_REPLY  0x04
84 #define STATE_GHBN   0x08
85
86 static CRITICAL_SECTION records_cs;
87
88 struct record
89 {
90   SOCKET s;
91   DWORD flags;
92   uint8_t state;
93   char *buf;
94   wchar_t *name;
95 };
96
97 static struct record *records = NULL;
98 static size_t records_len = 0;
99 static size_t records_size = 0;
100
101 static int
102 resize_records ()
103 {
104   size_t new_size = records_len > 0 ? records_len * 2 : 5;
105   struct record *new_records = malloc (new_size * sizeof (struct record));
106   if (new_records == NULL)
107   {
108     SetLastError (WSA_NOT_ENOUGH_MEMORY);
109     return 0;
110   }
111   memcpy (new_records, records, records_len * sizeof (struct record));
112   memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));
113   records_size = new_size;
114   free (records);
115   records = new_records;
116   return 1;
117 }
118
119 static int
120 add_record (SOCKET s, const wchar_t *name, DWORD flags)
121 {
122   int res = 1;
123   int i;
124   int empty = -1;
125   //EnterCriticalSection (&records_cs);
126   for (i = 0; i < records_len; i++)
127     if (records[i].state == 0)
128       break;
129   empty = i;
130   if (i == records_len)
131   {
132     res = resize_records ();
133     if (res)
134       empty = records_len++;
135   }
136   if (res)
137   {
138     struct record r;
139     r.s = s;
140     r.flags = flags;
141     r.name = (wchar_t *) name;
142     r.state = 1;
143     r.buf = NULL;
144     if (name)
145       r.name = wcsdup (name);
146     records[empty] = r;
147   }
148   //LeaveCriticalSection (&records_cs);
149   return res;
150 }
151
152 static void
153 free_record (int i)
154 {
155   if (records[i].name)
156     free (records[i].name);
157   records[i].state = 0;
158 }
159
160 /* These are not defined by mingw.org headers at the moment*/
161 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
162 typedef struct _NSP_ROUTINE_XP {
163   DWORD cbSize;
164   DWORD dwMajorVersion;
165   DWORD dwMinorVersion;
166   LPNSPCLEANUP NSPCleanup;
167   LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
168   LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
169   LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
170   LPNSPSETSERVICE NSPSetService;
171   LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
172   LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
173   LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
174   LPNSPIOCTL NSPIoctl;
175 } NSP_ROUTINE_XP;
176
177 static SOCKET
178 connect_to_dns_resolver ()
179 {
180   struct sockaddr_in addr;
181   SOCKET r;
182   int ret;
183
184   r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
185   if (INVALID_SOCKET == r)
186   {
187     SetLastError (16004);
188     return r;
189   }
190
191   addr.sin_family = AF_INET;
192   addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
193   addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
194
195   ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
196   if (SOCKET_ERROR == ret)
197   {
198     DWORD err = GetLastError ();
199     closesocket (r);
200     SetLastError (err);
201     SetLastError (16005);
202     r = INVALID_SOCKET;
203   }
204   return r;
205 }
206
207 static int
208 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
209     LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
210     SOCKET *resolver)
211 {
212   struct GNUNET_W32RESOLVER_GetMessage *msg;
213   int af4 = 0;
214   int af6 = 0;
215   char *buf;
216   int ret = 1;
217   int i;
218   uint32_t id;
219   size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
220   size_t namelen = 0;
221   if (lpqsRestrictions->lpszServiceInstanceName)
222     namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
223   size += namelen;
224   buf = malloc (size);
225   msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
226   msg->header.size = htons (size);
227   msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
228   if (lpqsRestrictions->dwNumberOfProtocols > 0)
229   {
230     int i;
231     for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
232     {
233       if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
234         af4 = 1;
235       if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
236         af6 = 1;
237     }
238   }
239   if (af4 && !af6)
240     msg->af = htonl (AF_INET);
241   else if (af6 && !af4)
242     msg->af = htonl (AF_INET6);
243   else
244     msg->af = htonl (AF_UNSPEC);
245   if (lpqsRestrictions->lpszServiceInstanceName)
246     memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
247   msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
248   msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
249   msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
250   for (i = 0; i < 8; i++)
251     msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
252   *resolver = connect_to_dns_resolver ();
253   if (*resolver != INVALID_SOCKET)
254   {
255     if (size != send (*resolver, buf, size, 0))
256     {
257       DWORD err = GetLastError ();
258       closesocket (*resolver);
259       *resolver = INVALID_SOCKET;
260       DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
261       SetLastError (WSATRY_AGAIN);
262       ret = 0;
263     }
264   }
265   else
266     ret = 0;
267   free (buf);
268   return ret;
269 }
270
271 static int WSPAPI
272 NSPCleanup (LPGUID lpProviderId)
273 {
274   DEBUGLOG ("NSPCleanup\n");
275   if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
276   {
277     return NO_ERROR;
278   }
279   SetLastError (WSAEINVALIDPROVIDER);
280   return SOCKET_ERROR;
281 }
282
283 BOOL WINAPI
284 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
285 {
286   switch (fdwReason)
287   {
288     case DLL_PROCESS_ATTACH:
289       if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
290       {
291         return FALSE;
292       }
293       break;
294     case DLL_THREAD_ATTACH:
295       break;
296     case DLL_THREAD_DETACH:
297       break;
298     case DLL_PROCESS_DETACH:
299       DeleteCriticalSection (&records_cs);
300       break;
301   }
302   return TRUE;
303 }
304
305
306
307
308 static int WSPAPI
309 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
310     LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
311     LPHANDLE lphLookup)
312 {
313   DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
314   if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
315   {
316     SOCKET s;
317     if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
318     {
319       DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
320       SetLastError (WSANO_DATA);
321       return SOCKET_ERROR;
322     }
323     if (lpqsRestrictions->lpszServiceInstanceName != NULL)
324     {
325       wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
326       size_t len = wcslen (s);
327       if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
328       {
329       }
330       else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
331       {
332       }
333       else
334       {
335         DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
336         SetLastError (WSANO_DATA);
337         return SOCKET_ERROR;
338       }
339     }
340
341     if (send_name_to_ip_request (lpqsRestrictions,
342         lpServiceClassInfo, dwControlFlags, &s))
343     {
344       if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
345       {
346         DWORD err = GetLastError ();
347         DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
348         closesocket (s);
349         SetLastError (err);
350         return SOCKET_ERROR;
351       }
352       *lphLookup = (HANDLE) s;
353       DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
354       return NO_ERROR;
355     }
356     return SOCKET_ERROR;
357   }
358   DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
359   SetLastError (WSAEINVALIDPROVIDER);
360   return SOCKET_ERROR;
361 }
362
363 #define UnmarshallPtr(ptr, ptrtype, base) \
364   if (ptr) \
365     ptr = (ptrtype *) (base + (uintptr_t) ptr)
366
367 static void
368 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
369 {
370   int i;
371   char *base = (char *) req;
372   UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
373   UnmarshallPtr (req->lpServiceClassId, GUID, base);
374   UnmarshallPtr (req->lpVersion, WSAVERSION, base);
375   UnmarshallPtr (req->lpszComment, wchar_t, base);
376   UnmarshallPtr (req->lpNSProviderId, GUID, base);
377   UnmarshallPtr (req->lpszContext, wchar_t, base);
378   UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
379   UnmarshallPtr (req->lpszQueryString, wchar_t, base);
380   UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
381   for (i = 0; i < req->dwNumberOfCsAddrs; i++)
382   {
383     UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
384     UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
385   }
386   UnmarshallPtr (req->lpBlob, BLOB, base);
387   if (req->lpBlob)
388     UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
389 }
390
391 static int WSAAPI
392 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
393     LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
394 {
395   DWORD effective_flags;
396   int i;
397   struct GNUNET_MessageHeader header = {0, 0};
398   int rec = -1;
399   int rc;
400   int to_receive;
401   int t;
402   char *buf;
403
404   DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
405   //EnterCriticalSection (&records_cs);
406   for (i = 0; i < records_len; i++)
407   {
408     if (records[i].s == (SOCKET) hLookup)
409     {
410       rec = i;
411       break;
412     }
413   }
414   if (rec == -1)
415   {
416     DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
417     SetLastError (WSA_INVALID_HANDLE);
418     //LeaveCriticalSection (&records_cs);
419     return SOCKET_ERROR;
420   }
421   if (records[rec].state & 4)
422   {
423     DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
424     SetLastError (WSA_E_NO_MORE);
425     //LeaveCriticalSection (&records_cs);
426     return SOCKET_ERROR;
427   }
428   effective_flags = dwControlFlags & records[rec].flags;
429   if (records[rec].buf)
430   {
431     header = *((struct GNUNET_MessageHeader *) records[rec].buf);
432     if (dwControlFlags & LUP_FLUSHCACHE)
433     {
434       free (records[rec].buf);
435       records[rec].buf = NULL;
436     }
437     else
438     {
439       if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
440       {
441         DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
442         SetLastError (WSAEFAULT);
443         //LeaveCriticalSection (&records_cs);
444         return SOCKET_ERROR;
445       }
446       memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
447       free (records[rec].buf);
448       records[rec].buf = NULL;
449       //LeaveCriticalSection (&records_cs);
450       UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
451       DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
452       return NO_ERROR;
453     }
454   }
455   records[rec].state |= 8;
456   //LeaveCriticalSection (&records_cs);
457   to_receive = sizeof (header);
458   rc = 0;
459   while (to_receive > 0)
460   {
461     t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
462     if (t > 0)
463     {
464       rc += t;
465       to_receive -= t;
466     }
467     else
468       break;
469   }
470   //EnterCriticalSection (&records_cs);
471   records[rec].state &= ~8;
472   if (rc != sizeof (header))
473   {
474     if (records[rec].state & 2)
475     {
476       DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
477       SetLastError (WSA_E_CANCELLED);
478     }
479     else
480     {
481       DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
482       SetLastError (WSA_E_NO_MORE);
483     }
484     records[rec].state |= 4;
485     //LeaveCriticalSection (&records_cs);
486     return SOCKET_ERROR;
487   }
488   records[rec].state &= ~8;
489   header.type = ntohs (header.type);
490   header.size = ntohs (header.size);
491   if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
492       (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
493       header.size == sizeof (header)))
494   {
495     records[rec].state |= 4;
496     DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header is wrong or type is wrong or no data\n");
497     //LeaveCriticalSection (&records_cs);
498     SetLastError (WSA_E_NO_MORE);
499     return SOCKET_ERROR;
500   }
501   buf = malloc (header.size);
502   if (buf == NULL)
503   {
504     records[rec].state |= 4;
505     DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
506     //LeaveCriticalSection (&records_cs);
507     SetLastError (WSA_E_NO_MORE);
508     return SOCKET_ERROR;
509   }
510   records[rec].state |= 8;
511   //LeaveCriticalSection (&records_cs);
512   memcpy (buf, &header, sizeof (header));
513   to_receive = header.size - sizeof (header);
514   rc = 0;
515   while (to_receive > 0)
516   {
517     t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
518     if (t > 0)
519     {
520       rc += t;
521       to_receive -= t;
522     }
523     else
524       break;
525   }
526   //EnterCriticalSection (&records_cs);
527   records[rec].state &= ~8;
528   if (rc != header.size - sizeof (header))
529   {
530     free (buf);
531     if (records[rec].state & 2)
532     {
533       DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
534       SetLastError (WSA_E_CANCELLED);
535     }
536     else
537     {
538       DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
539       SetLastError (WSA_E_NO_MORE);
540     }
541     records[rec].state |= 4;
542     //LeaveCriticalSection (&records_cs);
543     return SOCKET_ERROR;
544   }
545   if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
546   {
547     DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
548     SetLastError (WSAEFAULT);
549     records[rec].buf = buf;
550     //LeaveCriticalSection (&records_cs);
551     return SOCKET_ERROR;
552   }
553   //LeaveCriticalSection (&records_cs);
554   memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
555   free (buf);
556   DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
557   UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
558   DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
559   return NO_ERROR;
560 }
561
562 static int WSPAPI
563 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
564 {
565   DWORD effective_flags;
566   int i;
567   struct GNUNET_MessageHeader header = {0, 0};
568   int rec = -1;
569   int rc;
570   char *buf;
571
572   DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
573   //EnterCriticalSection (&records_cs);
574   for (i = 0; i < records_len; i++)
575   {
576     if (records[i].s == (SOCKET) hLookup)
577     {
578       rec = i;
579       break;
580     }
581   }
582   if (rec == -1)
583   {
584     SetLastError (WSA_INVALID_HANDLE);
585     //LeaveCriticalSection (&records_cs);
586     DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
587     return SOCKET_ERROR;
588   }
589   records[rec].state |= 2;
590   closesocket (records[rec].s);
591   while (records[rec].state & 8)
592   {
593     //LeaveCriticalSection (&records_cs);
594     Sleep (10);
595     //EnterCriticalSection (&records_cs);
596   }
597   if (records[rec].buf)
598     free (records[rec].buf);
599   records[rec].buf = NULL;
600   records[rec].state = 0;
601   if (records[rec].name)
602     free (records[rec].name);
603   //LeaveCriticalSection (&records_cs);
604   DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
605   return NO_ERROR;
606 }
607
608 static int WSAAPI
609 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
610     LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
611     WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
612 {
613   DEBUGLOG ("GNUNET_W32NSP_SetService\n");
614   SetLastError (WSAEOPNOTSUPP);
615   return SOCKET_ERROR;
616 }
617
618 static int WSAAPI
619 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
620     LPWSASERVICECLASSINFOW lpServiceClassInfo)
621 {
622   DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
623   SetLastError (WSAEOPNOTSUPP);
624   return SOCKET_ERROR;
625 }
626
627
628 static int WSAAPI
629 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
630 {
631   DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
632   SetLastError (WSAEOPNOTSUPP);
633   return SOCKET_ERROR;
634 }
635
636 static int WSAAPI
637 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
638   LPWSASERVICECLASSINFOW lpServiceClassInfo)
639 {
640   DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
641   SetLastError (WSAEOPNOTSUPP);
642   return SOCKET_ERROR;
643 }
644
645 static int WSAAPI
646 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
647     DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
648     LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
649     LPWSATHREADID lpThreadId)
650 {
651   DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
652   SetLastError (WSAEOPNOTSUPP);
653   return SOCKET_ERROR;
654 }
655
656 /**
657  * This function is called by Winsock to hook up our provider.
658  * It is the only function that [should be/is] exported by the
659  * provider. All other routines are passed as pointers in lpnspRoutines.
660  */
661 int WSAAPI
662 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
663 {
664   if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
665   {
666     if (!connect_to_dns_resolver ())
667     {
668       return SOCKET_ERROR;
669     }
670     /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
671      * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
672      * and use that offset as cbSize.
673      */
674     lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
675
676     lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
677     lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
678     lpnspRoutines->NSPCleanup = NSPCleanup;
679     lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
680     lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
681     lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
682     lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
683     lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
684     lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
685     lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
686     /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
687     lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
688     return NO_ERROR;
689   }
690   SetLastError (WSAEINVALIDPROVIDER);
691   return SOCKET_ERROR;
692 }
693