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