2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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".
31 # define DEBUGLOG(s, ...)
34 # define __printf__ printf
35 # define DEBUGLOG(s, ...) printf(s, ## __VA_ARGS__)
48 #define __BYTE_ORDER _BYTE_ORDER
51 #define __BYTE_ORDER BYTE_ORDER
57 #define __BIG_ENDIAN _BIG_ENDIAN
60 #define __BIG_ENDIAN BIG_ENDIAN
64 #ifndef __LITTLE_ENDIAN
66 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
69 #define __LITTLE_ENDIAN LITTLE_ENDIAN
73 #include "w32resolver.h"
75 #include "gnunet_w32nsp_lib.h"
78 #define NSPAPI_VERSION_MAJOR 4
79 #define NSPAPI_VERSION_MINOR 4
81 static CRITICAL_SECTION records_cs;
91 static struct record *records = NULL;
92 static size_t records_len = 0;
93 static size_t records_size = 0;
98 size_t new_size = records_len > 0 ? records_len * 2 : 5;
99 struct record *new_records = malloc(new_size * sizeof(struct record));
101 if (new_records == NULL)
103 SetLastError(WSA_NOT_ENOUGH_MEMORY);
106 GNUNET_memcpy(new_records, records, records_len * sizeof(struct record));
107 memset(&new_records[records_len], 0, sizeof(struct record) * (new_size - records_len));
108 records_size = new_size;
110 records = new_records;
115 add_record(SOCKET s, const wchar_t *name, DWORD flags)
121 //EnterCriticalSection (&records_cs);
122 for (i = 0; i < records_len; i++)
123 if (records[i].state == 0)
126 if (i == records_len)
128 res = resize_records();
130 empty = records_len++;
137 r.name = (wchar_t *)name;
141 r.name = wcsdup(name);
144 //LeaveCriticalSection (&records_cs);
148 /* These are not defined by mingw.org headers at the moment*/
149 typedef INT (WSPAPI *LPNSPIOCTL)(HANDLE, DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPWSACOMPLETION, LPWSATHREADID);
150 typedef struct _NSP_ROUTINE_XP {
152 DWORD dwMajorVersion;
153 DWORD dwMinorVersion;
154 LPNSPCLEANUP NSPCleanup;
155 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
156 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
157 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
158 LPNSPSETSERVICE NSPSetService;
159 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
160 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
161 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
166 connect_to_dns_resolver()
168 struct sockaddr_in addr;
172 r = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
173 if (INVALID_SOCKET == r)
179 addr.sin_family = AF_INET;
180 addr.sin_port = htons(5353); /* TCP 5353 is not registered; UDP 5353 is */
181 addr.sin_addr.s_addr = inet_addr("127.0.0.1");
183 ret = connect(r, (struct sockaddr *)&addr, sizeof(addr));
184 if (SOCKET_ERROR == ret)
186 DWORD err = GetLastError();
196 send_name_to_ip_request(LPWSAQUERYSETW lpqsRestrictions,
197 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
200 struct GNUNET_W32RESOLVER_GetMessage *msg;
206 size_t size = sizeof(struct GNUNET_W32RESOLVER_GetMessage);
209 if (lpqsRestrictions->lpszServiceInstanceName)
210 namelen = sizeof(wchar_t) * (wcslen(lpqsRestrictions->lpszServiceInstanceName) + 1);
213 msg = (struct GNUNET_W32RESOLVER_GetMessage *)buf;
214 msg->header.size = htons(size);
215 msg->header.type = htons(GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
216 if (lpqsRestrictions->dwNumberOfProtocols > 0)
219 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
221 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
223 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
228 msg->af = htonl(AF_INET);
229 else if (af6 && !af4)
230 msg->af = htonl(AF_INET6);
232 msg->af = htonl(AF_UNSPEC);
233 if (lpqsRestrictions->lpszServiceInstanceName)
234 GNUNET_memcpy(&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
235 msg->sc_data1 = htonl(lpqsRestrictions->lpServiceClassId->Data1);
236 msg->sc_data2 = htons(lpqsRestrictions->lpServiceClassId->Data2);
237 msg->sc_data3 = htons(lpqsRestrictions->lpServiceClassId->Data3);
238 for (i = 0; i < 8; i++)
239 msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
240 *resolver = connect_to_dns_resolver();
241 if (*resolver != INVALID_SOCKET)
243 if (size != send(*resolver, buf, size, 0))
246 DWORD err = GetLastError();
248 closesocket(*resolver);
249 *resolver = INVALID_SOCKET;
250 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
251 SetLastError(WSATRY_AGAIN);
262 NSPCleanup(LPGUID lpProviderId)
264 DEBUGLOG("NSPCleanup\n");
265 if (IsEqualGUID(lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
269 SetLastError(WSAEINVALIDPROVIDER);
274 DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
278 case DLL_PROCESS_ATTACH:
279 if (!InitializeCriticalSectionAndSpinCount(&records_cs, 0x00000400))
285 case DLL_THREAD_ATTACH:
288 case DLL_THREAD_DETACH:
291 case DLL_PROCESS_DETACH:
292 DeleteCriticalSection(&records_cs);
302 GNUNET_W32NSP_LookupServiceBegin(LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
303 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
306 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin\n");
307 if (IsEqualGUID(lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
310 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
312 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
313 SetLastError(WSAEINVAL);
316 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
318 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
319 size_t len = wcslen(s);
320 if (len >= 5 && wcscmp(&s[len - 5], L".zkey") == 0)
323 else if (len >= 4 && wcscmp(&s[len - 4], L".gnu") == 0)
328 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
329 SetLastError(WSAEINVAL);
334 if (send_name_to_ip_request(lpqsRestrictions,
335 lpServiceClassInfo, dwControlFlags, &s))
337 if (!(add_record(s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
339 DWORD err = GetLastError();
340 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
345 *lphLookup = (HANDLE)s;
346 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError());
351 DEBUGLOG("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
352 SetLastError(WSAEINVALIDPROVIDER);
356 #define UnmarshallPtr(ptr, ptrtype, base) \
358 ptr = (ptrtype *) (base + (uintptr_t)ptr)
361 UnmarshallWSAQUERYSETW(LPWSAQUERYSETW req)
364 char *base = (char *)req;
366 UnmarshallPtr(req->lpszServiceInstanceName, wchar_t, base);
367 UnmarshallPtr(req->lpServiceClassId, GUID, base);
368 UnmarshallPtr(req->lpVersion, WSAVERSION, base);
369 UnmarshallPtr(req->lpszComment, wchar_t, base);
370 UnmarshallPtr(req->lpNSProviderId, GUID, base);
371 UnmarshallPtr(req->lpszContext, wchar_t, base);
372 UnmarshallPtr(req->lpafpProtocols, AFPROTOCOLS, base);
373 UnmarshallPtr(req->lpszQueryString, wchar_t, base);
374 UnmarshallPtr(req->lpcsaBuffer, CSADDR_INFO, base);
375 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
377 UnmarshallPtr(req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
378 UnmarshallPtr(req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
380 UnmarshallPtr(req->lpBlob, BLOB, base);
382 UnmarshallPtr(req->lpBlob->pBlobData, BYTE, base);
386 GNUNET_W32NSP_LookupServiceNext(HANDLE hLookup, DWORD dwControlFlags,
387 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
389 /*DWORD effective_flags;*/
391 struct GNUNET_MessageHeader header = { 0, 0 };
398 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext\n");
399 //EnterCriticalSection (&records_cs);
400 for (i = 0; i < records_len; i++)
402 if (records[i].s == (SOCKET)hLookup)
410 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
411 SetLastError(WSA_INVALID_HANDLE);
412 //LeaveCriticalSection (&records_cs);
415 if (records[rec].state & 4)
417 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
418 SetLastError(WSA_E_NO_MORE);
419 //LeaveCriticalSection (&records_cs);
422 /*effective_flags = dwControlFlags & records[rec].flags;*/
423 if (records[rec].buf)
425 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: checking buffer\n");
426 header = *((struct GNUNET_MessageHeader *)records[rec].buf);
427 if (*lpdwBufferLength < header.size - sizeof(struct GNUNET_W32RESOLVER_GetMessage))
429 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
430 SetLastError(WSAEFAULT);
431 //LeaveCriticalSection (&records_cs);
434 GNUNET_memcpy(lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof(struct GNUNET_W32RESOLVER_GetMessage));
435 free(records[rec].buf);
436 records[rec].buf = NULL;
437 //LeaveCriticalSection (&records_cs);
438 UnmarshallWSAQUERYSETW((LPWSAQUERYSETW)lpqsResults);
439 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
442 records[rec].state |= 8;
443 //LeaveCriticalSection (&records_cs);
444 to_receive = sizeof(header);
449 int ior = ioctlsocket((SOCKET)hLookup, FIONREAD, &have);
450 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a header from %p, %lu bytes available\n", to_receive, hLookup, have);
453 while (to_receive > 0)
455 t = recv((SOCKET)hLookup, &((char *)&header)[rc], to_receive, 0);
467 int ior = ioctlsocket((SOCKET)hLookup, FIONREAD, &have);
468 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a header from %p, %lu bytes available\n", rc, hLookup, have);
471 //EnterCriticalSection (&records_cs);
472 records[rec].state &= ~8;
473 if (rc != sizeof(header))
475 if (records[rec].state & 2)
477 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
478 SetLastError(WSA_E_CANCELLED);
482 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data for a header (rc %d != %u, state is 0x%0X)\n", rc, sizeof(header), records[rec].state);
483 SetLastError(WSA_E_NO_MORE);
485 records[rec].state |= 4;
486 //LeaveCriticalSection (&records_cs);
489 records[rec].state &= ~8;
490 header.type = ntohs(header.type);
491 header.size = ntohs(header.size);
492 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: header type %d, header size %u\n", header.type, header.size);
493 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
494 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
495 header.size == sizeof(header)))
497 records[rec].state |= 4;
498 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE)
499 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: header type is wrong\n");
501 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: empty header - no data\n");
502 //LeaveCriticalSection (&records_cs);
503 SetLastError(WSA_E_NO_MORE);
506 buf = malloc(header.size);
509 records[rec].state |= 4;
510 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
511 //LeaveCriticalSection (&records_cs);
512 SetLastError(WSA_E_NO_MORE);
515 records[rec].state |= 8;
516 //LeaveCriticalSection (&records_cs);
517 GNUNET_memcpy(buf, &header, sizeof(header));
518 to_receive = header.size - sizeof(header);
523 int ior = ioctlsocket((SOCKET)hLookup, FIONREAD, &have);
524 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a body from %p, %lu bytes available\n", to_receive, hLookup, have);
527 while (to_receive > 0)
529 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: recv (%d)\n", to_receive);
530 t = recv((SOCKET)hLookup, &((char *)&((struct GNUNET_MessageHeader *)buf)[1])[rc], to_receive, 0);
531 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: recv returned %d\n", t);
543 int ior = ioctlsocket((SOCKET)hLookup, FIONREAD, &have);
544 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a body from %p, %lu bytes available\n", rc, hLookup, have);
547 //EnterCriticalSection (&records_cs);
548 records[rec].state &= ~8;
549 if (rc != header.size - sizeof(header))
552 if (records[rec].state & 2)
554 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
555 SetLastError(WSA_E_CANCELLED);
559 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: failed to receive enough data for the rest (rc %d != %d, state is 0x%0X)\n", rc, header.size - sizeof(header), records[rec].state);
560 SetLastError(WSA_E_NO_MORE);
562 records[rec].state |= 4;
563 //LeaveCriticalSection (&records_cs);
566 if (*lpdwBufferLength < header.size - sizeof(struct GNUNET_W32RESOLVER_GetMessage))
568 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
569 SetLastError(WSAEFAULT);
570 records[rec].buf = buf;
571 //LeaveCriticalSection (&records_cs);
574 //LeaveCriticalSection (&records_cs);
575 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: writing %d bytes into result buffer\n", header.size - sizeof(struct GNUNET_W32RESOLVER_GetMessage));
576 GNUNET_memcpy(lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof(struct GNUNET_W32RESOLVER_GetMessage));
578 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: OK\n");
579 UnmarshallWSAQUERYSETW((LPWSAQUERYSETW)lpqsResults);
580 DEBUGLOG("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError());
585 GNUNET_W32NSP_LookupServiceEnd(HANDLE hLookup)
590 DEBUGLOG("GNUNET_W32NSP_LookupServiceEnd\n");
591 //EnterCriticalSection (&records_cs);
592 for (i = 0; i < records_len; i++)
594 if (records[i].s == (SOCKET)hLookup)
602 SetLastError(WSA_INVALID_HANDLE);
603 //LeaveCriticalSection (&records_cs);
604 DEBUGLOG("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
607 records[rec].state |= 2;
608 closesocket(records[rec].s);
609 while (records[rec].state & 8)
611 //LeaveCriticalSection (&records_cs);
613 //EnterCriticalSection (&records_cs);
615 if (records[rec].buf)
616 free(records[rec].buf);
617 records[rec].buf = NULL;
618 records[rec].state = 0;
619 if (records[rec].name)
620 free(records[rec].name);
621 //LeaveCriticalSection (&records_cs);
622 DEBUGLOG("GNUNET_W32NSP_LookupServiceEnd: OK\n");
627 GNUNET_W32NSP_SetService(LPGUID lpProviderId,
628 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
629 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
631 DEBUGLOG("GNUNET_W32NSP_SetService\n");
632 SetLastError(WSAEOPNOTSUPP);
637 GNUNET_W32NSP_InstallServiceClass(LPGUID lpProviderId,
638 LPWSASERVICECLASSINFOW lpServiceClassInfo)
640 DEBUGLOG("GNUNET_W32NSP_InstallServiceClass\n");
641 SetLastError(WSAEOPNOTSUPP);
647 GNUNET_W32NSP_RemoveServiceClass(LPGUID lpProviderId, LPGUID lpServiceClassId)
649 DEBUGLOG("GNUNET_W32NSP_RemoveServiceClass\n");
650 SetLastError(WSAEOPNOTSUPP);
655 GNUNET_W32NSP_GetServiceClassInfo(LPGUID lpProviderId, LPDWORD lpdwBufSize,
656 LPWSASERVICECLASSINFOW lpServiceClassInfo)
658 DEBUGLOG("GNUNET_W32NSP_GetServiceClassInfo\n");
659 SetLastError(WSAEOPNOTSUPP);
664 GNUNET_W32NSP_Ioctl(HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
665 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
666 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
667 LPWSATHREADID lpThreadId)
669 DEBUGLOG("GNUNET_W32NSP_Ioctl\n");
670 SetLastError(WSAEOPNOTSUPP);
675 * This function is called by Winsock to hook up our provider.
676 * It is the only function that [should be/is] exported by the
677 * provider. All other routines are passed as pointers in lpnspRoutines.
680 GNUNET_W32NSP_NSPStartup(LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
682 if (IsEqualGUID(lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
684 if (!connect_to_dns_resolver())
688 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
689 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
690 * and use that offset as cbSize.
692 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
694 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
695 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
696 lpnspRoutines->NSPCleanup = NSPCleanup;
697 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
698 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
699 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
700 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
701 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
702 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
703 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
704 /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
705 lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
708 SetLastError(WSAEINVALIDPROVIDER);