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.
17 * @brief W32 integration for GNS
20 /* This code is partially based upon samples from the book
21 * "Network Programming For Microsoft Windows, 2Nd Edition".
26 # define DEBUGLOG(s, ...)
29 # define __printf__ printf
30 # define DEBUGLOG(s, ...) printf (s, ##__VA_ARGS__)
43 #define __BYTE_ORDER _BYTE_ORDER
46 #define __BYTE_ORDER BYTE_ORDER
52 #define __BIG_ENDIAN _BIG_ENDIAN
55 #define __BIG_ENDIAN BIG_ENDIAN
59 #ifndef __LITTLE_ENDIAN
61 #define __LITTLE_ENDIAN _LITTLE_ENDIAN
64 #define __LITTLE_ENDIAN LITTLE_ENDIAN
68 #include "w32resolver.h"
70 #include "gnunet_w32nsp_lib.h"
73 #define NSPAPI_VERSION_MAJOR 4
74 #define NSPAPI_VERSION_MINOR 4
76 static CRITICAL_SECTION records_cs;
87 static struct record *records = NULL;
88 static size_t records_len = 0;
89 static size_t records_size = 0;
94 size_t new_size = records_len > 0 ? records_len * 2 : 5;
95 struct record *new_records = malloc (new_size * sizeof (struct record));
96 if (new_records == NULL)
98 SetLastError (WSA_NOT_ENOUGH_MEMORY);
101 GNUNET_memcpy (new_records, records, records_len * sizeof (struct record));
102 memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));
103 records_size = new_size;
105 records = new_records;
110 add_record (SOCKET s, const wchar_t *name, DWORD flags)
115 //EnterCriticalSection (&records_cs);
116 for (i = 0; i < records_len; i++)
117 if (records[i].state == 0)
120 if (i == records_len)
122 res = resize_records ();
124 empty = records_len++;
131 r.name = (wchar_t *) name;
135 r.name = wcsdup (name);
138 //LeaveCriticalSection (&records_cs);
142 /* These are not defined by mingw.org headers at the moment*/
143 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
144 typedef struct _NSP_ROUTINE_XP {
146 DWORD dwMajorVersion;
147 DWORD dwMinorVersion;
148 LPNSPCLEANUP NSPCleanup;
149 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
150 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
151 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
152 LPNSPSETSERVICE NSPSetService;
153 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
154 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
155 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
160 connect_to_dns_resolver ()
162 struct sockaddr_in addr;
166 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
167 if (INVALID_SOCKET == r)
169 SetLastError (16004);
173 addr.sin_family = AF_INET;
174 addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
175 addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
177 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
178 if (SOCKET_ERROR == ret)
180 DWORD err = GetLastError ();
183 SetLastError (16005);
190 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
191 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
194 struct GNUNET_W32RESOLVER_GetMessage *msg;
200 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
202 if (lpqsRestrictions->lpszServiceInstanceName)
203 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
206 msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
207 msg->header.size = htons (size);
208 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
209 if (lpqsRestrictions->dwNumberOfProtocols > 0)
212 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
214 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
216 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
221 msg->af = htonl (AF_INET);
222 else if (af6 && !af4)
223 msg->af = htonl (AF_INET6);
225 msg->af = htonl (AF_UNSPEC);
226 if (lpqsRestrictions->lpszServiceInstanceName)
227 GNUNET_memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
228 msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
229 msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
230 msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
231 for (i = 0; i < 8; i++)
232 msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
233 *resolver = connect_to_dns_resolver ();
234 if (*resolver != INVALID_SOCKET)
236 if (size != send (*resolver, buf, size, 0))
239 DWORD err = GetLastError ();
241 closesocket (*resolver);
242 *resolver = INVALID_SOCKET;
243 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
244 SetLastError (WSATRY_AGAIN);
255 NSPCleanup (LPGUID lpProviderId)
257 DEBUGLOG ("NSPCleanup\n");
258 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
262 SetLastError (WSAEINVALIDPROVIDER);
267 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
271 case DLL_PROCESS_ATTACH:
272 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
277 case DLL_THREAD_ATTACH:
279 case DLL_THREAD_DETACH:
281 case DLL_PROCESS_DETACH:
282 DeleteCriticalSection (&records_cs);
292 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
293 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
296 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
297 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
300 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
302 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
303 SetLastError (WSAEINVAL);
306 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
308 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
309 size_t len = wcslen (s);
310 if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
313 else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
318 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
319 SetLastError (WSAEINVAL);
324 if (send_name_to_ip_request (lpqsRestrictions,
325 lpServiceClassInfo, dwControlFlags, &s))
327 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
329 DWORD err = GetLastError ();
330 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
335 *lphLookup = (HANDLE) s;
336 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
341 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
342 SetLastError (WSAEINVALIDPROVIDER);
346 #define UnmarshallPtr(ptr, ptrtype, base) \
348 ptr = (ptrtype *) (base + (uintptr_t) ptr)
351 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
354 char *base = (char *) req;
355 UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
356 UnmarshallPtr (req->lpServiceClassId, GUID, base);
357 UnmarshallPtr (req->lpVersion, WSAVERSION, base);
358 UnmarshallPtr (req->lpszComment, wchar_t, base);
359 UnmarshallPtr (req->lpNSProviderId, GUID, base);
360 UnmarshallPtr (req->lpszContext, wchar_t, base);
361 UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
362 UnmarshallPtr (req->lpszQueryString, wchar_t, base);
363 UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
364 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
366 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
367 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
369 UnmarshallPtr (req->lpBlob, BLOB, base);
371 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
375 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
376 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
378 /*DWORD effective_flags;*/
380 struct GNUNET_MessageHeader header = {0, 0};
387 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
388 //EnterCriticalSection (&records_cs);
389 for (i = 0; i < records_len; i++)
391 if (records[i].s == (SOCKET) hLookup)
399 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
400 SetLastError (WSA_INVALID_HANDLE);
401 //LeaveCriticalSection (&records_cs);
404 if (records[rec].state & 4)
406 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
407 SetLastError (WSA_E_NO_MORE);
408 //LeaveCriticalSection (&records_cs);
411 /*effective_flags = dwControlFlags & records[rec].flags;*/
412 if (records[rec].buf)
414 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: checking buffer\n");
415 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
416 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
418 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
419 SetLastError (WSAEFAULT);
420 //LeaveCriticalSection (&records_cs);
423 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
424 free (records[rec].buf);
425 records[rec].buf = NULL;
426 //LeaveCriticalSection (&records_cs);
427 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
428 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
431 records[rec].state |= 8;
432 //LeaveCriticalSection (&records_cs);
433 to_receive = sizeof (header);
438 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
439 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a header from %p, %lu bytes available\n", to_receive, hLookup, have);
442 while (to_receive > 0)
444 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
456 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
457 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a header from %p, %lu bytes available\n", rc, hLookup, have);
460 //EnterCriticalSection (&records_cs);
461 records[rec].state &= ~8;
462 if (rc != sizeof (header))
464 if (records[rec].state & 2)
466 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
467 SetLastError (WSA_E_CANCELLED);
471 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);
472 SetLastError (WSA_E_NO_MORE);
474 records[rec].state |= 4;
475 //LeaveCriticalSection (&records_cs);
478 records[rec].state &= ~8;
479 header.type = ntohs (header.type);
480 header.size = ntohs (header.size);
481 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type %d, header size %u\n", header.type, header.size);
482 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
483 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
484 header.size == sizeof (header)))
486 records[rec].state |= 4;
487 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE)
488 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type is wrong\n");
490 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: empty header - no data\n");
491 //LeaveCriticalSection (&records_cs);
492 SetLastError (WSA_E_NO_MORE);
495 buf = malloc (header.size);
498 records[rec].state |= 4;
499 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
500 //LeaveCriticalSection (&records_cs);
501 SetLastError (WSA_E_NO_MORE);
504 records[rec].state |= 8;
505 //LeaveCriticalSection (&records_cs);
506 GNUNET_memcpy (buf, &header, sizeof (header));
507 to_receive = header.size - sizeof (header);
512 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
513 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a body from %p, %lu bytes available\n", to_receive, hLookup, have);
516 while (to_receive > 0)
518 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv (%d)\n", to_receive);
519 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
520 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv returned %d\n", t);
532 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
533 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a body from %p, %lu bytes available\n", rc, hLookup, have);
536 //EnterCriticalSection (&records_cs);
537 records[rec].state &= ~8;
538 if (rc != header.size - sizeof (header))
541 if (records[rec].state & 2)
543 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
544 SetLastError (WSA_E_CANCELLED);
548 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);
549 SetLastError (WSA_E_NO_MORE);
551 records[rec].state |= 4;
552 //LeaveCriticalSection (&records_cs);
555 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
557 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
558 SetLastError (WSAEFAULT);
559 records[rec].buf = buf;
560 //LeaveCriticalSection (&records_cs);
563 //LeaveCriticalSection (&records_cs);
564 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: writing %d bytes into result buffer\n", header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
565 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
567 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
568 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
569 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
574 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
579 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
580 //EnterCriticalSection (&records_cs);
581 for (i = 0; i < records_len; i++)
583 if (records[i].s == (SOCKET) hLookup)
591 SetLastError (WSA_INVALID_HANDLE);
592 //LeaveCriticalSection (&records_cs);
593 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
596 records[rec].state |= 2;
597 closesocket (records[rec].s);
598 while (records[rec].state & 8)
600 //LeaveCriticalSection (&records_cs);
602 //EnterCriticalSection (&records_cs);
604 if (records[rec].buf)
605 free (records[rec].buf);
606 records[rec].buf = NULL;
607 records[rec].state = 0;
608 if (records[rec].name)
609 free (records[rec].name);
610 //LeaveCriticalSection (&records_cs);
611 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
616 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
617 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
618 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
620 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
621 SetLastError (WSAEOPNOTSUPP);
626 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
627 LPWSASERVICECLASSINFOW lpServiceClassInfo)
629 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
630 SetLastError (WSAEOPNOTSUPP);
636 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
638 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
639 SetLastError (WSAEOPNOTSUPP);
644 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
645 LPWSASERVICECLASSINFOW lpServiceClassInfo)
647 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
648 SetLastError (WSAEOPNOTSUPP);
653 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
654 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
655 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
656 LPWSATHREADID lpThreadId)
658 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
659 SetLastError (WSAEOPNOTSUPP);
664 * This function is called by Winsock to hook up our provider.
665 * It is the only function that [should be/is] exported by the
666 * provider. All other routines are passed as pointers in lpnspRoutines.
669 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
671 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
673 if (!connect_to_dns_resolver ())
677 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
678 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
679 * and use that offset as cbSize.
681 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
683 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
684 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
685 lpnspRoutines->NSPCleanup = NSPCleanup;
686 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
687 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
688 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
689 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
690 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
691 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
692 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
693 /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
694 lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
697 SetLastError (WSAEINVALIDPROVIDER);