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/>.
20 * @brief W32 integration for GNS
23 /* This code is partially based upon samples from the book
24 * "Network Programming For Microsoft Windows, 2Nd Edition".
29 # define DEBUGLOG(s, ...)
32 # define __printf__ printf
33 # 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 static CRITICAL_SECTION records_cs;
90 static struct record *records = NULL;
91 static size_t records_len = 0;
92 static size_t records_size = 0;
97 size_t new_size = records_len > 0 ? records_len * 2 : 5;
98 struct record *new_records = malloc (new_size * sizeof (struct record));
99 if (new_records == NULL)
101 SetLastError (WSA_NOT_ENOUGH_MEMORY);
104 GNUNET_memcpy (new_records, records, records_len * sizeof (struct record));
105 memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));
106 records_size = new_size;
108 records = new_records;
113 add_record (SOCKET s, const wchar_t *name, DWORD flags)
118 //EnterCriticalSection (&records_cs);
119 for (i = 0; i < records_len; i++)
120 if (records[i].state == 0)
123 if (i == records_len)
125 res = resize_records ();
127 empty = records_len++;
134 r.name = (wchar_t *) name;
138 r.name = wcsdup (name);
141 //LeaveCriticalSection (&records_cs);
145 /* These are not defined by mingw.org headers at the moment*/
146 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
147 typedef struct _NSP_ROUTINE_XP {
149 DWORD dwMajorVersion;
150 DWORD dwMinorVersion;
151 LPNSPCLEANUP NSPCleanup;
152 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
153 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
154 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
155 LPNSPSETSERVICE NSPSetService;
156 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
157 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
158 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
163 connect_to_dns_resolver ()
165 struct sockaddr_in addr;
169 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
170 if (INVALID_SOCKET == r)
172 SetLastError (16004);
176 addr.sin_family = AF_INET;
177 addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
178 addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
180 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
181 if (SOCKET_ERROR == ret)
183 DWORD err = GetLastError ();
186 SetLastError (16005);
193 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
194 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
197 struct GNUNET_W32RESOLVER_GetMessage *msg;
203 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
205 if (lpqsRestrictions->lpszServiceInstanceName)
206 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
209 msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
210 msg->header.size = htons (size);
211 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
212 if (lpqsRestrictions->dwNumberOfProtocols > 0)
215 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
217 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
219 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
224 msg->af = htonl (AF_INET);
225 else if (af6 && !af4)
226 msg->af = htonl (AF_INET6);
228 msg->af = htonl (AF_UNSPEC);
229 if (lpqsRestrictions->lpszServiceInstanceName)
230 GNUNET_memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
231 msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
232 msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
233 msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
234 for (i = 0; i < 8; i++)
235 msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
236 *resolver = connect_to_dns_resolver ();
237 if (*resolver != INVALID_SOCKET)
239 if (size != send (*resolver, buf, size, 0))
242 DWORD err = GetLastError ();
244 closesocket (*resolver);
245 *resolver = INVALID_SOCKET;
246 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
247 SetLastError (WSATRY_AGAIN);
258 NSPCleanup (LPGUID lpProviderId)
260 DEBUGLOG ("NSPCleanup\n");
261 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
265 SetLastError (WSAEINVALIDPROVIDER);
270 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
274 case DLL_PROCESS_ATTACH:
275 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
280 case DLL_THREAD_ATTACH:
282 case DLL_THREAD_DETACH:
284 case DLL_PROCESS_DETACH:
285 DeleteCriticalSection (&records_cs);
295 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
296 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
299 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
300 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
303 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
305 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
306 SetLastError (WSAEINVAL);
309 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
311 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
312 size_t len = wcslen (s);
313 if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
316 else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
321 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
322 SetLastError (WSAEINVAL);
327 if (send_name_to_ip_request (lpqsRestrictions,
328 lpServiceClassInfo, dwControlFlags, &s))
330 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
332 DWORD err = GetLastError ();
333 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
338 *lphLookup = (HANDLE) s;
339 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
344 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
345 SetLastError (WSAEINVALIDPROVIDER);
349 #define UnmarshallPtr(ptr, ptrtype, base) \
351 ptr = (ptrtype *) (base + (uintptr_t) ptr)
354 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
357 char *base = (char *) req;
358 UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
359 UnmarshallPtr (req->lpServiceClassId, GUID, base);
360 UnmarshallPtr (req->lpVersion, WSAVERSION, base);
361 UnmarshallPtr (req->lpszComment, wchar_t, base);
362 UnmarshallPtr (req->lpNSProviderId, GUID, base);
363 UnmarshallPtr (req->lpszContext, wchar_t, base);
364 UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
365 UnmarshallPtr (req->lpszQueryString, wchar_t, base);
366 UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
367 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
369 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
370 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
372 UnmarshallPtr (req->lpBlob, BLOB, base);
374 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
378 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
379 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
381 /*DWORD effective_flags;*/
383 struct GNUNET_MessageHeader header = {0, 0};
390 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
391 //EnterCriticalSection (&records_cs);
392 for (i = 0; i < records_len; i++)
394 if (records[i].s == (SOCKET) hLookup)
402 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
403 SetLastError (WSA_INVALID_HANDLE);
404 //LeaveCriticalSection (&records_cs);
407 if (records[rec].state & 4)
409 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
410 SetLastError (WSA_E_NO_MORE);
411 //LeaveCriticalSection (&records_cs);
414 /*effective_flags = dwControlFlags & records[rec].flags;*/
415 if (records[rec].buf)
417 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: checking buffer\n");
418 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
419 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
421 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
422 SetLastError (WSAEFAULT);
423 //LeaveCriticalSection (&records_cs);
426 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
427 free (records[rec].buf);
428 records[rec].buf = NULL;
429 //LeaveCriticalSection (&records_cs);
430 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
431 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
434 records[rec].state |= 8;
435 //LeaveCriticalSection (&records_cs);
436 to_receive = sizeof (header);
441 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
442 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a header from %p, %lu bytes available\n", to_receive, hLookup, have);
445 while (to_receive > 0)
447 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
459 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
460 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a header from %p, %lu bytes available\n", rc, hLookup, have);
463 //EnterCriticalSection (&records_cs);
464 records[rec].state &= ~8;
465 if (rc != sizeof (header))
467 if (records[rec].state & 2)
469 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
470 SetLastError (WSA_E_CANCELLED);
474 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);
475 SetLastError (WSA_E_NO_MORE);
477 records[rec].state |= 4;
478 //LeaveCriticalSection (&records_cs);
481 records[rec].state &= ~8;
482 header.type = ntohs (header.type);
483 header.size = ntohs (header.size);
484 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type %d, header size %u\n", header.type, header.size);
485 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
486 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
487 header.size == sizeof (header)))
489 records[rec].state |= 4;
490 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE)
491 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type is wrong\n");
493 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: empty header - no data\n");
494 //LeaveCriticalSection (&records_cs);
495 SetLastError (WSA_E_NO_MORE);
498 buf = malloc (header.size);
501 records[rec].state |= 4;
502 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
503 //LeaveCriticalSection (&records_cs);
504 SetLastError (WSA_E_NO_MORE);
507 records[rec].state |= 8;
508 //LeaveCriticalSection (&records_cs);
509 GNUNET_memcpy (buf, &header, sizeof (header));
510 to_receive = header.size - sizeof (header);
515 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
516 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a body from %p, %lu bytes available\n", to_receive, hLookup, have);
519 while (to_receive > 0)
521 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv (%d)\n", to_receive);
522 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
523 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv returned %d\n", t);
535 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
536 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a body from %p, %lu bytes available\n", rc, hLookup, have);
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 for the rest (rc %d != %d, state is 0x%0X)\n", rc, header.size - sizeof (header), records[rec].state);
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 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: writing %d bytes into result buffer\n", header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
568 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
570 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
571 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
572 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
577 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
582 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
583 //EnterCriticalSection (&records_cs);
584 for (i = 0; i < records_len; i++)
586 if (records[i].s == (SOCKET) hLookup)
594 SetLastError (WSA_INVALID_HANDLE);
595 //LeaveCriticalSection (&records_cs);
596 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
599 records[rec].state |= 2;
600 closesocket (records[rec].s);
601 while (records[rec].state & 8)
603 //LeaveCriticalSection (&records_cs);
605 //EnterCriticalSection (&records_cs);
607 if (records[rec].buf)
608 free (records[rec].buf);
609 records[rec].buf = NULL;
610 records[rec].state = 0;
611 if (records[rec].name)
612 free (records[rec].name);
613 //LeaveCriticalSection (&records_cs);
614 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
619 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
620 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
621 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
623 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
624 SetLastError (WSAEOPNOTSUPP);
629 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
630 LPWSASERVICECLASSINFOW lpServiceClassInfo)
632 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
633 SetLastError (WSAEOPNOTSUPP);
639 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
641 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
642 SetLastError (WSAEOPNOTSUPP);
647 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
648 LPWSASERVICECLASSINFOW lpServiceClassInfo)
650 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
651 SetLastError (WSAEOPNOTSUPP);
656 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
657 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
658 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
659 LPWSATHREADID lpThreadId)
661 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
662 SetLastError (WSAEOPNOTSUPP);
667 * This function is called by Winsock to hook up our provider.
668 * It is the only function that [should be/is] exported by the
669 * provider. All other routines are passed as pointers in lpnspRoutines.
672 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
674 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
676 if (!connect_to_dns_resolver ())
680 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
681 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
682 * and use that offset as cbSize.
684 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
686 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
687 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
688 lpnspRoutines->NSPCleanup = NSPCleanup;
689 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
690 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
691 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
692 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
693 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
694 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
695 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
696 /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
697 lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
700 SetLastError (WSAEINVALIDPROVIDER);