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".
37 # define DEBUGLOG(s, ...)
40 # define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)
47 #define __BYTE_ORDER _BYTE_ORDER
50 #define __BYTE_ORDER BYTE_ORDER
56 #define __BIG_ENDIAN _BIG_ENDIAN
59 #define __BIG_ENDIAN BIG_ENDIAN
63 #ifndef __LITTLE_ENDIAN
65 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
68 #define __LITTLE_ENDIAN LITTLE_ENDIAN
72 #include "gnunet_w32nsp_lib.h"
73 #include "w32resolver.h"
75 #define NSPAPI_VERSION_MAJOR 4
76 #define NSPAPI_VERSION_MINOR 4
78 #define REPLY_LIFETIME 60*5
80 #define STATE_BEGIN 0x01
81 #define STATE_END 0x02
82 #define STATE_REPLY 0x04
83 #define STATE_GHBN 0x08
86 GNUNET_htonll (uint64_t n)
88 #if __BYTE_ORDER == __BIG_ENDIAN
90 #elif __BYTE_ORDER == __LITTLE_ENDIAN
91 return (((uint64_t) htonl (n)) << 32) + htonl (n >> 32);
93 #error byteorder undefined
97 CRITICAL_SECTION records_cs;
108 static struct record *records = NULL;
109 static size_t records_len = 0;
110 static size_t records_size = 0;
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)
119 SetLastError (WSA_NOT_ENOUGH_MEMORY);
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;
126 records = new_records;
131 add_record (SOCKET s, const wchar_t *name, DWORD flags)
136 //EnterCriticalSection (&records_cs);
137 for (i = 0; i < records_len; i++)
138 if (records[i].state == 0)
141 if (i == records_len)
143 res = resize_records ();
145 empty = records_len++;
152 r.name = (wchar_t *) name;
156 r.name = wcsdup (name);
159 //LeaveCriticalSection (&records_cs);
167 free (records[i].name);
168 records[i].state = 0;
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 {
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;
189 connect_to_dns_resolver ()
191 struct sockaddr_in addr;
195 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
196 if (INVALID_SOCKET == r)
198 SetLastError (16004);
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");
206 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
207 if (SOCKET_ERROR == ret)
209 DWORD err = GetLastError ();
212 SetLastError (16005);
219 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
220 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
223 struct GNUNET_W32RESOLVER_GetMessage *msg;
230 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
232 if (lpqsRestrictions->lpszServiceInstanceName)
233 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
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)
242 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
244 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
246 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
251 msg->af = htonl (AF_INET);
252 else if (af6 && !af4)
253 msg->af = htonl (AF_INET6);
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);
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)
268 if (size != send (*resolver, buf, size, 0))
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);
285 NSPCleanup (LPGUID lpProviderId)
287 DEBUGLOG ("NSPCleanup\n");
288 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
292 SetLastError (WSAEINVALIDPROVIDER);
297 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
301 case DLL_PROCESS_ATTACH:
302 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
307 case DLL_THREAD_ATTACH:
309 case DLL_THREAD_DETACH:
311 case DLL_PROCESS_DETACH:
312 DeleteCriticalSection (&records_cs);
322 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
323 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
326 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
327 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
330 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
332 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
333 SetLastError (WSANO_DATA);
336 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
338 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
339 size_t len = wcslen (s);
340 if (len >= 4 && wcscmp (&s[len - 4], L"zkey") == 0)
343 else if (len >= 4 && wcscmp (&s[len - 4], L"gnu") == 0)
348 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
349 SetLastError (WSANO_DATA);
354 if (send_name_to_ip_request (lpqsRestrictions,
355 lpServiceClassInfo, dwControlFlags, &s))
357 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
359 DWORD err = GetLastError ();
360 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
365 *lphLookup = (HANDLE) s;
366 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
371 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
372 SetLastError (WSAEINVALIDPROVIDER);
376 #define UnmarshallPtr(ptr, ptrtype, base) \
378 ptr = (ptrtype *) (base + (uintptr_t) ptr)
381 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
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++)
396 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
397 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
399 UnmarshallPtr (req->lpBlob, BLOB, base);
401 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
405 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
406 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
408 DWORD effective_flags;
410 struct GNUNET_MessageHeader header = {0, 0};
417 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
418 //EnterCriticalSection (&records_cs);
419 for (i = 0; i < records_len; i++)
421 if (records[i].s == (SOCKET) hLookup)
429 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
430 SetLastError (WSA_INVALID_HANDLE);
431 //LeaveCriticalSection (&records_cs);
434 if (records[rec].state & 4)
436 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
437 SetLastError (WSA_E_NO_MORE);
438 //LeaveCriticalSection (&records_cs);
441 effective_flags = dwControlFlags & records[rec].flags;
442 if (records[rec].buf)
444 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
445 if (dwControlFlags & LUP_FLUSHCACHE)
447 free (records[rec].buf);
448 records[rec].buf = NULL;
452 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
454 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
455 SetLastError (WSAEFAULT);
456 //LeaveCriticalSection (&records_cs);
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");
468 records[rec].state |= 8;
469 //LeaveCriticalSection (&records_cs);
470 to_receive = sizeof (header);
472 while (to_receive > 0)
474 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
483 //EnterCriticalSection (&records_cs);
484 records[rec].state &= ~8;
485 if (rc != sizeof (header))
487 if (records[rec].state & 2)
489 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
490 SetLastError (WSA_E_CANCELLED);
494 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
495 SetLastError (WSA_E_NO_MORE);
497 records[rec].state |= 4;
498 //LeaveCriticalSection (&records_cs);
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)))
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);
514 buf = malloc (header.size);
517 records[rec].state |= 4;
518 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
519 //LeaveCriticalSection (&records_cs);
520 SetLastError (WSA_E_NO_MORE);
523 records[rec].state |= 8;
524 //LeaveCriticalSection (&records_cs);
525 memcpy (buf, &header, sizeof (header));
526 to_receive = header.size - sizeof (header);
528 while (to_receive > 0)
530 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
539 //EnterCriticalSection (&records_cs);
540 records[rec].state &= ~8;
541 if (rc != header.size - sizeof (header))
544 if (records[rec].state & 2)
546 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
547 SetLastError (WSA_E_CANCELLED);
551 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data\n");
552 SetLastError (WSA_E_NO_MORE);
554 records[rec].state |= 4;
555 //LeaveCriticalSection (&records_cs);
558 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
560 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
561 SetLastError (WSAEFAULT);
562 records[rec].buf = buf;
563 //LeaveCriticalSection (&records_cs);
566 //LeaveCriticalSection (&records_cs);
567 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
569 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
570 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
571 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
576 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
578 DWORD effective_flags;
580 struct GNUNET_MessageHeader header = {0, 0};
585 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
586 //EnterCriticalSection (&records_cs);
587 for (i = 0; i < records_len; i++)
589 if (records[i].s == (SOCKET) hLookup)
597 SetLastError (WSA_INVALID_HANDLE);
598 //LeaveCriticalSection (&records_cs);
599 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
602 records[rec].state |= 2;
603 closesocket (records[rec].s);
604 while (records[rec].state & 8)
606 //LeaveCriticalSection (&records_cs);
608 //EnterCriticalSection (&records_cs);
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");
622 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
623 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
624 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
626 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
627 SetLastError (WSAEOPNOTSUPP);
632 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
633 LPWSASERVICECLASSINFOW lpServiceClassInfo)
635 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
636 SetLastError (WSAEOPNOTSUPP);
642 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
644 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
645 SetLastError (WSAEOPNOTSUPP);
650 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
651 LPWSASERVICECLASSINFOW lpServiceClassInfo)
653 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
654 SetLastError (WSAEOPNOTSUPP);
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)
664 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
665 SetLastError (WSAEOPNOTSUPP);
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.
675 NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
677 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
679 if (!connect_to_dns_resolver ())
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.
687 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE_XP);
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;
702 SetLastError (WSAEINVALIDPROVIDER);