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