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".
30 # define DEBUGLOG(s, ...)
33 # define __printf__ printf
34 # 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 "w32resolver.h"
74 #include "gnunet_w32nsp_lib.h"
77 #define NSPAPI_VERSION_MAJOR 4
78 #define NSPAPI_VERSION_MINOR 4
80 #define REPLY_LIFETIME 60*5
82 #define STATE_BEGIN 0x01
83 #define STATE_END 0x02
84 #define STATE_REPLY 0x04
85 #define STATE_GHBN 0x08
87 static CRITICAL_SECTION records_cs;
98 static struct record *records = NULL;
99 static size_t records_len = 0;
100 static size_t records_size = 0;
105 size_t new_size = records_len > 0 ? records_len * 2 : 5;
106 struct record *new_records = malloc (new_size * sizeof (struct record));
107 if (new_records == NULL)
109 SetLastError (WSA_NOT_ENOUGH_MEMORY);
112 memcpy (new_records, records, records_len * sizeof (struct record));
113 memset (&new_records[records_len], 0, sizeof (struct record) * (new_size - records_len));
114 records_size = new_size;
116 records = new_records;
121 add_record (SOCKET s, const wchar_t *name, DWORD flags)
126 //EnterCriticalSection (&records_cs);
127 for (i = 0; i < records_len; i++)
128 if (records[i].state == 0)
131 if (i == records_len)
133 res = resize_records ();
135 empty = records_len++;
142 r.name = (wchar_t *) name;
146 r.name = wcsdup (name);
149 //LeaveCriticalSection (&records_cs);
157 free (records[i].name);
158 records[i].state = 0;
161 /* These are not defined by mingw.org headers at the moment*/
162 typedef INT (WSPAPI *LPNSPIOCTL) (HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPWSACOMPLETION,LPWSATHREADID);
163 typedef struct _NSP_ROUTINE_XP {
165 DWORD dwMajorVersion;
166 DWORD dwMinorVersion;
167 LPNSPCLEANUP NSPCleanup;
168 LPNSPLOOKUPSERVICEBEGIN NSPLookupServiceBegin;
169 LPNSPLOOKUPSERVICENEXT NSPLookupServiceNext;
170 LPNSPLOOKUPSERVICEEND NSPLookupServiceEnd;
171 LPNSPSETSERVICE NSPSetService;
172 LPNSPINSTALLSERVICECLASS NSPInstallServiceClass;
173 LPNSPREMOVESERVICECLASS NSPRemoveServiceClass;
174 LPNSPGETSERVICECLASSINFO NSPGetServiceClassInfo;
179 connect_to_dns_resolver ()
181 struct sockaddr_in addr;
185 r = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
186 if (INVALID_SOCKET == r)
188 SetLastError (16004);
192 addr.sin_family = AF_INET;
193 addr.sin_port = htons (5353); /* TCP 5353 is not registered; UDP 5353 is */
194 addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
196 ret = connect (r, (struct sockaddr *) &addr, sizeof (addr));
197 if (SOCKET_ERROR == ret)
199 DWORD err = GetLastError ();
202 SetLastError (16005);
209 send_name_to_ip_request (LPWSAQUERYSETW lpqsRestrictions,
210 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
213 struct GNUNET_W32RESOLVER_GetMessage *msg;
220 size_t size = sizeof (struct GNUNET_W32RESOLVER_GetMessage);
222 if (lpqsRestrictions->lpszServiceInstanceName)
223 namelen = sizeof (wchar_t) * (wcslen (lpqsRestrictions->lpszServiceInstanceName) + 1);
226 msg = (struct GNUNET_W32RESOLVER_GetMessage *) buf;
227 msg->header.size = htons (size);
228 msg->header.type = htons (GNUNET_MESSAGE_TYPE_W32RESOLVER_REQUEST);
229 if (lpqsRestrictions->dwNumberOfProtocols > 0)
232 for (i = 0; i < lpqsRestrictions->dwNumberOfProtocols; i++)
234 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET)
236 if (lpqsRestrictions->lpafpProtocols[0].iAddressFamily == AF_INET6)
241 msg->af = htonl (AF_INET);
242 else if (af6 && !af4)
243 msg->af = htonl (AF_INET6);
245 msg->af = htonl (AF_UNSPEC);
246 if (lpqsRestrictions->lpszServiceInstanceName)
247 memcpy (&msg[1], lpqsRestrictions->lpszServiceInstanceName, namelen);
248 msg->sc_data1 = htonl (lpqsRestrictions->lpServiceClassId->Data1);
249 msg->sc_data2 = htons (lpqsRestrictions->lpServiceClassId->Data2);
250 msg->sc_data3 = htons (lpqsRestrictions->lpServiceClassId->Data3);
251 for (i = 0; i < 8; i++)
252 msg->sc_data4[i] = lpqsRestrictions->lpServiceClassId->Data4[i];
253 *resolver = connect_to_dns_resolver ();
254 if (*resolver != INVALID_SOCKET)
256 if (size != send (*resolver, buf, size, 0))
258 DWORD err = GetLastError ();
259 closesocket (*resolver);
260 *resolver = INVALID_SOCKET;
261 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to send request: %lu\n", err);
262 SetLastError (WSATRY_AGAIN);
273 NSPCleanup (LPGUID lpProviderId)
275 DEBUGLOG ("NSPCleanup\n");
276 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
280 SetLastError (WSAEINVALIDPROVIDER);
285 DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
289 case DLL_PROCESS_ATTACH:
290 if (!InitializeCriticalSectionAndSpinCount (&records_cs, 0x00000400))
295 case DLL_THREAD_ATTACH:
297 case DLL_THREAD_DETACH:
299 case DLL_PROCESS_DETACH:
300 DeleteCriticalSection (&records_cs);
310 GNUNET_W32NSP_LookupServiceBegin (LPGUID lpProviderId, LPWSAQUERYSETW lpqsRestrictions,
311 LPWSASERVICECLASSINFOW lpServiceClassInfo, DWORD dwControlFlags,
314 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin\n");
315 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
318 if (lpqsRestrictions->dwNameSpace != NS_DNS && lpqsRestrictions->dwNameSpace != NS_ALL)
320 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong namespace\n");
321 SetLastError (WSANO_DATA);
324 if (lpqsRestrictions->lpszServiceInstanceName != NULL)
326 wchar_t *s = lpqsRestrictions->lpszServiceInstanceName;
327 size_t len = wcslen (s);
328 if (len >= 5 && wcscmp (&s[len - 5], L".zkey") == 0)
331 else if (len >= 4 && wcscmp (&s[len - 4], L".gnu") == 0)
336 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: unsupported TLD\n");
337 SetLastError (WSANO_DATA);
342 if (send_name_to_ip_request (lpqsRestrictions,
343 lpServiceClassInfo, dwControlFlags, &s))
345 if (!(add_record (s, lpqsRestrictions->lpszServiceInstanceName, dwControlFlags)))
347 DWORD err = GetLastError ();
348 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: failed to add a record\n");
353 *lphLookup = (HANDLE) s;
354 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: OK (%lu)\n", GetLastError ());
359 DEBUGLOG ("GNUNET_W32NSP_LookupServiceBegin: wrong provider\n");
360 SetLastError (WSAEINVALIDPROVIDER);
364 #define UnmarshallPtr(ptr, ptrtype, base) \
366 ptr = (ptrtype *) (base + (uintptr_t) ptr)
369 UnmarshallWSAQUERYSETW (LPWSAQUERYSETW req)
372 char *base = (char *) req;
373 UnmarshallPtr (req->lpszServiceInstanceName, wchar_t, base);
374 UnmarshallPtr (req->lpServiceClassId, GUID, base);
375 UnmarshallPtr (req->lpVersion, WSAVERSION, base);
376 UnmarshallPtr (req->lpszComment, wchar_t, base);
377 UnmarshallPtr (req->lpNSProviderId, GUID, base);
378 UnmarshallPtr (req->lpszContext, wchar_t, base);
379 UnmarshallPtr (req->lpafpProtocols, AFPROTOCOLS, base);
380 UnmarshallPtr (req->lpszQueryString, wchar_t, base);
381 UnmarshallPtr (req->lpcsaBuffer, CSADDR_INFO, base);
382 for (i = 0; i < req->dwNumberOfCsAddrs; i++)
384 UnmarshallPtr (req->lpcsaBuffer[i].LocalAddr.lpSockaddr, SOCKADDR, base);
385 UnmarshallPtr (req->lpcsaBuffer[i].RemoteAddr.lpSockaddr, SOCKADDR, base);
387 UnmarshallPtr (req->lpBlob, BLOB, base);
389 UnmarshallPtr (req->lpBlob->pBlobData, BYTE, base);
393 GNUNET_W32NSP_LookupServiceNext (HANDLE hLookup, DWORD dwControlFlags,
394 LPDWORD lpdwBufferLength, LPWSAQUERYSETW lpqsResults)
396 DWORD effective_flags;
398 struct GNUNET_MessageHeader header = {0, 0};
405 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext\n");
406 //EnterCriticalSection (&records_cs);
407 for (i = 0; i < records_len; i++)
409 if (records[i].s == (SOCKET) hLookup)
417 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: invalid handle\n");
418 SetLastError (WSA_INVALID_HANDLE);
419 //LeaveCriticalSection (&records_cs);
422 if (records[rec].state & 4)
424 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: session is closed\n");
425 SetLastError (WSA_E_NO_MORE);
426 //LeaveCriticalSection (&records_cs);
429 effective_flags = dwControlFlags & records[rec].flags;
430 if (records[rec].buf)
432 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: checking buffer\n");
433 header = *((struct GNUNET_MessageHeader *) records[rec].buf);
434 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
436 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
437 SetLastError (WSAEFAULT);
438 //LeaveCriticalSection (&records_cs);
441 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)records[rec].buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
442 free (records[rec].buf);
443 records[rec].buf = NULL;
444 //LeaveCriticalSection (&records_cs);
445 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
446 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK (from buffer)\n");
449 records[rec].state |= 8;
450 //LeaveCriticalSection (&records_cs);
451 to_receive = sizeof (header);
455 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
456 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a header from %p, %lu bytes available\n", to_receive, hLookup, have);
458 while (to_receive > 0)
460 t = recv ((SOCKET) hLookup, &((char *) &header)[rc], to_receive, 0);
471 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
472 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: read %d bytes as a header from %p, %lu bytes available\n", rc, hLookup, have);
474 //EnterCriticalSection (&records_cs);
475 records[rec].state &= ~8;
476 if (rc != sizeof (header))
478 if (records[rec].state & 2)
480 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
481 SetLastError (WSA_E_CANCELLED);
485 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);
486 SetLastError (WSA_E_NO_MORE);
488 records[rec].state |= 4;
489 //LeaveCriticalSection (&records_cs);
492 records[rec].state &= ~8;
493 header.type = ntohs (header.type);
494 header.size = ntohs (header.size);
495 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type %d, header size %u\n", header.type, header.size);
496 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE ||
497 (header.type == GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE &&
498 header.size == sizeof (header)))
500 records[rec].state |= 4;
501 if (header.type != GNUNET_MESSAGE_TYPE_W32RESOLVER_RESPONSE)
502 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: header type is wrong\n");
504 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: empty header - no data\n");
505 //LeaveCriticalSection (&records_cs);
506 SetLastError (WSA_E_NO_MORE);
509 buf = malloc (header.size);
512 records[rec].state |= 4;
513 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: malloc() failed\n");
514 //LeaveCriticalSection (&records_cs);
515 SetLastError (WSA_E_NO_MORE);
518 records[rec].state |= 8;
519 //LeaveCriticalSection (&records_cs);
520 memcpy (buf, &header, sizeof (header));
521 to_receive = header.size - sizeof (header);
525 int ior = ioctlsocket ((SOCKET) hLookup, FIONREAD, &have);
526 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: reading %d bytes as a body from %p, %lu bytes available\n", to_receive, hLookup, have);
528 while (to_receive > 0)
530 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: recv (%d)\n", to_receive);
531 t = recv ((SOCKET) hLookup, &((char *) &((struct GNUNET_MessageHeader *) buf)[1])[rc], to_receive, 0);
532 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);
546 //EnterCriticalSection (&records_cs);
547 records[rec].state &= ~8;
548 if (rc != header.size - sizeof (header))
551 if (records[rec].state & 2)
553 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: call cancelled\n");
554 SetLastError (WSA_E_CANCELLED);
558 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);
559 SetLastError (WSA_E_NO_MORE);
561 records[rec].state |= 4;
562 //LeaveCriticalSection (&records_cs);
565 if (*lpdwBufferLength < header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage))
567 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: client buffer is too small\n");
568 SetLastError (WSAEFAULT);
569 records[rec].buf = buf;
570 //LeaveCriticalSection (&records_cs);
573 //LeaveCriticalSection (&records_cs);
574 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: writing %d bytes into result buffer\n", header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
575 memcpy (lpqsResults, &((struct GNUNET_W32RESOLVER_GetMessage *)buf)[1], header.size - sizeof (struct GNUNET_W32RESOLVER_GetMessage));
577 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: OK\n");
578 UnmarshallWSAQUERYSETW ((LPWSAQUERYSETW) lpqsResults);
579 DEBUGLOG ("GNUNET_W32NSP_LookupServiceNext: returning (%lu)\n", GetLastError ());
584 GNUNET_W32NSP_LookupServiceEnd (HANDLE hLookup)
586 DWORD effective_flags;
588 struct GNUNET_MessageHeader header = {0, 0};
593 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd\n");
594 //EnterCriticalSection (&records_cs);
595 for (i = 0; i < records_len; i++)
597 if (records[i].s == (SOCKET) hLookup)
605 SetLastError (WSA_INVALID_HANDLE);
606 //LeaveCriticalSection (&records_cs);
607 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: invalid handle\n");
610 records[rec].state |= 2;
611 closesocket (records[rec].s);
612 while (records[rec].state & 8)
614 //LeaveCriticalSection (&records_cs);
616 //EnterCriticalSection (&records_cs);
618 if (records[rec].buf)
619 free (records[rec].buf);
620 records[rec].buf = NULL;
621 records[rec].state = 0;
622 if (records[rec].name)
623 free (records[rec].name);
624 //LeaveCriticalSection (&records_cs);
625 DEBUGLOG ("GNUNET_W32NSP_LookupServiceEnd: OK\n");
630 GNUNET_W32NSP_SetService (LPGUID lpProviderId,
631 LPWSASERVICECLASSINFOW lpServiceClassInfo, LPWSAQUERYSETW lpqsRegInfo,
632 WSAESETSERVICEOP essOperation, DWORD dwControlFlags)
634 DEBUGLOG ("GNUNET_W32NSP_SetService\n");
635 SetLastError (WSAEOPNOTSUPP);
640 GNUNET_W32NSP_InstallServiceClass (LPGUID lpProviderId,
641 LPWSASERVICECLASSINFOW lpServiceClassInfo)
643 DEBUGLOG ("GNUNET_W32NSP_InstallServiceClass\n");
644 SetLastError (WSAEOPNOTSUPP);
650 GNUNET_W32NSP_RemoveServiceClass (LPGUID lpProviderId, LPGUID lpServiceClassId)
652 DEBUGLOG ("GNUNET_W32NSP_RemoveServiceClass\n");
653 SetLastError (WSAEOPNOTSUPP);
658 GNUNET_W32NSP_GetServiceClassInfo (LPGUID lpProviderId, LPDWORD lpdwBufSize,
659 LPWSASERVICECLASSINFOW lpServiceClassInfo)
661 DEBUGLOG ("GNUNET_W32NSP_GetServiceClassInfo\n");
662 SetLastError (WSAEOPNOTSUPP);
667 GNUNET_W32NSP_Ioctl (HANDLE hLookup, DWORD dwControlCode, LPVOID lpvInBuffer,
668 DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer,
669 LPDWORD lpcbBytesReturned, LPWSACOMPLETION lpCompletion,
670 LPWSATHREADID lpThreadId)
672 DEBUGLOG ("GNUNET_W32NSP_Ioctl\n");
673 SetLastError (WSAEOPNOTSUPP);
678 * This function is called by Winsock to hook up our provider.
679 * It is the only function that [should be/is] exported by the
680 * provider. All other routines are passed as pointers in lpnspRoutines.
683 GNUNET_W32NSP_NSPStartup (LPGUID lpProviderId, LPNSP_ROUTINE lpnspRoutines)
685 if (IsEqualGUID (lpProviderId, &GNUNET_NAMESPACE_PROVIDER_DNS))
687 if (!connect_to_dns_resolver ())
691 /* This assumes that NSP_ROUTINE struct doesn't have a NSPIoctl member.
692 * If it does, you need to use FIELD_OFFSET() macro to get offset of NSPIoctl
693 * and use that offset as cbSize.
695 lpnspRoutines->cbSize = sizeof(NSP_ROUTINE);
697 lpnspRoutines->dwMajorVersion = NSPAPI_VERSION_MAJOR;
698 lpnspRoutines->dwMinorVersion = NSPAPI_VERSION_MINOR;
699 lpnspRoutines->NSPCleanup = NSPCleanup;
700 lpnspRoutines->NSPLookupServiceBegin = GNUNET_W32NSP_LookupServiceBegin;
701 lpnspRoutines->NSPLookupServiceNext = GNUNET_W32NSP_LookupServiceNext;
702 lpnspRoutines->NSPLookupServiceEnd = GNUNET_W32NSP_LookupServiceEnd;
703 lpnspRoutines->NSPSetService = GNUNET_W32NSP_SetService;
704 lpnspRoutines->NSPInstallServiceClass = GNUNET_W32NSP_InstallServiceClass;
705 lpnspRoutines->NSPRemoveServiceClass = GNUNET_W32NSP_RemoveServiceClass;
706 lpnspRoutines->NSPGetServiceClassInfo = GNUNET_W32NSP_GetServiceClassInfo;
707 /*((NSP_ROUTINE_XP *) lpnspRoutines)->NSPIoctl = GNUNET_W32NSP_Ioctl;*/
708 lpnspRoutines->NSPIoctl = GNUNET_W32NSP_Ioctl;
711 SetLastError (WSAEINVALIDPROVIDER);