2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
22 * @brief W32 integration for GNS
25 /* This code is partially based upon samples from the book
26 * "Network Programming For Microsoft Windows, 2Nd Edition".
36 # define DEBUGLOG(s, ...)
39 # define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)
46 #define __BYTE_ORDER _BYTE_ORDER
49 #define __BYTE_ORDER BYTE_ORDER
55 #define __BIG_ENDIAN _BIG_ENDIAN
58 #define __BIG_ENDIAN BIG_ENDIAN
62 #ifndef __LITTLE_ENDIAN
64 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
67 #define __LITTLE_ENDIAN LITTLE_ENDIAN
71 #include "w32resolver.h"
73 #include "gnunet_w32nsp_lib.h"
76 #define NSPAPI_VERSION_MAJOR 4
77 #define NSPAPI_VERSION_MINOR 4
79 #define REPLY_LIFETIME 60*5
81 #define STATE_BEGIN 0x01
82 #define STATE_END 0x02
83 #define STATE_REPLY 0x04
84 #define STATE_GHBN 0x08
86 static CRITICAL_SECTION records_cs;
97 static struct record *records = NULL;
98 static size_t records_len = 0;
99 static size_t records_size = 0;
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)
108 SetLastError (WSA_NOT_ENOUGH_MEMORY);
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;
115 records = new_records;
120 add_record (SOCKET s, const wchar_t *name, DWORD flags)
125 //EnterCriticalSection (&records_cs);
126 for (i = 0; i < records_len; i++)
127 if (records[i].state == 0)
130 if (i == records_len)
132 res = resize_records ();
134 empty = records_len++;
141 r.name = (wchar_t *) name;
145 r.name = wcsdup (name);
148 //LeaveCriticalSection (&records_cs);
156 free (records[i].name);
157 records[i].state = 0;
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 {
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;
178 connect_to_dns_resolver ()
180 struct sockaddr_in addr;
184 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
185 if (INVALID_SOCKET == r)
187 SetLastError (16004);
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");
195 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
196 if (SOCKET_ERROR == ret)
198 DWORD err = GetLastError ();
201 SetLastError (16005);
208 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
209 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
212 struct GNUNET_W32RESOLVER_GetMessage *msg;
219 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
221 if (lpqsRestrictions->lpszServiceInstanceName)
222 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
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)
231 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
233 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
235 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
240 msg->af = htonl (AF_INET);
241 else if (af6 && !af4)
242 msg->af = htonl (AF_INET6);
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)
255 if (size != send (*resolver, buf, size, 0))
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);
272 NSPCleanup (LPGUID lpProviderId)
274 DEBUGLOG ("NSPCleanup\n");
275 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
279 SetLastError (WSAEINVALIDPROVIDER);
284 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
288 case DLL_PROCESS_ATTACH:
289 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
294 case DLL_THREAD_ATTACH:
296 case DLL_THREAD_DETACH:
298 case DLL_PROCESS_DETACH:
299 DeleteCriticalSection (&records_cs);
309 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
310 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
313 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
314 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
317 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
319 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
320 SetLastError (WSANO_DATA);
323 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
325 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
326 size_t len = wcslen (s);
327 if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
330 else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
335 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
336 SetLastError (WSANO_DATA);
341 if (send_name_to_ip_request (lpqsRestrictions,
342 lpServiceClassInfo, dwControlFlags, &s))
344 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
346 DWORD err = GetLastError ();
347 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
352 *lphLookup = (HANDLE) s;
353 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
358 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
359 SetLastError (WSAEINVALIDPROVIDER);
363 #define UnmarshallPtr(ptr, ptrtype, base) \
365 ptr = (ptrtype *) (base + (uintptr_t) ptr)
368 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
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++)
383 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
384 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
386 UnmarshallPtr (req->lpBlob, BLOB, base);
388 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
392 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
393 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
395 DWORD effective_flags;
397 struct GNUNET_MessageHeader header = {0, 0};
404 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
405 //EnterCriticalSection (&records_cs);
406 for (i = 0; i < records_len; i++)
408 if (records[i].s == (SOCKET) hLookup)
416 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
417 SetLastError (WSA_INVALID_HANDLE);
418 //LeaveCriticalSection (&records_cs);
421 if (records[rec].state & 4)
423 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
424 SetLastError (WSA_E_NO_MORE);
425 //LeaveCriticalSection (&records_cs);
428 effective_flags = dwControlFlags & records[rec].flags;
429 if (records[rec].buf)
431 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
432 if (dwControlFlags & LUP_FLUSHCACHE)
434 free (records[rec].buf);
435 records[rec].buf = NULL;
439 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
441 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
442 SetLastError (WSAEFAULT);
443 //LeaveCriticalSection (&records_cs);
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");
455 records[rec].state |= 8;
456 //LeaveCriticalSection (&records_cs);
457 to_receive = sizeof (header);
459 while (to_receive > 0)
461 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
470 //EnterCriticalSection (&records_cs);
471 records[rec].state &= ~8;
472 if (rc != sizeof (header))
474 if (records[rec].state & 2)
476 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
477 SetLastError (WSA_E_CANCELLED);
481 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
482 SetLastError (WSA_E_NO_MORE);
484 records[rec].state |= 4;
485 //LeaveCriticalSection (&records_cs);
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)))
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);
501 buf = malloc (header.size);
504 records[rec].state |= 4;
505 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
506 //LeaveCriticalSection (&records_cs);
507 SetLastError (WSA_E_NO_MORE);
510 records[rec].state |= 8;
511 //LeaveCriticalSection (&records_cs);
512 memcpy (buf, &header, sizeof (header));
513 to_receive = header.size - sizeof (header);
515 while (to_receive > 0)
517 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
526 //EnterCriticalSection (&records_cs);
527 records[rec].state &= ~8;
528 if (rc != header.size - sizeof (header))
531 if (records[rec].state & 2)
533 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
534 SetLastError (WSA_E_CANCELLED);
538 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
539 SetLastError (WSA_E_NO_MORE);
541 records[rec].state |= 4;
542 //LeaveCriticalSection (&records_cs);
545 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
547 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
548 SetLastError (WSAEFAULT);
549 records[rec].buf = buf;
550 //LeaveCriticalSection (&records_cs);
553 //LeaveCriticalSection (&records_cs);
554 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
556 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
557 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
558 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
563 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
565 DWORD effective_flags;
567 struct GNUNET_MessageHeader header = {0, 0};
572 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
573 //EnterCriticalSection (&records_cs);
574 for (i = 0; i < records_len; i++)
576 if (records[i].s == (SOCKET) hLookup)
584 SetLastError (WSA_INVALID_HANDLE);
585 //LeaveCriticalSection (&records_cs);
586 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
589 records[rec].state |= 2;
590 closesocket (records[rec].s);
591 while (records[rec].state & 8)
593 //LeaveCriticalSection (&records_cs);
595 //EnterCriticalSection (&records_cs);
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");
609 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
610 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
611 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
613 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
614 SetLastError (WSAEOPNOTSUPP);
619 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
620 LPWSASERVICECLASSINFOW lpServiceClassInfo)
622 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
623 SetLastError (WSAEOPNOTSUPP);
629 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
631 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
632 SetLastError (WSAEOPNOTSUPP);
637 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
638 LPWSASERVICECLASSINFOW lpServiceClassInfo)
640 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
641 SetLastError (WSAEOPNOTSUPP);
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)
651 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
652 SetLastError (WSAEOPNOTSUPP);
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.
662 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
664 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
666 if (!connect_to_dns_resolver ())
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.
674 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
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;
690 SetLastError (WSAEINVALIDPROVIDER);