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
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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".
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;
92 static struct record *records = NULL;
93 static size_t records_len = 0;
94 static size_t records_size = 0;
99 size_t new_size = records_len > 0 ? records_len * 2 : 5;
100 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)
120 //EnterCriticalSection (&records_cs);
121 for (i = 0; i < records_len; i++)
122 if (records[i].state == 0)
125 if (i == records_len)
127 res = resize_records ();
129 empty = records_len++;
136 r.name = (wchar_t *) name;
140 r.name = wcsdup (name);
143 //LeaveCriticalSection (&records_cs);
147 /* These are not defined by mingw.org headers at the moment*/
148 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
149 typedef struct _NSP_ROUTINE_XP {
151 DWORD dwMajorVersion;
152 DWORD dwMinorVersion;
153 LPNSPCLEANUP NSPCleanup;
154 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
155 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
156 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
157 LPNSPSETSERVICE NSPSetService;
158 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
159 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
160 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
165 connect_to_dns_resolver ()
167 struct sockaddr_in addr;
171 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
172 if (INVALID_SOCKET == r)
174 SetLastError (16004);
178 addr.sin_family = AF_INET;
179 addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
180 addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
182 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
183 if (SOCKET_ERROR == ret)
185 DWORD err = GetLastError ();
188 SetLastError (16005);
195 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
196 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
199 struct GNUNET_W32RESOLVER_GetMessage *msg;
205 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
207 if (lpqsRestrictions->lpszServiceInstanceName)
208 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
211 msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
212 msg->header.size = htons (size);
213 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
214 if (lpqsRestrictions->dwNumberOfProtocols > 0)
217 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
219 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
221 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
226 msg->af = htonl (AF_INET);
227 else if (af6 && !af4)
228 msg->af = htonl (AF_INET6);
230 msg->af = htonl (AF_UNSPEC);
231 if (lpqsRestrictions->lpszServiceInstanceName)
232 GNUNET_memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
233 msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
234 msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
235 msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
236 for (i = 0; i < 8; i++)
237 msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
238 *resolver = connect_to_dns_resolver ();
239 if (*resolver != INVALID_SOCKET)
241 if (size != send (*resolver, buf, size, 0))
244 DWORD err = GetLastError ();
246 closesocket (*resolver);
247 *resolver = INVALID_SOCKET;
248 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
249 SetLastError (WSATRY_AGAIN);
260 NSPCleanup (LPGUID lpProviderId)
262 DEBUGLOG ("NSPCleanup\n");
263 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
267 SetLastError (WSAEINVALIDPROVIDER);
272 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
276 case DLL_PROCESS_ATTACH:
277 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
282 case DLL_THREAD_ATTACH:
284 case DLL_THREAD_DETACH:
286 case DLL_PROCESS_DETACH:
287 DeleteCriticalSection (&records_cs);
297 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
298 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
301 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
302 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
305 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
307 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
308 SetLastError (WSAEINVAL);
311 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
313 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
314 size_t len = wcslen (s);
315 if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
318 else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
323 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
324 SetLastError (WSAEINVAL);
329 if (send_name_to_ip_request (lpqsRestrictions,
330 lpServiceClassInfo, dwControlFlags, &s))
332 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
334 DWORD err = GetLastError ();
335 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
340 *lphLookup = (HANDLE) s;
341 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
346 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
347 SetLastError (WSAEINVALIDPROVIDER);
351 #define UnmarshallPtr(ptr, ptrtype, base) \
353 ptr = (ptrtype *) (base + (uintptr_t) ptr)
356 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
359 char *base = (char *) req;
360 UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
361 UnmarshallPtr (req->lpServiceClassId, GUID, base);
362 UnmarshallPtr (req->lpVersion, WSAVERSION, base);
363 UnmarshallPtr (req->lpszComment, wchar_t, base);
364 UnmarshallPtr (req->lpNSProviderId, GUID, base);
365 UnmarshallPtr (req->lpszContext, wchar_t, base);
366 UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
367 UnmarshallPtr (req->lpszQueryString, wchar_t, base);
368 UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
369 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
371 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
372 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
374 UnmarshallPtr (req->lpBlob, BLOB, base);
376 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
380 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
381 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
383 /*DWORD effective_flags;*/
385 struct GNUNET_MessageHeader header = {0, 0};
392 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
393 //EnterCriticalSection (&records_cs);
394 for (i = 0; i < records_len; i++)
396 if (records[i].s == (SOCKET) hLookup)
404 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
405 SetLastError (WSA_INVALID_HANDLE);
406 //LeaveCriticalSection (&records_cs);
409 if (records[rec].state & 4)
411 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
412 SetLastError (WSA_E_NO_MORE);
413 //LeaveCriticalSection (&records_cs);
416 /*effective_flags = dwControlFlags & records[rec].flags;*/
417 if (records[rec].buf)
419 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: checking buffer\n");
420 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
421 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
423 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
424 SetLastError (WSAEFAULT);
425 //LeaveCriticalSection (&records_cs);
428 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
429 free (records[rec].buf);
430 records[rec].buf = NULL;
431 //LeaveCriticalSection (&records_cs);
432 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
433 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
436 records[rec].state |= 8;
437 //LeaveCriticalSection (&records_cs);
438 to_receive = sizeof (header);
443 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
444 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a header from %p, %lu bytes available\n", to_receive, hLookup, have);
447 while (to_receive > 0)
449 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
461 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
462 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a header from %p, %lu bytes available\n", rc, hLookup, have);
465 //EnterCriticalSection (&records_cs);
466 records[rec].state &= ~8;
467 if (rc != sizeof (header))
469 if (records[rec].state & 2)
471 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
472 SetLastError (WSA_E_CANCELLED);
476 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);
477 SetLastError (WSA_E_NO_MORE);
479 records[rec].state |= 4;
480 //LeaveCriticalSection (&records_cs);
483 records[rec].state &= ~8;
484 header.type = ntohs (header.type);
485 header.size = ntohs (header.size);
486 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type %d, header size %u\n", header.type, header.size);
487 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
488 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
489 header.size == sizeof (header)))
491 records[rec].state |= 4;
492 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE)
493 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type is wrong\n");
495 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: empty header - no data\n");
496 //LeaveCriticalSection (&records_cs);
497 SetLastError (WSA_E_NO_MORE);
500 buf = malloc (header.size);
503 records[rec].state |= 4;
504 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
505 //LeaveCriticalSection (&records_cs);
506 SetLastError (WSA_E_NO_MORE);
509 records[rec].state |= 8;
510 //LeaveCriticalSection (&records_cs);
511 GNUNET_memcpy (buf, &header, sizeof (header));
512 to_receive = header.size - sizeof (header);
517 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
518 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a body from %p, %lu bytes available\n", to_receive, hLookup, have);
521 while (to_receive > 0)
523 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv (%d)\n", to_receive);
524 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
525 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv returned %d\n", t);
537 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
538 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a body from %p, %lu bytes available\n", rc, hLookup, have);
541 //EnterCriticalSection (&records_cs);
542 records[rec].state &= ~8;
543 if (rc != header.size - sizeof (header))
546 if (records[rec].state & 2)
548 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
549 SetLastError (WSA_E_CANCELLED);
553 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);
554 SetLastError (WSA_E_NO_MORE);
556 records[rec].state |= 4;
557 //LeaveCriticalSection (&records_cs);
560 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
562 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
563 SetLastError (WSAEFAULT);
564 records[rec].buf = buf;
565 //LeaveCriticalSection (&records_cs);
568 //LeaveCriticalSection (&records_cs);
569 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: writing %d bytes into result buffer\n", header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
570 GNUNET_memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
572 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
573 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
574 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
579 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
584 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
585 //EnterCriticalSection (&records_cs);
586 for (i = 0; i < records_len; i++)
588 if (records[i].s == (SOCKET) hLookup)
596 SetLastError (WSA_INVALID_HANDLE);
597 //LeaveCriticalSection (&records_cs);
598 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
601 records[rec].state |= 2;
602 closesocket (records[rec].s);
603 while (records[rec].state & 8)
605 //LeaveCriticalSection (&records_cs);
607 //EnterCriticalSection (&records_cs);
609 if (records[rec].buf)
610 free (records[rec].buf);
611 records[rec].buf = NULL;
612 records[rec].state = 0;
613 if (records[rec].name)
614 free (records[rec].name);
615 //LeaveCriticalSection (&records_cs);
616 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
621 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
622 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
623 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
625 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
626 SetLastError (WSAEOPNOTSUPP);
631 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
632 LPWSASERVICECLASSINFOW lpServiceClassInfo)
634 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
635 SetLastError (WSAEOPNOTSUPP);
641 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
643 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
644 SetLastError (WSAEOPNOTSUPP);
649 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
650 LPWSASERVICECLASSINFOW lpServiceClassInfo)
652 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
653 SetLastError (WSAEOPNOTSUPP);
658 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
659 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
660 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
661 LPWSATHREADID lpThreadId)
663 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
664 SetLastError (WSAEOPNOTSUPP);
669 * This function is called by Winsock to hook up our provider.
670 * It is the only function that [should be/is] exported by the
671 * provider. All other routines are passed as pointers in lpnspRoutines.
674 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
676 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
678 if (!connect_to_dns_resolver ())
682 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
683 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
684 * and use that offset as cbSize.
686 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
688 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
689 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
690 lpnspRoutines->NSPCleanup = NSPCleanup;
691 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
692 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
693 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
694 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
695 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
696 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
697 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
698 /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
699 lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
702 SetLastError (WSAEINVALIDPROVIDER);